爬虫实战:页面解析详细指南(正则表达式、XPath、jsoup、Gson)

爬虫的第二步,是对源码进行解析,提炼出目标内容。

本篇我们主要介绍以下 4 种常用的解析技术:

  • 正则表达式
  • XPath
  • jsoup
  • Gson


正则表达式

正则表达式(Regular Expression),计算机科学的一个概念。通常被用来检索、替换那些符合某个规则的文本。

在爬虫程序中,随处可见正则表达式的影子。无论是 URL 筛选过滤,还是正文内容解析,都离不开正则表达式的支持。可以这么说,如果没有正则表达式,那么开发者将很难编写一个完整的爬虫程序。

如果之前没有接触过正则表达式,可以通过以下教程快速入门:

Java 与正则表达式相关的类主要在 java.util.regex 包中。在 Java 中使用正则表达式,首先就要掌握 regex 包中的 Pattern 类与 Matcher 类。二者的作用如下表所示:

class name introduction
Pattern 表示一个已经编译好的正则表达式
Matcher 通过 Pattern 实例对任意字符序列进行匹配的引擎


使用 Pattern 与 Matcher 实现正则匹配,需要以下步骤:

  • 通过 Pattern.compile(String regex) 创建一个不可变的、线程安全的 Pattern 实例;
  • 通过 Pattern.matcher(CharSequence input) 获得 Matcher 类实例;
  • 使用 Matcher 类的 find() 方法对任意字符序列进行匹配(matches()lookingAt() 方法也可以实现匹配功能);
  • 通过 Matcher 类的 group(int group) 返回匹配到的子字符串。

下面,我们尝试使用正则表达式从以下 HTML 文本中解析出节点 P 中的文本信息。

<html>
    <body>
        <p>今天的日期是:2017-11-11</p>
    </body>
</html>
package demo;

import util.FileUtils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 正则表达式 demo
 *
 * @author panda
 * @date 2017/11/12
 */
public class RegexDemo {

    private static Pattern DATE_PATTERN = Pattern.compile("<p>(.*?)</p>");

    public static void main(String[] args) {
        String htmlBody = FileUtils.readFile("test.html", "UTF-8");
        System.out.println(htmlBody);

        Matcher matcher = DATE_PATTERN.matcher(htmlBody);

        if (matcher.find()) {
            String[] s = new String[matcher.groupCount() + 1];
            for (int i = 0; i <= matcher.groupCount(); i++) {
                s[i] = matcher.group(i);
            }
            System.out.println(s[1]);
        }
    }

}

运行主函数后,控制台输出如下信息:

<html>    <body>        <p>今天的日期是:2017-11-11</p>    </body></html>
今天的日期是:2017-11-11


XPath

XPath 是一门在 XML 文档中查找信息的语言,可用来在 XML 文档中对元素和属性进行遍历。它可以通过路径表达式在树状数据结构中选取指定节点或节点集。

由于 HTML 和 XML 一样拥有树状数据结构,因此 XPath 同样适用 HTML 文档。

在 Java 中使用 XPath,需要引入以下 jar 包:

  • xalan.jar
  • nekohtml.jar
  • xml-apis.jar

通过 XPath 实现 HTML 文档解析,一般需要以下步骤:

  • 通过 nekehtml.jar 中 DOMParser 类的 parse(InputSource var1) 方法获取一个 Document 实例;
  • 通过 xalan.jar 中的 XPathAPI,实现节点或节点集的选取;
  • 通过 Node 接口提取节点属性与节点信息。

下面,我们尝试使用 XPath 来解析出上述 HTML 文档中 P 节点的文本信息。

package demo;

import org.apache.xpath.XPathAPI;
import org.cyberneko.html.parsers.DOMParser;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import util.FileUtils;

import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;

/**
 * XPath demo
 *
 * @author panda
 * @date 2017/11/18
 */
public class XPathDemo {

    public static void main(String[] args) {
        String htmlBody = FileUtils.readFile("test.html", "UTF-8");
        System.out.println(htmlBody);

        try {
            DOMParser parser = new DOMParser();
            parser.setFeature("http://xml.org/sax/features/namespaces", false);
            parser.setProperty(
                    "http://cyberneko.org/html/properties/default-encoding",
                    "UTF-8");

            ByteArrayInputStream in = new ByteArrayInputStream(htmlBody.getBytes());
            InputStreamReader reader = new InputStreamReader(in);
            InputSource source = new InputSource(reader);
            parser.parse(source);

            Document doc = parser.getDocument();
            Node node = XPathAPI.selectSingleNode(doc, ".//P");
            System.out.println(node.getTextContent());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

运行主函数后,我们可以在控制台看到同样的结果。


jsoup

jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常强大的 API,可通过 DOM,CSS 以及类似于 jQuery 的操作方法来取出和操作数据。

实际上,jsoup 与 XPath 非常相似。

在 Java 中使用 jsoup,同样需要我们引入 jar 包:

  • jsoup-1.10.2.jar

通过 jsoup 解析 HTML 文档,需要以下步骤:

  • 通过 Jsoup.parse(String html) 获取一个 Document 实例(注意,不是 w3c 下的 Document);
  • 通过 Document 获取 Element 对象或 Elements 集合;
  • 通过 Element 获取节点属性和节点信息。

下面,我们尝试使用 jsoup 完成相同的解析需求。

package demo;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import util.FileUtils;

/**
 * jsoup demo
 *
 * @author panda
 * @date 2017/11/12
 */
public class JsoupDemo {

    public static void main(String[] args) {
        String htmlBody = FileUtils.readFile("test.html", "UTF-8");
        System.out.println(htmlBody);

        Document doc;
        try {
            doc = Jsoup.parse(htmlBody);
            Elements elements = doc.getElementsByTag("P");
            for (int i = 0; i < elements.size(); i++) {
                Element element = elements.get(i);
                System.out.println(element.text());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

运行主函数后,我们同样能获取相同的结果。

如果想了解 jsoup 更多使用方法,请参考以下专栏:http://blog.csdn.net/column/details/jsoup.html


Gson

Gson 是 Google 提供的用于解析 Json 数据的开源类库,相似的类库还有 Jackson、FastJson 等。

使用 Gson,需添加 jar 包:

  • gson-2.8.0.jar

一个简单的 Gson 解析 Json 数据示例,需要以下步骤:

  • 创建字段与 Json 数据相对应的 POJO;
  • 通过 Gson 实例的 fromJson(String json, Class<T> classOfT) 方法实现 Json 数据到 POJO 的映射;
  • 通过 POJO 字段获取目标内容。

现在,我们尝试解析出以下 Json 数据中的信息。

{
    name:"panda",
    age:18
}
package demo;

import com.google.gson.Gson;
import util.FileUtils;

/**
 * Gson demo
 *
 * @author panda
 * @date 2017/11/30
 */
public class GsonDemo {

    public static void main(String[] args) {
        String jsonString = FileUtils.readFile("json.txt", "UTF-8");

        Gson gson = new Gson();
        User user = gson.fromJson(jsonString, User.class);
        System.out.println("name:" + user.name);
        System.out.println("age:" + user.age);
    }

    private class User {
        private String name;
        private int age;
    }

}

运行主函数后,获取如下结果:

name:panda
age:18

如果想更全面地学习 Gson,请点这里:http://www.jianshu.com/p/e740196225a4

猜你喜欢

转载自blog.csdn.net/magicpenta/article/details/78674577