Skip to main content

页面解析详细指南

info

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

一、正则表达式

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

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

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

http://blog.csdn.net/GitChat/article/details/78526667?ref=myrecommend

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

class nameintroduction
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