Jsoup

Jsoup

XML 解析

数据存储在 XML 后,我们就希望通过程序获取 XML 的内容。
人们为不同问题提供不同的解析方式,使用不同的解析器进行解析,方便开发人员操作 XML。

解析方式

解析方式:市场上的解析方式有三种:
1. DOM:要求解析器把整个 XML 文档装载到内存,
   Document Object Model
   并解析成一个 Document 对象
   优点:元素与元素之间保留结构关系,可以进行增删改查操作。
   缺点:XML 文档过大,可能出现内存溢出。
   
2. SAX:是一种速度更快,更有效的方法。它逐行扫描文档,
   Simple Api for Xml 一边扫描一边解析。并以事件驱动的方式进行解析。
   优点:处理速度快,可以处理过大 XML 文档。
   缺点:只能读,逐行后将释放资源,解析操作繁琐。

3. PULL:Android 内置的 XML 解析方式,类似 SAX。

解析器:

根据不同的解析方式提供具体实现。
   
有的解析器操作过于繁琐,为了方便开发人员,提供易于操作的解析开发包。

解析开发包:
JAXP:sun 公司提供支持 DOM 和 SAX 开发包
Dom4j:比较简单的的解析开发包
JDom:与 Dom4j 类似
JSoup:功能强大 DOM 方式的 XML 解析开发包,尤其对 HTML 解析更加方便。

什么是 Jsoup

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

Jsoup 的应用场景

1. 解析 XML 文档并操作和管理 XML 元素、属性、元素体等数据。

2. 解析 HTML 页面并进行数据收集,例如:爬虫

Jsoup 的基本使用

解析原理:


XML DOM 和 HTML DOM 一样,XML DOM 将整个 XML 文档加载到内存,生成一个 DOM 树,
并获得一个 Document 对象,通过 Document 对象就可以对 DOM 进行操作。

以下面 books.xml 文档为例:

 version="1.0" encoding="UTF-8"?>
<books>
    <book id="it0001">
        <name>JavaWeb 开发教程name>
        <author>张孝祥author>
        <sale>100.00 元sale>
    book>
    <book id="it0002">
        <name>三国演义name>
        <author>罗贯中author>
        <sale>100.00 元sale>
    book>
books>

结构模型:

DOM 中的核心概念就是节点,在 XML 文档中的元素、属性、文本,在 DOM 中都是节点!

所有的节点都封装到了 Document 对象中。

引入 Jsoup 的 JAR 包:

由于 DOM 方式解析 XML 文档所有都是节点,
所有节点又都被封装到 Document 对象中,

所以解析的重点就是获取 Document 对象,之后在根据 Document对象的相关方法就可以获取和操作 XML 文档数据,

那么现在如何使用 Jsoup 获取 Document 对象呢?

获取 Document 文档对象

static Document parse(String html)  将给定的html代码解析成文档。

static Document parse(File in, String charsetName)  将指定的字符集文件解析成文档。


static Connection connect(String url)   创建并返回URL的连接。
Document get() 以get方式发送请求并对返回结果Document进行解析

/**
* 根据 XML 文档字符串获取 Document
*/
@Test
public void test1(){
    String str = "WWW.BAIDU.COM";
    //根据 XML 文档字符串获取 Document
    Document document = Jsoup.parse(str);
    System.out.println(document);
}

/**
* 根据文件获取 Document
* 加载 src/book.xml
*/
@Test
public void test2() throws Exception{
    //获取文件路径
    String path = this.getClass().getResource("/book.xml").getPath();
    
    File file = new File(path);
    
    //根据文件获取 Document
    Document document = Jsoup.parse(file, "UTF-8");
    System.out.println(document);
}

/**
* 根据 url 获取 Document
*/
@Test
public void test3() throws Exception{
    String url = "https://www.tmall.com/";
    //根据 url 获取 Document
    Document document = Jsoup.connect(url).get();
    System.out.println(document);
}

Document 对象常用方法解析 XML

获取元素:

getElementById(String id) 用id获得元素
getElementsByTag(String tag) 用标签获得元素
getElementsByClass(String className) 用class获得元素
getElementsByAttribute(String key)  用属性获得元素

获得与设置元素的数据

attr(String key)  获得元素的数据 
attr(String key, String value) 设置元素数据 
attributes() 获得所以属性
id(), className()  classNames() 获得id class得值
text()获得文本值
text(String value) 设置文本值
html() 获取html 
html(String value)设置html
outerHtml() 获得内部html
data()获得数据内容
tag()  获得tag  tagName() 获得tagname 

index.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body id="main">
    <h1 id="footer">XML&JSOUPh1>
    <h3><font color="red">font>h3>
    <h3><font color="green">font>h3>
    <h3><font color="blue">font>h3>
    <div class="item"><font color="yellow">font>div>
    <div class="item"><font color="pink">font>div>
    <div class="item"><font color="purple">font>div>
    <span data-toggle="abc">span>
    <span data-toggle="abc">span>
    <span data-tip="abc">!span>
    <a href="#"><div>去百度div>a>
    <a href="#"><div>去新浪div>a>
    <ul>
        <li class="bj">北京li>
        <li class="sh">上海li>
        <li class="gz">广州li>
        <li class="sz">深圳li>
    ul>
    <ol>
        <li class="bj">北京北京li>
        <li class="sh">上海上海li>
        <li class="gz">广州广州li>
        <li class="sz">深圳深圳li>
    ol>
 body>
html>

/**
 * Document 对象常用方法解析 XML
 * 读取 src/index.html
 */
public class Demo {
        private Document document;

        @Before
        public void init() throws Exception{
            //获取文件路径
            String path = this.getClass().getResource("/index.html").getPath();

            File file = new File(path);

            //根据文件获取 Document
            document = Jsoup.parse(file, "UTF-8");
        }
        /**
         * 需求 1:获取 index.html 中所有 h3 标签名称的元素列表并打印输出
         * API:Elements elements = document.getElementsByTag("h3");
         * API:String nodeName = element.nodeName();
         * API:String html = element.html();
         * API:String text = element.text();
         */
        @Test
        public void test1() throws Exception{
            //根据标签名获取元素
            Elements elements = document.getElementsByTag("h3");

            if(elements!=null && elements.size()>0){
                //遍历
                for (Element e : elements) {

                    System.out.println(e.nodeName());

                    System.out.println(e.html());

                    System.out.println(e.text());
                }
            }
        }

        /**
         *需求 2:获取 index.html 中所有元素含有 class 属性值为 item 并打印输出
         * API:Elements elements = document.getElementsByClass("item");
         */
        @Test
        public void test2() throws Exception{

            Elements elements = document.getElementsByClass("item");

            if(elements!=null && elements.size()>0){
                for (Element e : elements) {

                    System.out.println(e.nodeName()+"&"+e.text());
                }
            }
        }
        /**
         *需求 3:获取 index.html 中所有元素含有属性 data‐toggle 所有元素列表并打印输出
         * API:Elements elements = document.getElementsByAttribute("data‐toggle");
         */
        @Test
        public void test3() throws Exception{

            Elements elements = document.getElementsByAttribute("data-toggle");
            if(elements!=null && elements.size()>0){
                for (Element e : elements) {
                    System.out.println(e.nodeName()+"&"+e.text());
                }
            }
        }
        /**
         *需求 4:获取 index.html 中元素属性 id="footer"的一个元素并打印输出
         * API:Element e = document.getElementById("footer");
         */
        @Test
        public void test4() throws Exception{
            Element e = document.getElementById("footer");
            System.out.println(e.nodeName()+"&"+e.text());
        }
        /**
         *需求 5:获取 index.html 中元素属性 id="footer"的一个元素的父元素标签名称并打印输出
         * API:Element ep = e.parent();
         */
        @Test
        public void test5() throws Exception{
            Element e = document.getElementById("footer");
            Element ep = e.parent();
            System.out.println(ep.nodeName()+"&"+ep.text());
        }
        /**
         *需求 6:获取 index.html 中元素属性 id="footer"的元素的父元素的子元素列表的长度个数
         */
        @Test
        public void test6() throws Exception{
            Element e = document.getElementById("footer");
            Element ep = e.parent();

            Elements elements = ep.children();

            System.out.println(elements.size());
            if(elements!=null && elements.size()>0){
                for (Element element : elements) {
                    System.out.println(element.nodeName()+"&"+element.text());
                }
            }
        }
}

Jsoup 选择器解析(针对 HTML/XML)

选择器分为:基本选择器、组合选择器、伪类选择器。

基本选择器

tagname 使用标签名来定位,例如 a      h3

ns|tag  使用命名空间的标签定位,例如 fb:name 来查找 <fb:name> 元素 

#id     使用元素 id 定位,例如 #logo 

.class     使用元素的 class 属性定位,例如 .head 

*     定位所有元素 

[attribute] 使用元素的属性进行定位,例如 [href] 表示检索具有 href 属性的所有元素 

[^attr] 使用元素的属性名前缀进行定位,例如 [^data-] 用来查找 HTML5  dataset 属性 

[attr=value]使用属性值进行定位,例如 [width=500] 定位所有 width 属性值为 500 的元素 

[attr^=value],[attr$=value],[attr*=value] 这三个语法分别代表,属性以 value 开头、结尾以及包含 

[attr~=regex]使用正则表达式进行属性值的过滤,例如 img[src~=(?i)\.(png|jpe?g)] 

/**
 * Jsoup 中的三种选择器解析‐基本选择器
 * 读取 src/index.html
 */
public class Demo {
    private Document document;
    @Before
    public void init() throws Exception{
        
        String path = this.getClass().getResource("/index.html").getPath();
        
        File file = new File(path);
        //根据文件获取 Document
        document = Jsoup.parse(file, "UTF-8");
    }

    /**
     *需求 1:获取 id="footer"元素并输出元素名称
     *API:Elements elements = document.select("#footer");
     */
    @Test
    public void test1() throws Exception{
        Elements elements = document.select("#footer");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
    /**
     *需求 2:获取 index.html 中所有元素含有 class 属性值为 item 并打印输出元素体内容
     * API:Elements elements = document.select(".item");
     */
    @Test
    public void test2() throws Exception{
        Elements elements = document.select(".item");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
    /**
     *需求 3:获取 index.html 中所有 h3 标签名称的元素列表并打印输出元素名称
     * API:Elements elements = document.select("h3");
     */
    @Test
    public void test3() throws Exception{
        Elements elements = document.select("h3");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
    /**
     *需求 4:获取 index.html 中含有属性 data‐toggle 所有元素并打印输出元素名称和元素体数据
     * API:Elements elements = document.select("[data‐toggle]");
     */
    @Test
    public void test4() throws Exception{
        Elements elements = document.select("[data-toggle]");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
    /**
     *需求 5:获取 index.html 中含有属性以 data 属性名开头的所有元素列表并打印输出元素名称
     * API:Elements elements = document.select("[^data]");
     */
    @Test
    public void test5() throws Exception{
        Elements elements = document.select("[^data]");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
    
    /**
     *需求 6:获取 index.html 中属性 data‐toggle 值为"abc"的所有元素列表并打印输出元素名称
     * API:Elements elements = document.select("[data‐toggle='abc']");
     */
    @Test
    public void test6() throws Exception{
        Elements elements = document.select("[data-toggle='abc']");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
    
    /**
     *需求 7:获取 index.html 中属性 data‐toggle 值以"a"开头前缀的所有元素列表并打印输出元素名称
     * API:
     */
    @Test
    public void test7() throws Exception{
        Elements elements = document.select("[data-toggle^='a']");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
    
    /**
     *需求 8:获取 index.html 中属性 data‐toggle 值包含"a"的所有元素列表并打印输出元素名称
     * API:
     */
    @Test
    public  void test08() throws IOException {
        
        Elements elements = document.select("[data-toggle*=a]");
        
        for (Element e : elements) {
            System.out.println(e.nodeName()+"&"+e.text());
        }
    }
    
}

组合选择器

el#id      定位id值某个元素,例如 a#logo -> <a id=logo href=  > 
    
el.class   定位 class 为指定值的元素,例如 div.head -> <div class=head>xxxxdiv> 

el[attr]   定位所有定义了某属性的元素,例如 a[href] 

以上三个任意组合     例如 a[href]#logo 、a[name].outerlink、a[href].highlight

   
ancestor child: 查找某个元素下子元素,比如:可以用.body p 查找在"body"元素下的所有 p元素

parent > child: 查找某个父元素下的直接子元素,
比如:可以用div.content > p 查找 p 元素,也可以用body > * 查找body标签下所有直接子元素

siblingA + siblingB: 查找在A元素之前第一个同级元素B,比如:div.head + div

siblingA ~ siblingX: 查找A元素之前的同级X元素,比如:h1 ~ p

el, el, el:多个选择器组合,查找匹配任一选择器的唯一元素,
例如:div.masthead, div.logo

/**
 * Jsoup 中的三种选择器解析‐组合选择器
 * 读取 src/02_index.html
 */
public class Demo {
    private Document document;
    @Before
    public void init() throws Exception{
        String path = this.getClass().getResource("index.html").getPath();
        File file = new File(path);
        document = Jsoup.parse(file, "UTF-8");
    }
    /**
     *需求 1:获取 index.html 中 div 元素含有 class 属性值为 item 并打印元素数据
     *API:Elements elements = document.select("div.item");
     */
    @Test
    public void test1() throws Exception{
        Elements elements = document.select("div.item");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
    /**
     *需求 2:获取 index.html 中 a 元素含有属性 href 的所有元素列表并打印元素数据
     *API:Elements elements = document.select("a[href]");
     */
    @Test
    public void test2() throws Exception{
        Elements elements = document.select("a[href]");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
/**
 *需求 3:获取 index.html 中属性 id 值为"main"的所有 div 子孙元素并打印元素数据
 *API:Elements elements = document.select("#main div");
 */
    @Test
    public void test3() throws Exception{
        Elements elements = document.select("#main div");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
    /**
     *需求 4:获取 index.html 中属性 id 值为"main"的直接 div 子元素并打印元素数据
     *API:Elements elements = document.select("#main>div");
     */
    @Test
    public void test4() throws Exception{
        Elements elements = document.select("#main>div");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
    /**
     *需求 5:获取 index.html 中 class="item"元素后面同级第一个 div 元素并打印元素数据
     *API:Elements elements = document.select(".item + div");
     */
    @Test
    public void test5() throws Exception{
        Elements elements = document.select(".item + div");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
    /**
     *需求 6:获取 index.html 中 class="item"元素后面同级所有 div 元素并打印元素数据
     *API:Elements elements = document.select(".item ~ div");
     */
    @Test
    public void test6() throws Exception{
        Elements elements = document.select(".item ~ div");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName()+"#"+e.text());
            }
        }
    }
}

伪类选择器

:lt(n): 查找哪些元素的同级索引值(它的位置在DOM树中是相对于它的父节点)小于n,
比如:td:lt(3) 表示索引号小于3的lt元素 

:gt(n):查找哪些元素的同级索引值大于n,
比如: div p:gt(2)表示哪些div中索引号大于2的p元素

:eq(n): 查找哪些元素的同级索引值与n相等,
比如:form input:eq(1)表示Form中索引号等于1的input标签的元素

//注意:上述伪选择器索引是从0开始的,也就是说第一个元素索引值为0,第二个元素index为1等

:has(seletor): 查找匹配选择器包含元素的元素,
比如:div:has(p)表示哪些div包含了p元素 

:not(selector): 查找与选择器不匹配的元素,
比如: div:not(.logo) 表示不包含 class=logo 元素的所有 div 列表 

:contains(text): 查找包含给定文本的元素,搜索不区分大不写,
比如: p:contains(jsoup)
    
:containsOwn(text): 查找直接包含给定文本的元素

:matches(regex): 查找哪些元素的文本匹配指定的正则表达式,
比如:div:matches((?i)login)
    
:matchesOwn(regex): 查找自身包含文本匹配指定正则表达式的元素

/**
 * Jsoup 中的三种选择器解析‐伪类选择器
 * 读取 src/index.html
 */
public class Demo {
    private Document document;
    @Before
    public void init() throws Exception{
        String path = this.getClass().getResource("/index.html").getPath();
        File file = new File(path);
        document = Jsoup.parse(file, "UTF-8");
    }
    /**
     *需求 1:属性 class 值为"item"的元素,并且该元素含有 font 元素并打印元素数据
     *API:Elements elements = document.select(".item(font)");
     */
    @Test
    public void test1() throws Exception{
        Elements elements = document.select(".item:has(font)");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
    /**
     *需求 2:获取 index.html 中 ul 中的 li 元素,并且排除当前元素 class="gz"的元素并打印元素数据
     *API:Elements elements = document.select("ul li:not(.gz)");
     */
    @Test
    public void test2() throws Exception{
        Elements elements = document.select("ul li:not(.gz)");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
    /**
     *需求 3:获取 index.html 中 ul 中的 li 元素,并且排除当前元素 class="gz"的元素,并且索引号大于 0,并打印元素
     数据
     *API:Elements elements = document.select("ul li:not(.gz):gt(0)");
     */
    @Test
    public void test3() throws Exception{
        Elements elements = document.select("ul li:not(.gz):gt(0)");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
    /**
     *需求 4:获取 index.html 中 ul 中的 li 元素,并且排除当前元素 class="gz"的元素,并且索引号等于 0,并打印元素
     数据
     *API:Elements elements = document.select("ul li:not(.gz):gt(0)");
     */
    @Test
    public void test4() throws Exception{
        Elements elements = document.select("ul li:not(.gz):eq(2)");
        if(elements!=null && elements.size()>0){
            for (Element e : elements) {
                System.out.println(e.nodeName());
            }
        }
    }
}

你可能感兴趣的:(javaWeb)