使用Jsoup解析HTML进行数据收集

Jsoup简介

回顾XML简介与解析

Jsoup官方地址

Jsoup中文文档

  • Jsoup是一种Java 的HTML(html也是XML文档)解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套易于操作的API,可通过DOM,CSS以及类似于jQuery选择器的操作方法来取出和操作数据。使用jsoup就可以解析HTML。
  • Jsoup使用的是DOM解析方式,把整个HTML文档(XML文档)加载到内存中形成一棵DOM树,得到文档的Document对象。HTML里的标签,会转换成Element对象

Jsoup的基本使用步骤

1.引入依赖

 <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.11.2</version>
 </dependency>

2.解析HTML,得到文档的Document对象

  • 读取字符串,得到Document: Document document = Jsoup.parse(String html);
  • 读取文件,得到Document:Document document = Jsoup.parse(File file, String charset);
  • 读取url,得到Document:Document document = Jsoup.connect(String url).get();
//Jsoup获取Document的方式
public class JsoupDocument {

    //读取字符串,得到Document
    @Test
    public void test1(){
        String html="\n" +
                "<!DOCTYPE html>\n" +
                "<html>\n" +
                "<head>\n" +
                "    <meta charset=\"utf-8\">\n" +
                "    <title>测试</title>\n" +
                "</head>\n" +
                "<body>\n" +
                "<!-- 职位列表 -->\n" +
                "<div class=\"s_position_list \" id=\"s_position_list\">\n" +
                "    <ul class=\"item_con_list\">\n" +
                "        <li>\n" +
                "            <div class=\"list_item_top\">\n" +
                "                <div class=\"position\">\n" +
                "                    <div class=\"p_top\">\n" +
                "                        <a class=\"position_link\" href=\"\">\n" +
                "                            <!-- 工作地点 -->\n" +
                "                            <h3>高级Java开发工程师(上海、深圳、新加坡)</h3>\n" +
                "                            <span class=\"add\">[<em>上海·浦东新区</em>]</span>\n" +
                "                        </a>\n" +
                "                        <span class=\"format-time\">2020-02-26</span>\n" +
                "                    </div>\n" +
                "                    <div class=\"p_bot\">\n" +
                "                        <div class=\"li_b_l\">\n" +
                "                            <span class=\"money\">25k-50k</span>\n" +
                "                            <!-- 工作经验及学历要求 -->\n" +
                "                            经验3-5年 / 本科\n" +
                "                        </div>\n" +
                "                    </div>\n" +
                "                </div>\n" +
                "                <div class=\"company\">\n" +
                "                    <div class=\"company_name\">\n" +
                "                        <!-- 公司名称 -->\n" +
                "                        <a href=\"\" >蚂蚁金服集团</a>\n" +
                "                    </div>\n" +
                "                    <div class=\"industry\">\n" +
                "                        <!-- 行业领域 融资阶段 公司规模-->\n" +
                "                        金融,移动互联网 / B轮 / 2000人以上\n" +
                "                    </div>\n" +
                "                </div>\n" +
                "                <div class=\"com_logo\">\n" +
                "                    <a href=\"\">\n" +
                "                        <!-- 图标logo -->\n" +
                "                        <img src=\"//www.lgstatic.com/thumbnail_120x120/i/image/M00/1F/54/CgpFT1kRuMmASL74AAAg3WZnNI005.jpeg\" alt=\"蚂蚁金服集团\"\n" +
                "                             width=\"60\" height=\"60\">\n" +
                "                    </a>\n" +
                "                </div>\n" +
                "            </div>\n" +
                "            <div class=\"list_item_bot\">\n" +
                "                <div class=\"li_b_l\">\n" +
                "                    <!-- 职位描述 -->\n" +
                "                    <span>互联网金融</span>\n" +
                "                    <span>后端</span>\n" +
                "                    <span>分布式</span>\n" +
                "                </div>\n" +
                "                <!-- 福利 -->\n" +
                "                <div class=\"li_b_r\">“全球化视野”</div>\n" +
                "            </div>\n" +
                "        </li>\n" +
                "    </ul>\n" +
                "\n" +
                "</body>\n" +
                "</html>";
        Document document = Jsoup.parse(html);
        System.out.println(document);
    }

    //读取文件,得到Document
    @Test
    public void test2() throws IOException {
        String path = this.getClass().getClassLoader().getResource("test.html").getPath();
        Document document = Jsoup.parse(new File(path),"UTF-8");
        System.out.println(document);
    }


    //读取url,得到Document
    @Test
    public void test3() throws IOException {
        Document document = Jsoup.connect("https://blog.csdn.net/qq_45615417").get();
        System.out.println(document);
    }
}

test.html(要解析的html文档):

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>测试</title>
</head>
<body>
<!-- 职位列表 -->
<div class="s_position_list " id="s_position_list">
    <ul class="item_con_list">
        <li>
            <div class="list_item_top">
                <div class="position">
                    <div class="p_top">
                        <a class="position_link" href="">
                            <!--职位-->
                            <h3>高级Java开发工程师(上海、深圳、新加坡)</h3>
                            <!-- 工作地点 -->
                            <span class="add">[<em>上海·浦东新区</em>]</span>
                        </a>
                        <span class="format-time">2020-02-26</span>
                    </div>
                    <div class="p_bot">
                        <div class="li_b_l">
                            <span class="money">25k-50k</span>
                            <!-- 工作经验及学历要求 -->
                            经验3-5年 / 本科
                        </div>
                    </div>
                </div>
                <div class="company">
                    <div class="company_name">
                        <!-- 公司名称 -->
                        <a href="" >蚂蚁金服集团</a>
                    </div>
                    <div class="industry">
                        <!-- 行业领域 融资阶段 公司规模-->
                        金融,移动互联网 / B轮 / 2000人以上
                    </div>
                </div>
                <div class="com_logo">
                    <a href="">
                        <!-- 图标logo -->
                        <img src="//www.lgstatic.com/thumbnail_120x120/i/image/M00/1F/54/CgpFT1kRuMmASL74AAAg3WZnNI005.jpeg" alt="蚂蚁金服集团"
                             width="60" height="60">
                    </a>
                </div>
            </div>
            <div class="list_item_bot">
                <div class="li_b_l">
                    <!-- 职位描述 -->
                    <span>互联网金融</span>
                    <span>后端</span>
                    <span>分布式</span>
                </div>
                <!-- 福利 -->
                <div class="li_b_r">“全球化视野”</div>
            </div>
        </li>
    </ul>

</body>
</html>

3.从Document里找到标签Element对象

获取Element对象的两种方式
①使用类似js的方式
  • 根据id找到Element对象: Element element = document.getElementById(String id)
  • 根据标签找到Element对象:Elements elements = document.getElementsByTag(String tagName);
  • 根据类名找到Element对象: Elements elements = document.getElementsByClass(String className);
  • 根据属性找到Element对象:Elements elements = document.getElementsByAttribute(String attrName);
  • 获取当前元素的父节点对象:Element parentElement = element.parent();
  • 获取当前元素的子元素列表: Elements elements = element.children();
  • Element是标签转换成的一个对象。
  • Elements本质是ArrayList<Element>,是一个Element的集合。
//Jsoup获取Element标签
public class JsoupElement {
   private Document document;

    @Before
    public void init() throws IOException {
        String path = this.getClass().getClassLoader().getResource("test.html").getPath();
        document = Jsoup.parse(new File(path),"UTF-8");
    }

   //使用类似js的方法获取Element标签
   @Test
    public void testJS1(){
         //查找id为s_position_list的元素
        Element element = document.getElementById("s_position_list");
        System.out.println(element);
    }
    @Test
    public void testJS2(){
        //查找所有的span标签
        Elements elements = document.getElementsByTag("span");
        /*输出结果:
                 <span class="add">[<em>上海·浦东新区</em>]</span>

                 <span class="format-time">2020-02-26</span>

                 <span class="money">25k-50k</span>

                 <span>互联网金融</span>

                 <span>后端</span>

                 <span>分布式</span>
         */

        //查询所有类名为company的元素
        elements = document.getElementsByClass("company");
        /*
        <div class="company">
           <div class="company_name">
             <!-- 公司名称 -->
             <a href="">蚂蚁金服集团</a>
           </div>
           <div class="industry">
             <!-- 行业领域 融资阶段 公司规模-->
              金融,移动互联网 / B轮 / 2000人以上
           </div>
       </div>
         */

        //查找所有包含href属性的元素
        elements = document.getElementsByAttribute("href");
        /*
        <a class="position_link" href="">
        <h3>高级Java开发工程师(上海、深圳、新加坡)</h3>
        <span class="add">[<em>上海·浦东新区</em>]</span>
        </a>

        <a href="">蚂蚁金服集团</a>

        <a href="">
         <img src="//www.lgstatic.com/thumbnail_120x120/i/image/M00/1F/54/CgpFT1kRuMmASL74AAAg3WZnNI005.jpeg" alt="蚂蚁金服集团" width="60" height="60">
        </a>
         */

        for (Element element : elements) {
            System.out.println(element);
        }
    }
}

②使用类似jQuery选择器的方式

常用选择器

jQuery常用选择器

  • div.cls :获取类名为cls的div元素
  • :has(selector):获取包含有selector结果的元素。比如:li:has(a)获取文档中有a元素的li元素
  • :not(selector):包含有selector选择的结果不要。比如:li:not(a)获取文档中没有a元素的li元素

Document对执行选择器的方法

 Elements elements = document.select(String cssQuery);
 Elements elements = element.select(String cssQuery);
 Elements elementsResult = elements.select(String cssQuery);
 //cssQuery:选择器
 
//Document对象使用此方法:从整个html文档里查找
//Element对象使用此方法:从该Element标签内部查找
//Elements对象使用此方法:从该Elements标签内部查找

代码示例:

//Jsoup获取Element标签
public class JsoupElement {
   private Document document;

    @Before
    public void init() throws IOException {
        String path = this.getClass().getClassLoader().getResource("test.html").getPath();
        document = Jsoup.parse(new File(path),"UTF-8");
    }
  //使用类似JQ选择器方法获取Element标签
    @Test
    public void testJQ1(){
        //通过标签选择器的方式获取Element对象
        Elements elements = document.select("#s_position_list");
        System.out.println(elements);
    }

    @Test
    public void testJQ2(){
        //标签选择器查找span元素
        Elements elements = document.select("span");
        /*输出结果:
        <span class="add">[<em>上海·浦东新区</em>]</span>
        <span class="format-time">2020-02-26</span>
        <span class="money">25k-50k</span>
        <span>互联网金融</span>
        <span>后端</span>
        <span>分布式</span>
         */

        //组合选择器查找类名为li_b_l的div元素
         elements = document.select("div.li_b_l");
        /*
        <div class="li_b_l">
            <span class="money">25k-50k</span>
             经验3-5年 / 本科
        </div>
        <div class="li_b_l">
            <span>互联网金融</span>
            <span>后端</span>
            <span>分布式</span>
        </div>
         */

        //获取role属性值为listbox的div元素
        elements = document.select("div[class='list_item_bot']");
        /*
        <div class="list_item_bot">
           <div class="li_b_l">
            <span>互联网金融</span>
            <span>后端</span>
            <span>分布式</span>
          </div>

          <div class="li_b_r">
             “全球化视野”
          </div>
        </div>
         */

        //获取索引小于1的li元素
        elements = document.select("li:lt(1)");//注意:这个找的是整个文档每一部分出现li元素的第一个

        //扩展:这个方法找的才是整个文档的第一个li元素
        elements = document.select("li");
        elements.get(0);

        for (Element element : elements) {
            System.out.println(element);
        }
    }
}

4.从Element上获取数据

  • 获取标签体:html()
  • 获取标签体里文本:text()
  • 获取属性值: attr(String attrName)
//Jsoup获取标签上的数据
public class JsoupData {
    private  Document document;
    @Before
    public void init() throws IOException {
        String path = this.getClass().getClassLoader().getResource("test.html").getPath();
         document = Jsoup.parse(new File(path), "UTF-8");
    }

    @Test
    public void test1(){
        //获取类名为company_name的元素
        Elements elements = document.select(".company_name");

        //获取标签体内容
        String html = elements.html();
        System.out.println(html);
        /*
        <!-- 公司名称 -->
        <a href="">蚂蚁金服集团</a>
         */

        //获取标签体文本内容
        String text = elements.text();
        System.out.println(text);
        /*
        蚂蚁金服集团
         */

        //获取类名为com_logo的后代元素img的placeholder属性值
            //1.使用层级选择器,获取类名为com_logo的后代元素img
        elements = document.select(".com_logo img");
        System.out.println(elements);
        /*
        <img src="//www.lgstatic.com/thumbnail_120x120/i/image/M00/1F/54/CgpFT1kRuMmASL74AAAg3WZnNI005.jpeg" alt="蚂蚁金服集团" width="60" height="60">
         */
            //2.获取img的placeholder属性值
        String src = elements.attr("src");
        System.out.println(src);
        /*
        //www.lgstatic.com/thumbnail_120x120/i/image/M00/1F/54/CgpFT1kRuMmASL74AAAg3WZnNI005.jpeg
         */
    }
}

基于Jsoup的拓展——jsoupXPath的使用

jsoupXPath官网

  • jsoupXPath:使用xpath解析HTML的解析器,html的DOM树借助jsoup生成。
  • XPath:使用路径表达式来选取HTML文档中的元素节点或属性节点。

常用的XPath表达式

XPath表达式:用于选取HTML文档中节点的表达式字符串。

获取XML文档节点元素一共有如下4种XPath语法方式:

  1. 绝对路径表达式方式:以/开头,一级一级描述标签的层级路径,不可以跨层级.。
/body/ul/li: 查找html里根标签下body,body下的ul,ul下的li
注:开头的“/”代表HTML文档根元素,所以在绝对路径中不可以写根元素路径。
  1. 全文搜索路径表达式方式:以//开头
//li:全文搜索所有的li标签
  1. 条件筛选方式:以//开头,根据条件过滤判断进行选取节点。
//a[@id='rname']:查找id属性值为rname的a元素

//a[@id='rname']/@href:查找id属性值为rname的a元素,获取a元素的href属性

//a[@id='rname']/text():查找id属性值为rname的a元素,获取元素里自有的文本
自有的文本:该标签的文本,不包含该标签子标签的文本。

//a[@id='rname']/allText():查找id属性值为rname的a元素,获取元素里所有的文本
所有的文本:该标签文本与其子标签文本都会获取。

//a[@id='rname']/html():查找id属性值为rname的a元素,获取元素的标签体

jsoupXPath使用步骤

1. jsoupXPath核心类JXDocument和执行Xpath表达式字符串的API方法介绍

JXDocument是Document的包装类,额外增加了XPath表达式的支持

  • 构造方法:JXDocument jxDocument = new JXDocument(Document document)

  • 执行Xpath表达式字符串常用方法:List<Object> list = jxDocument.sel(String xpath)

2.使用步骤

①引入依赖

        <dependency>
            <groupId>cn.wanghaomiao</groupId>
            <artifactId>JsoupXpath</artifactId>
            <version>2.2</version>
        </dependency>

②创建JXDocument对象
③使用sel()方法,执行xpath表达式,获取结果

示例:

public class TestJsoupXpath {
    @Test
    public void testJsoupXpath() throws IOException {
        String path = this.getClass().getClassLoader().getResource("test.html").getPath();
        Document document = Jsoup.parse(new File(path), "utf-8");
        //创建JXDocument对象
        JXDocument jxDocument = new JXDocument(document);

        //使用sel()方法,得到结果

            //绝对路径表达式方式,获取html里 /body/div/ul/li/div/div/a/h3
        List<Object> objects = jxDocument.sel("/body/div/ul/li/div/div/div/a/h3");
        /*输出结果:
        <h3>高级Java开发工程师(上海、深圳、新加坡)</h3>
         */

            //全文搜索路径表达式方式,获取所有的img标签
        objects = jxDocument.sel("//img");
        /*
        <img src="//www.lgstatic.com/thumbnail_120x120/i/image/M00/1F/54/CgpFT1kRuMmASL74AAAg3WZnNI005.jpeg" alt="蚂蚁金服集团" width="60" height="60">
         */

            //条件筛选方式:获取class属性值是industry的div元素
        objects = jxDocument.sel("//div[@class='industry']");
        /*
        <div class="industry">
            <!-- 行业领域 融资阶段 公司规模-->
            金融,移动互联网 / B轮 / 2000人以上
        </div>
         */


            //条件筛选方式:获取class属性值是li_b_l的div元素的标签体文本(自有文本)
        objects = jxDocument.sel("//div[@class='li_b_l']/text()");
        /*
        经验3-5年 / 本科
         */


            //条件筛选方式:获取class属性值是li_b_l的div元素的标签体文本(所有文本)
        objects = jxDocument.sel("//div[@class='li_b_l']/allText()");
        /*
        25k-50k
        经验3-5年 / 本科

        互联网金融 后端 分布式
         */

            //条件筛选方式:获取class属性值是li_b_l的div元素的标签体
        objects = jxDocument.sel("//div[@class='li_b_l']/html()");
        /*
        <span class="money">25k-50k</span>
        <!-- 工作经验及学历要求 -->
         经验3-5年 / 本科

        <!-- 职位描述 -->
        <span>互联网金融</span>
        <span>后端</span>
        <span>分布式</span>
         */


        for (Object object : objects) {
            if (object instanceof Element) {
                Element element = (Element) object;
                System.out.println(element);
            }else{
                System.out.println(object);
            }

        }
    }
}

test.html(要解析HTML文档)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>测试</title>
</head>
<body>
<!-- 职位列表 -->
<div class="s_position_list " id="s_position_list">
    <ul class="item_con_list">
        <li>
            <div class="list_item_top">
                <div class="position">
                    <div class="p_top">
                        <a class="position_link" href="">
                            <!--职位-->
                            <h3>高级Java开发工程师(上海、深圳、新加坡)</h3>
                            <!-- 工作地点 -->
                            <span class="add">[<em>上海·浦东新区</em>]</span>
                        </a>
                        <span class="format-time">2020-02-26</span>
                    </div>
                    <div class="p_bot">
                        <div class="li_b_l">
                            <span class="money">25k-50k</span>
                            <!-- 工作经验及学历要求 -->
                            经验3-5年 / 本科
                        </div>
                    </div>
                </div>
                <div class="company">
                    <div class="company_name">
                        <!-- 公司名称 -->
                        <a href="" >蚂蚁金服集团</a>
                    </div>
                    <div class="industry">
                        <!-- 行业领域 融资阶段 公司规模-->
                        金融,移动互联网 / B轮 / 2000人以上
                    </div>
                </div>
                <div class="com_logo">
                    <a href="">
                        <!-- 图标logo -->
                        <img src="//www.lgstatic.com/thumbnail_120x120/i/image/M00/1F/54/CgpFT1kRuMmASL74AAAg3WZnNI005.jpeg" alt="蚂蚁金服集团"
                             width="60" height="60">
                    </a>
                </div>
            </div>
            <div class="list_item_bot">
                <div class="li_b_l">
                    <!-- 职位描述 -->
                    <span>互联网金融</span>
                    <span>后端</span>
                    <span>分布式</span>
                </div>
                <!-- 福利 -->
                <div class="li_b_r">“全球化视野”</div>
            </div>
        </li>
    </ul>

</body>
</html>

案例:使用Java+Jsoup做数据爬虫

发布了48 篇原创文章 · 获赞 18 · 访问量 2938

猜你喜欢

转载自blog.csdn.net/qq_45615417/article/details/104609723