我们抓取到页面之后,还需要对页面进行解析。可以使用字符串处理工具解析页面,也可以使用正则表达式,但是这些方法都会带来很大的开发成本,所以我们需要使用一款专门解析html页面的技术—Jsoup。

3.1 Jsoup介绍

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

  1. 从一个URL,文件或字符串中解析HTML;
  2. 使用DOM或CSS选择器来查找、取出数据;
  3. 可操作HTML元素、属性、文本。

添加jsoup相关依赖

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>cn.itbuild</groupId>
  7. <artifactId>itbuild-crawler-first</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <dependencies>
  10. <!--引入jar包-->
  11. <dependency>
  12. <groupId>org.apache.httpcomponents</groupId>
  13. <artifactId>httpclient</artifactId>
  14. <version>4.5.2</version>
  15. </dependency>
  16. <dependency>
  17. <groupId>org.slf4j</groupId>
  18. <artifactId>slf4j-log4j12</artifactId>
  19. <version>1.7.25</version>
  20. </dependency>
  21. <!--Jsoup-->
  22. <dependency>
  23. <groupId>org.jsoup</groupId>
  24. <artifactId>jsoup</artifactId>
  25. <version>1.11.3</version>
  26. </dependency>
  27. <!--测试-->
  28. <dependency>
  29. <groupId>junit</groupId>
  30. <artifactId>junit</artifactId>
  31. <version>4.12</version>
  32. <scope>test</scope>
  33. </dependency>
  34. <!--操作文件FileUtils-->
  35. <dependency>
  36. <groupId>commons-io</groupId>
  37. <artifactId>commons-io</artifactId>
  38. <version>2.4</version>
  39. </dependency>
  40. <!--操作字符串StringUtils-->
  41. <dependency>
  42. <groupId>org.apache.commons</groupId>
  43. <artifactId>commons-lang3</artifactId>
  44. <version>3.4</version>
  45. </dependency>
  46. </dependencies>
  47. </project>


3.2 解析Url

虽然使用Jsoup可以替代HttpClient直接发起请求解析数据,但是往往不会这样用,因为实际的开发过程中,需要使用到多线程,连接池,代理等等方式,而 jsoup 对这些的支持并不是很好,所以我们一般把jsoup 仅仅作为 Html解析工具使用。

  1. package cn.itbuild.test;
  2. import org.jsoup.Jsoup;
  3. import org.jsoup.nodes.Document;
  4. import org.junit.Test;
  5. import java.net.URL;
  6. /**
  7. * @Date 2020/12/21 22:53
  8. * @Version 10.21
  9. * @Author DuanChaojie
  10. */
  11. public class JsoupTest {
  12. @Test
  13. public void testUrl() throws Exception {
  14. // 1. 解析url地址, 第一个参数是访问的url, 第二个参数时访问时候的超时时间
  15. Document doc = Jsoup.parse(new URL("http://www.itcast.cn"), 1000);
  16. // 2. 使用标签选择器, 获取title标签中的内容
  17. String title = doc.getElementsByTag("title").first().text();
  18. // 3.打印
  19. System.out.println(title);
  20. }
  21. }

将test.html的路径在JsoupTest中先定义好:

  1. private static final String TESTHTML = "E:\\file\\gitee\\itbuild-crawler-first\\src\\main\\java\\cn\\itbuild\\crawler\\test\\test.html";

test.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>传智教育官网-好口碑IT培训机构,一样的教育,不一样的品质</title>
  6. <style>
  7. .class_a{
  8. }
  9. .class_b{
  10. }
  11. .a_name{
  12. }
  13. </style>
  14. </head>
  15. <body>
  16. <div class="city">
  17. <h3 id="city_bj">北京中心</h3>
  18. <div class="city_in">
  19. <div class="city_con" style="display:none;">
  20. <ul>
  21. <li id="test" class="class_a class_b">
  22. <a href="http://www.itcast.cn" target="_blank" >
  23. <span class="a_name">北京</span>
  24. </a>
  25. </li>
  26. <li>
  27. <a href="http://sh.itcast.cn" target="_blank">
  28. <span class="a_name">上海</span>
  29. </a>
  30. </li>
  31. <li>
  32. <a href="http://gz.itcast.cn" target="_blank">
  33. <span abc="123" class="a_name">广东</span>
  34. </a>
  35. </li>
  36. </ul>
  37. <ul>
  38. <li>天津</li>
  39. </ul>
  40. </div>
  41. </div>
  42. </div>
  43. </body>
  44. </html>

3.3 解析字符串

  1. @Test
  2. public void testString() throws Exception {
  3. // 1. 使用工具类读取文件, 获取字符串
  4. String content = FileUtils.readFileToString(new File(TESTHTML), "utf8");
  5. // 2. 解析字符串
  6. Document doc = Jsoup.parse(content);
  7. String title = doc.getElementsByTag("title").first().text();
  8. // 3.打印
  9. System.out.println(title);
  10. }


3.4 解析文件

  1. @Test
  2. public void testFile() throws Exception {
  3. // 1. 解析文件
  4. Document doc = Jsoup.parse(new File(TESTHTML), "utf8");
  5. String title = doc.getElementsByTag("title").first().text();
  6. System.out.println(title);
  7. }


3.5 使用DOM方式遍历文档

元素获取:

  1. 根据id查询元素 getElementByld
  2. 根据标签获取元素getElementsByTag
  3. 根据class获取元素getElementsByClass
  4. 根据属性获取元素getElementsByAttribute
  1. @Test
  2. public void testDom() throws Exception {
  3. // 解析文件, 获取Document对象
  4. Document doc = Jsoup.parse(new File(TESTHTML), "utf8");
  5. // 1.根据id查询元素getElementById
  6. Element element = doc.getElementById("city_bj");
  7. // 2.根据标签获取元素getElementsByTag
  8. Elements spans = doc.getElementsByTag("span");
  9. // 3.根据class获取元素getElementsByClass
  10. Element clazz = doc.getElementsByClass("class_a class_b").first();
  11. // 4.根据属性获取元素getElementsByAttribute
  12. Element abc = doc.getElementsByAttribute("abc").first();
  13. // 5.根据属性与属性值筛选
  14. Element href = doc.getElementsByAttributeValue("href", "http://sh.itcast.cn").first();
  15. // 打印元素内容
  16. System.out.println("获取到的元素内容是: " + element.text());
  17. for (Element span : spans) {
  18. System.out.println(span.text());
  19. }
  20. System.out.println(clazz.text());
  21. System.out.println("abc.text() = " + abc.text());
  22. System.out.println("href.text() = " + href.text());
  23. }

元素中获取数据:

  1. 从元素中获取id
  2. 从元素中获取className
  3. 从元素中获取属性的值 attr
  4. 从元素中获取所有属性attributes
  5. 从元紊中获取文本内容 text

    1. @Test
    2. public void testDate() throws IOException {
    3. // 1.解析文件获取Document
    4. Document doc = Jsoup.parse(new File(TESTHTML), "utf8");
    5. // 2.根据id获取元素
    6. Element element = doc.getElementById("test");
    7. String str = "";
    8. //元素中获取数据:
    9. // 1. 从元素中获取id
    10. str = element.id();
    11. // 2. 从元素中获取className
    12. str = element.className();
    13. Set<String> sets = element.classNames();
    14. for (String set : sets) {
    15. System.out.println("set = " + set);
    16. }
    17. // 3. 从元素中获取属性的值 attr
    18. str = element.attr("id");
    19. str = element.attr("class");
    20. // 4. 从元素中获取所有属性attributes
    21. Attributes attributes = element.attributes();
    22. System.out.println("attributes = " + attributes.toString());
    23. // 5. 从元紊中获取文本内容 text
    24. str = element.text();
    25. // 打印获取到的内容
    26. System.out.println("获取到的数据:" + str);
    27. }


    3.6 Selector选择器概述

    tagname:通过标签查找元素,比如: span
    #id:通过ID查找元素,比如:#city_bj .class:通过 class名称查找元素,比如:.class_a
    [attribute]:利用属性查找元素,比如:[abc]
    [attr=value]:利用属性值来查找元素,比如:[class=s_name] ```java @Test public void testSelector() throws Exception{

     // 解析html文件,获取Document对象
     Document doc = Jsoup.parse(new File(TESTHTML), "utf8");
    
    Elements spans = doc.select("span");
    for (Element span : spans) {
        System.out.println(span.text());
    }

    Element element = doc.select("#city_bj").first();

    element = doc.select(".class_a").first();

    element = doc.select("[abc]").first();

    element = doc.select("[class=a_name]").first();

    System.out.println("获取到的结果为:" + element.text());
}
<a name="gLqmD"></a>
#### <br />3.7 Selector选择器组合使用
```java
    @Test
    public void testSelector2() throws Exception {
        // 解析html文件, 获取Document对象
        Document doc = Jsoup.parse(new File(TESTHTML), "utf8");

        //el#id: 元素+ID,比如: h3#city_bj
        //Element element = doc.select("h3#city_bj").first();

        //el.class: 元素+class,比如: li.class_a
        //Element element = doc.select("li.class_a").first();

        //el[attr]: 元素+属性名,比如: span[abc]
        //Element element = doc.select("span[abc]").first();

        //任意组合: 比如:span[abc].s_name
        Element element = doc.select("span[abc].a_name").first();

        // 后代选择器
        //Elements elements = doc.select(".city_con li");

        // 父子选择器
        //Elements elements = doc.select(".city_con > ul > li");

        //parent > *: 查找某个父元素下所有直接子元素
        Elements elements = doc.select(".city_con > ul > *");

        // 打印
        System.out.println("获取到的内容是: " + element.text());

        for (Element ele : elements) {
            System.out.println("遍历的结果: " + ele.text());
        }
    }