Skip to content

jsoup ​

jsoup 是一个用于解析、提取和处理 HTML 的 Java 库。它提供了一个非常方便的 API,可以让开发者轻松地从 URL、文件或字符串中解析 HTML,并提取所需的内容。本文将带深入了解 jsoup 的基础知识、核心对象以及常用的选择器语法,并通过实际案例演示其应用。

jsoup 基础 ​

1.1 jsoup 入门案例 ​

1.1.1 创建工程 se-jsoup-demo1 ​

首先,创建一个新的 Maven 工程,命名为se-jsoup-demo1。在项目的pom.xml文件中添加 jsoup 的依赖:

xml
<dependency>
  <groupId>org.jsoup</groupId>
  <artifactId>jsoup</artifactId>
  <version>1.12.1</version>
</dependency>

1.1.2 获取网页源码 ​

在爬取网页时,通常会使用HttpClient等框架获取网页源码。获取到源码后,需要从中提取所需的内容,这时就可以使用 jsoup 这样的 HTML 解析器来实现。jsoup 支持解析 HTML 字符串、URL 和文件,并将其转换为org.jsoup.nodes.Document对象,方便进一步操作。

以下是一个简单的示例,展示如何获取网页的标题:

java
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

public class JsoupExampleGetTitle {
  public static void main(String[] args) {
    Document doc = null;
    try {
      doc = Jsoup.connect("http://www.baidu.com/").get();
    } catch (IOException e) {
      e.printStackTrace();
    }
    String title = doc.title();
    System.out.println(title);
  }
}

输出结果:

百度一下,就知道

接下来是一个获取网页源码的示例:

java
package com.uairobot.bill.study.jsoup;

import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

public class JsonSourceContent {
  public static void main(String[] args) {
    Document document = null;
    try {
      document = Jsoup.connect("http://www.baidu.com").get();
    } catch (IOException e) {
      e.printStackTrace();
    }
    String text = document.text();
    String outerHtml = document.outerHtml();
    System.out.println("text");
    System.out.println(text);
    System.out.println("outerHtml");
    System.out.println(outerHtml);
  }
}

获取网页内容的方法:

  • Element.text(): 获取元素中的纯文本。
  • Element.html() 或 Node.outerHtml(): 获取元素中的 HTML 内容。
  • Node.attr(String key): 获取元素的属性值,例如获取<a href="">中的href值。

有时需要模拟登录操作并获取返回的 cookie。以下示例展示了如何通过 jsoup 连接并获取登录后的 cookie:

java
package com.uairobot.bill.study.jsoup;

import java.io.IOException;
import java.util.Map;
import org.jsoup.Connection;
import org.jsoup.Connection.Response;
import org.jsoup.Jsoup;

public class JsonLogin {
  public static void main(String[] args) {
    String url = "http://www.iotcloud168.com:8083/user/login?username=181228001&password=123";
    Connection connect = Jsoup.connect(url);
    Response execute = null;
    try {
      execute = connect.execute();
    } catch (IOException e) {
      e.printStackTrace();
    }
    Map<String, String> cookies = execute.cookies();
    System.out.println(cookies);
  }
}

1.2 jsoup Document 对象 ​

1.2.1 获取 Document 对象 ​

获取Document对象的方法主要有以下几种:

  • 从 URL 获取 HTML 解析:

    java
    Document doc = Jsoup.connect("http://www.baidu.com/").get();

    Jsoup.connect("xxx")方法返回一个org.jsoup.Connection对象。在执行请求前,可以通过该对象设置请求信息,如头信息、cookie、超时时间、代理等,以模拟浏览器行为。例如:

    java
    Document doc = Jsoup.connect("http://example.com")
      .data("query", "Java")
      .userAgent("Mozilla")
      .cookie("auth", "token")
      .timeout(3000)
      .post();
  • 从文件获取 HTML 解析:

    java
    String addr = "http://zszcba.haedu.gov.cn/result/query";
    File input = new File("example.html");
    try {
      Document parse = Jsoup.parse(input, "UTF-8", addr);
    } catch (IOException e) {
      e.printStackTrace();
    }

1.2.2 从 Document 获取指定的元素 ​

Document对象提供了多种方法来获取指定的 HTML 元素:

  • 通过 DOM 方式获取:

    • getElementById(String id): 通过 ID 获取元素。
    • getElementsByTag(String tagName): 通过标签名获取元素。
    • getElementsByClass(String className): 通过类名获取元素。
    • getElementsByAttribute(String key): 通过属性名获取元素。
    • getElementsByAttributeValue(String key, String value): 通过指定的属性名和值获取元素。
    • getAllElements(): 获取所有元素。
  • 通过选择器语法获取:

    使用类似 CSS 或 jQuery 的选择器,通过Element类的select方法来查找元素。例如:

    java
    File input = new File("/tmp/input.html");
    Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/");
    Elements links = doc.select("a[href]"); // 选择所有带有href属性的a标签
    Elements pngs = doc.select("img[src$=.png]"); // 选择所有扩展名为.png的图片
    Element masthead = doc.select("div.masthead").first(); // 选择class为masthead的div标签
    Elements resultLinks = doc.select("h3.r > a"); // 选择h3标签内的a标签

1.3 选择器的语法 ​

选择器是 jsoup 中非常强大的功能,允许开发者通过类似 CSS 的语法来查找和过滤元素。

1.3.1 通过标签查找元素 ​

选择器语法支持多种方式通过标签查找元素:

  • 标签名: a - 选择所有<a>标签。
  • 命名空间标签: ns|tag - 例如,fb|name选择<fb:name>元素。
  • ID 选择器: #id - 例如,#logo选择 ID 为logo的元素。
  • 类选择器: .class - 例如,.masthead选择所有类名包含masthead的元素。
  • 属性选择器:
    • [attribute] - 选择拥有指定属性的元素,例如 [href]。
    • [attr=value] - 选择属性值等于指定值的元素,例如 [width=500]。
    • [attr^=value], [attr$=value], [attr*=value] - 分别选择属性值以指定值开头、结尾或包含指定值的元素。
    • [attr~=regex] - 选择属性值匹配指定正则表达式的元素,例如 img[src~=(?i).(png|jpe?g)]。
  • 通配符: * - 匹配所有元素。

组合使用选择器:

  • el#id: 元素加 ID,例如 div#logo。
  • el.class: 元素加类,例如 div.masthead。
  • el[attr]: 元素加属性,例如 a[href]。
  • 多种选择器组合,例如 a[href].highlight。
  • 层级关系选择器:
    • ancestor child: 选择某元素下的子元素,例如 .body p选择.body元素下的所有<p>元素。
    • parent > child: 选择父元素的直接子元素,例如 div.content > p。
    • siblingA + siblingB: 选择紧接在siblingA之后的同级元素siblingB,例如 div.head + div。
    • siblingA ~ siblingX: 选择siblingA之前的所有同级元素siblingX,例如 h1 ~ p。
  • 多个选择器: el, el, el - 选择匹配任一选择器的元素,例如 div.masthead, div.logo。

1.3.2 伪选择器 ​

jsoup 支持多种伪选择器,用于进一步过滤元素:

  • :lt(n): 选择同级索引值小于 n 的元素,例如 td:lt(3)选择前三个<td>元素。
  • :gt(n): 选择同级索引值大于 n 的元素,例如 div p:gt(2)选择包含超过两个<p>元素的<div>。
  • :eq(n): 选择同级索引值等于 n 的元素,例如 form input:eq(1)选择表单中的第二个<input>元素。
  • :has(selector): 选择包含匹配选择器的子元素的元素,例如 div:has(p)选择包含<p>元素的所有<div>。
  • :not(selector): 选择不匹配选择器的元素,例如 div:not(.logo)选择所有不包含class="logo"的<div>元素。
  • :contains(text): 选择包含指定文本的元素,搜索不区分大小写,例如 p:contains(jsoup)。
  • :containsOwn(text): 选择直接包含指定文本的元素。
  • :matches(regex): 选择文本匹配指定正则表达式的元素,例如 div:matches((?i)login)。
  • :matchesOwn(regex): 选择自身文本匹配指定正则表达式的元素。

注意: 伪选择器中的索引从 0 开始,第一个元素索引为 0,第二个为 1,以此类推。

1.3.3 获取 Element 对象内容 ​

从Element对象中提取内容常用的方法包括:

  • 获取文本: Element.text()
    java
    String text = element.text();
  • 获取 HTML 内容: Element.html() 或 Node.outerHtml()
    java
    String htmlContent = element.html();
    String outerHtml = element.outerHtml();
  • 获取属性值: Node.attr(String key)
    java
    String href = element.attr("href");

1.4 jsoup 获取元素属性案例 ​

1.4.1 获取 A 标签的链接 ​

以下示例展示了如何使用 jsoup 获取特定条件下的<a>标签链接:

java
package com.litong.jsoup.demo;

import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import lombok.extern.slf4j.Slf4j;

/**
 * @author
 * @date 2020年11月12日
 * @version 1.0
 * @desc 获取所有2020年高职扩招的学校
 */
@Slf4j
public class GetAllSchoolName {
  public static void main(String[] args) throws IOException {
    String httpUrl = "http://xxx/result/query";
    for (int i = 1; i < 6; i++) {
      // 连接并获取HTML文档
      Document document = Jsoup.connect(httpUrl + "?page=" + i).get();
      log.info("爬取第" + i + "页");

      // 使用选择器获取包含特定文本的a标签
      Elements select1 = document.select("td a[href]:contains(2020年高职扩招)");
      Elements select2 = document.select("td a[href]:contains(2020年扩招)");

      // 合并两个Elements对象
      select1.addAll(select2);
      log.info("共有学校" + select1.size() + "个");

      // 获取学校的名称和链接
      if (select1.size() > 0) {
        for (Element element : select1) {
          String text = element.text();
          String value = element.attr("href");
          log.info("获取到学校的名称: {}, 学校的连接: {}", text, value);
        }
      }
    }
  }
}

说明:

  • 连接与获取文档: 使用Jsoup.connect(url).get()连接指定 URL 并获取 HTML 文档。
  • 选择器使用: 使用select方法结合contains伪选择器,筛选出包含特定文本的<a>标签。
  • 合并元素: 将两个Elements对象合并,避免遗漏任何符合条件的元素。
  • 提取内容: 遍历Elements,提取每个<a>标签的文本和href属性值。

案例演示 ​

通过上述内容,我们已经了解了 jsoup 的基础用法。接下来,我们将结合实际场景,展示如何使用 jsoup 进行网页数据的抓取与解析。

示例场景: 抓取高校扩招信息 ​

假设我们需要抓取某教育网站上 2020 年高职扩招的所有学校名称及其链接。以下是详细步骤:

  1. 确定目标 URL: http://xxx/result/query?page=1 到 http://xxx/result/query?page=5
  2. 分析网页结构: 通过浏览器的开发者工具,确定目标数据所在的 HTML 标签及其属性。
  3. 编写爬虫代码: 使用 jsoup 连接每一页,提取目标数据。

完整代码示例:

java
package com.litong.jsoup.demo;

import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import lombok.extern.slf4j.Slf4j;

/**
 * 获取所有2020年高职扩招的学校
 */
@Slf4j
public class GetAllSchoolName {
  public static void main(String[] args) throws IOException {
    String httpUrl = "http://xxx/result/query";
    for (int i = 1; i < 6; i++) {
      // 连接并获取HTML文档
      Document document = Jsoup.connect(httpUrl + "?page=" + i).get();
      log.info("爬取第" + i + "页");

      // 使用选择器获取包含特定文本的a标签
      Elements select1 = document.select("td a[href]:contains(2020年高职扩招)");
      Elements select2 = document.select("td a[href]:contains(2020年扩招)");

      // 合并两个Elements对象
      select1.addAll(select2);
      log.info("共有学校" + select1.size() + "个");

      // 提取学校名称和链接
      if (select1.size() > 0) {
        for (Element element : select1) {
          String text = element.text();
          String value = element.attr("href");
          log.info("获取到学校的名称: {}, 学校的连接: {}", text, value);
        }
      }
    }
  }
}

运行结果:

INFO  爬取第1页
INFO  共有学校5个
INFO  获取到学校的名称: XXX大学, 学校的连接: http://xxx/school/xxx
...
INFO  爬取第5页
INFO  共有学校4个
INFO  获取到学校的名称: YYY学院, 学校的连接: http://xxx/school/yyy
...

总结:

通过以上示例,我们展示了如何使用 jsoup 进行网页数据的抓取与解析。jsoup 强大的选择器语法和简洁的 API 使得 HTML 解析变得非常高效和便捷。无论是简单的网页抓取,还是复杂的数据提取任务,jsoup 都能胜任。

结语 ​

jsoup 是 Java 开发中处理 HTML 的强大工具。本文介绍了 jsoup 的基础用法,包括如何获取Document对象、使用选择器语法查找元素以及提取元素内容和属性。通过实际案例,我们进一步展示了 jsoup 在数据抓取中的应用。希望本指南能帮助更好地掌握 jsoup,提升网页数据处理的效率。


参考资源:

MIT Licensed