Jsoup学习笔记
阅读原文时间:2023年07月10日阅读:1

时间:2016-7-7 00:05

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

jsoup的主要功能如下:

从一个URL,文件或字符串中解析HTML; 

使用DOM或CSS选择器来查找、取出数据; 

可操作HTML元素、属性、文本; 

jsoup解析

Jsoup提供一系列的静态解析方法生成Document对象

static Document parse(File in, String charsetName)

static Document parse(File in, String charsetName, String baseUri)

static Document parse(InputStream in, String charsetName, String baseUri)

static Document parse(String html)

static Document parse(String html, String baseUri)   

static Document parse(URL url, int timeoutMillis)

static Document parseBodyFragment(String bodyHtml)

static Document parseBodyFragment(String bodyHtml, String baseUri) 

其中baseUri表示检索到的相对URL是相对于baseUriURL的 

其中charsetName表示字符集

Connection connect(String url) 根据给定的url(必须是http或https)来创建连接

Connection 提供一些方法来抓去网页内容

Connection cookie(String name, String value) 发送请求时放置cookie 

Connection data(Map data) 传递请求参数 

Connection data(String… keyvals) 传递请求参数

Document get() 以get方式发送请求并对返回结果进行解析

Document post()以post方式发送请求并对返回结果进行解析 

Connection userAgent(String userAgent) 

Connection header(String name, String value) 添加请求头

Connection referrer(String referrer) 设置请求来源

jsoup提供类似JS获取html元素:

getElementById(String id) 用id获得元素

getElementsByTag(String tag) 用标签获得元素

getElementsByClass(String className) 用class获得元素

getElementsByAttribute(String key)  用属性获得元素

同时还提供下面的方法提供获取兄弟节点:siblingElements(), firstElementSibling(), lastElementSibling();nextElementSibling(), previousElementSibling()

获得与设置元素的数据

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 

操作html元素:

append(String html), prepend(String html)

appendText(String text), prependText(String text)

appendElement(String tagName), prependElement(String tagName)

html(String value)

jsoup还提供了类似于JQuery方式的选择器

采用选择器来检索数据

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

ns|tag     使用命名空间的标签定位,例如 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)] 

以上是最基本的选择器语法,这些语法也可以组合起来使用

组合用法

el#id      定位id值某个元素,例如 a#logo ->

http://www.example.com").timeout(60000).get();

//File文件作为输入源

File input = new File("/tmp/input.html");

Document doc = Jsoup.parse(input, "UTF-8", "http://www.example.com/");

//String作为输入源

Document doc = Jsoup.parse(htmlStr);

和java script类似,Jsoup提供了下列的函数

getElementById(String id) 通过id获得元素

getElementsByTag(String tag) 通过标签获得元素

getElementsByClass(String className) 通过class获得元素

getElementsByAttribute(String key) 通过属性获得元素

同时还提供下面的方法提供获取兄弟节点:

siblingElements(), firstElementSibling(), lastElementSibling();nextElementSibling(), previousElementSibling()

用下面方法获得元素的数据: 

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

操作html提供了下面方法:

append(String html), prepend(String html)

appendText(String text), prependText(String text)

appendElement(String tagName), prependElement(String tagName)

html(String value)

========================================================================================== 

爬取爱帮网首页所有城市,并打印到控制台

import java.io.IOException;

import org.jsoup.*;

import org.jsoup.nodes.*;

import org.jsoup.select.*;

public class GetCity {

    public static void main(String[] args) throws Exception

    {

        try {

            //加载网页地址并链接网页地址

            Document doc = Jsoup.connect("http://www.aibang.com/cities-www").get();

//         System.out.println(doc);

            //获取ul标签里的所有元素

//         Elements tags = doc.getElementsByTag("ul");

            //筛选并获取第二组元素所有ul标签,索引值默认从0开始

//         Element element = tags.get(1);

//         Elements el = doc.select("ul").get(1).select("li p");

            Elements el = doc.select("ul li p");

            for(Element e : el)

            {

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

            }

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}

============================================================================================

package day01;

import java.io.*;

import org.jsoup.*;

import org.jsoup.nodes.*;

import org.jsoup.select.Elements;

/**

 * 2016年7月6日21:45:16 使用Jsoup解析HTML文件

 * 

 * @author WYC

 *

 */

public class JsoupDemo01 {

    public static void main(String[] args) {

        // 创建StringBuilder,存储从HTML中读取到的字符串

        StringBuilder sb = new StringBuilder();

        // 将文件读入内存,并打印

        BufferedReader br = null;

        try {

            // 创建HTML文件对象并与之关联

            File f = new File("G:\\Java\\eclipse workspace\\Jsoup\\Sample.html");

            // 创建输入流

            FileReader fr = new FileReader(f);

            // 创建输入流缓冲区

            br = new BufferedReader(fr);

            String line = "";

            // 判断读取到的字符串是否为null,如果不是,则继续读取

            while ((line = br.readLine()) != null) {

                // System.out.println(line);

                // 将读取到的一行数据追加到StringBuilder中并添加换行

                sb.append(line + "\n");

            }

        } catch (Exception ex) {

            ex.printStackTrace();

        } finally {

            try {

                br.close();

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

        // 打印获取到的HTML对象信息

        // System.out.prinltn(sb.toString());

        // 获取HTML文档的Document对象,将HTML转换为Document对象

        // 可以通过Document对象来操作HTML中的全部内容

        Document doc1 = Jsoup.parse(sb.toString());

        // 解析一个body片段

        Document doc2 = Jsoup.parseBodyFragment(sb.toString());

        // 该方法仅仅是获取body部分的代码

        // Document.body()方法能够获取文档body标签的对象,

        // 与doc.getElementById("body");相同

        Element body = doc2.body();

        // 打印获取到的body对象

        System.out.println(body);

        // 根据URL来获取一个HTMLDocument对象

        // Document doc3 = null;

        // try

        // {

        // //不能使用本地路径当做URL参数

        // doc3 = Jsoup.connect("www.baidu.com").get();

        // }

        // catch(Exception ex)

        // {

        // ex.printStackTrace();

        // }

        // 从本地文件加载一个文档

        // parse(File input,String charsetName, String baseUri);

        Document doc4 = null;

        File input = new File("G:\\Java\\eclipse workspace\\Jsoup");

        try {

            // 疑问:第三个参数(baseUri)是做什么的

            doc4 = Jsoup.parse(input, "utf-8", "aaa");

            // 另外还有一个方法:parse(File input, String charsetName)

            // 它使用文件的路径作为baseUri,

            // 这个方法适用于如果被解析文件位于网站的本地文件系统,

            // 且相关链接也指向该文件系统

        } catch (Exception ex) {

            ex.printStackTrace();

        }

        // 数据抽取

        // 使用DOM方法来遍历一个文档

        // 方法:将HTML文件解析成一个Document对象后,

        // 就可以使用类似于DOM的方法进行操作

        Document doc = null;

        Document doc5 = null;

        File f = new File("G:\\Java\\eclipse workspace\\Jsoup");

        try {

            doc5 = Jsoup.parse(f, "utf-8", "www");

        } catch (Exception ex) {

            ex.printStackTrace();

        }

        Element content = doc.getElementById("content");

        Elements links = content.getElementsByTag("a");

        // 遍历获取到的链接

        for (Element e : links) {

            String linkHref = e.attr("href");

            String linkText = e.text();

            // System.out.println(linkHref);

            // System.out.println(linkText);

        }

        // 操作HTML和文本

        // 在获取到的HTML文本的最后追加HTML对象

        doc.append("哈哈哈哈哈");

        // System.out.println("doc");

        // 在获取到的HTML文本的前面插入HTML对象

        // System.out.println("doc");

        // 追加文本

        // appendText(String text);

        // prependText(String text);

        // 追加Element对象

        // appendElement(String tagName)

        // prependElement(String tagName)

        // 给获取到的HTML对象设置新文本

        doc5.html("aaa");

        // System.out.println(doc5);

        // 使用选择器语法来查找元素

        // 使用类似于CSS或jQuery的语法来查找或操作元素

        // element.select(String selector) Elements.selectString selector)

        // Jsoup element对象支持类似于CSS或者jQuery的选择器语法,

        // 来实现非常强大和灵活的查找功能。

        // 这个select方法在Document、Element或者Elements对象中都可以使用

        // 且向下文相关,因此可以实现指定元素的过滤,或者链式选择访问

        // Select方法将返回一个Element集合,并提供一组方法来抽取和处理结果

        Document doc6 = null;

        File input2 = new File("G:\\Java\\eclipse workspace\\Jsoup");

        try {

            doc6 = Jsoup.parse(input2, "utf-8");

            // 获取带有href属性的a标签

            Elements links2 = doc6.select("a[href]");

            // 获取扩展名为.png的图片

            Elements pngs = doc6.select("img[src$=.png]");

            // 获取class等于masthead的div标签中的所有代码

            Element Header = doc.select("div.header").first();

            // 获取在h3元素之后的a标签

            Elements resultLinks = doc6.select("h3.r > a");

            for (Element element : links2) {

                // System.out.println(element);

            }

        } catch (Exception ex) {

            ex.printStackTrace();

        }

        /**

         * Selector选择器概述 01、tarname:通过标签查找元素,比如:a

         * 02、ns|tag:通过标签在命名空间查找元素,比如:可以用fb||name语法来查找元素

         * 03、#id:通过id查找元素,比如:#logo 04、[attribute]:利用属性查找元素,比如:[href]

         * 05、.class:通过class名称查找元素,比如:.masthead

         * 06、[^attr]:利用属性名前缀来查找元素,比如:可以用[^data-]来查找带有HTML5 Dataset属性的元素

         * 07、[attr=value]:利用属性值来查找元素,比如:[width=500]

         * 08、[attr^=value]、[attr$=value]、[attr*=value]:利用匹配属性值开头、
         * 结尾或者包含属性值来查找元素,比如:[href*=/path/]

         * 09、[attr^=value]:利用属性值匹配正则表达式来查找元素,比如:img[src~=(?i)\.(png|jpeg)

         * 10、*:这个符号匹配所有元素

         */

        /**

         * Selector选择器组合使用 01、el#id:元素+id,比如:div#logo

         * 02、el.class:元素+class,比如:div.masthead 03、el[attr]:元素[属性],比如:[href]

         * 04、任意组合:比如:a[href]/highlight 05、ancestor

         * child:查找某个元素下的子元素,比如:可以使用.body p,查找在body元素下的所有p元素 06、parent >

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

         * 查找body标签下的所有直接元素 07、siblingA + siblingB:查找在A元素之前第一个同级元素B,比如:div.head

         * + div 08、siblingA ~ SiblingX:查找A元素之前的同级X元素,比如:h1~p

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

         */

        /**

         * 伪选择器 Selectors

         * 01、lt(n):查找哪些元素的同级索引值(它的位置在DOM树种使相对于它的父节点)小于n,
         *     比如:td:lt(3)标识小于3列的元素

         * 02、gt(n):查找哪些元素的同级索引值大于n,比如:div p:gt(2)标识哪些div中包含2个以上的p元素

         * 03、eq(n):查找哪些元素的同级索引值与n相等,比如:form input:eq(1),表示含有一个input标签的form元素

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

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

         * logo的所有div列表

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

         * 07、containsOwn(text):查找直接包含给定文本的元素

         * 08、matches(regex):查找哪些元素的文本匹配指定的正则表达式,比如:div.matches((?i)login)

         * 09、matchesOwn(regex):查找自身包含文本匹配指定正则表达式的元素 注意:上述伪选择器索引是从0开始

         */

        // 从元素抽取属性、文本和HTML

        // 问题:在解析获得一个Document实例对象、并查找到一些元素后,

        // 你希望取得在这些元素中的数据,该如何操作?

        // 方法:

        // 1、要取得一个属性的值,可以使用Node.attr(String key)方法

        // 2、对于一个元素中的文本,可以使用Element.text()方法

        // 3、对于要取得元素或属性中的HTML内容,

        // 可以使用Element.html()或者Node.outerHtml()方法

        // 解析HTML字符串返回一个Document实例

        Document doc7 = Jsoup.parse(sb.toString());

        // 查找第一个a元素

        Element link = doc7.select("a").first();

        // System.out.println(link);

        // 取得字符串中的文本

        String text = doc7.body().text();

        // System.out.println(text);

        // 获取链接地址

        String linkHref = link.attr("href");

        // System.out.println(linkHref);

        // 取得链接地址中的文本

        String linkText = link.text();

        // System.out.println(linkText);

        String linkOuterH = link.outerHtml();

        // System.out.println(linkOuterH);

        // 获取链接内的HTML内容

        String linkInnerH = link.html();

        // System.out.println(linkInnerH);

        // 数据修改

        // 当解析一个Document之后可能想修改其中的某些属性值,

        // 然后再保存到磁盘或输出到前台页面

        // 方法:可以使用属性设置方法:Element.attr(String key,String

        // value)和Elements.attr(String key,String value)

        Document doc8 = Jsoup.parse(sb.toString());

        Element a = doc8.getElementById("a");

        // 为id=a的a标签添加href属性

        a.attr("href", "aaa");

        // System.out.println(doc8.select("a").first());

        // 例如需要修改一个元素的class属性,可以使用Element.addClass(String

        // className)和Element.removeClass(String className)方法

        a.addClass("aaa");

        // System.out.println(a.select("a").first());

        // Elements提供了批量操作元素属性的class的方法

        // 比如:要为div中的每一个a元素都添加一个rel="nofollow",可以使用如下方法

        // doc.select("div.comments a").attr("rel","nofollow");

        // 说明:与Element中的其他方法一样,

        // attr也是返回当前Element(或者在使用选择器时返回Elements集合),

        // 这样能够很方便使用方法链书写,比如:

        // doc.select("div.masthead").attr("title","jsoup").addClass(round-box");

        // 设置一个元素的HTML内容

        // 获取第一个div元素

        Element div = doc8.select("div").first();

        // 向div标签中插入元素数据

        div.html("

哈哈哈

");

        // 在div标签之前插入数据

        div.prepend("

哈哈哈哈哈

");

        // 在div标签之后插入数据

        div.append("

哈哈

");

        // 打印当前div信息

        // System.out.println("div");

        Element span = doc.select("span").first();

        // span.wrap("这是span标签");

        // System.out.println(span);

        /**

         * 说明: Element.html(String html): 这个方法将先清除元素中的HTML内容, 然后用传入的HTML代替原有HTML

         * Element.prepend(String first)和Element.append(String last)

         * Element.wrap(String around):对元素包裹一个外部HTML内容

         * 

         */

        // 设置元素的文本内容

        Element div2 = doc.select("div").first();

        div.text("five > four");

        div.append("First");

        div.prepend("Last");

        System.out.println(div);

        /**

         * 说明: 文本设置方法与HTML setter方法一致 Element.text(String

         * text)将先清除一个元素中的内部HTML内容, 然后用传入的文本进行替代 对于传入的文本如果有像

         * < > 这样的字符,将以文本形式进行处理,而非HTML。

         */

        /**

         * HTML清理 清理不受信任的HTML(来防止XSS攻击)

         * 

         * 问题:在做网站的时候,经常会提供用户评论的功能, 
         * 有些不怀好意的用户,会搞一些脚本到评论内容中, 而这些脚本可能会破坏整个页面的行为

         * 更严重的是获取一些重要信息,此时需要清理该HTML, 以避免跨站脚本攻击(XSS)

         * 

         * 方法: 使用jsoup HTML Cleaner方法进行清除, 但需要指定一个可配置的whitelist

         */

        /**

         * 说明

         * 

         * XSS又叫CSS(Cross Site Script),跨站脚本攻击,它指的是恶意攻击者往Web页面中插入恶意的HTML代码,

         * 当用户浏览到该页面时,嵌入该页面中的HTML代码会被执行,从而达到恶意攻击用户的特殊目的。

         * 

         * XSS属于被动式的攻击,因为其被动且不好利用,所以经常会忽略其危害性,

         * 所以我们经常只让用户输入纯文本的内容,但是这样用户体验性就比较差了。

         * 一个更好的解决方法就是使用一个富文本编辑器,WYSIWYG、CKEditor和TinyMCE,

         * 这些可以输出HTML并能够让用户可视化编辑,虽然他们可以在客户端进行校验,

         * 但是这样还不够安全,需要在服务器端进行校验并清除有害的HTML代码, 
         * 这样才能确保输入到你网站的HTML代码是安全的,否则,

         * 攻击者能够绕过客户端的JavaScript验证,并注入不安全的HTML代码 直接进入您的网站。

         * 

         * jsoup的whitelist清理器能够在服务器端对用户输入的HTML进行过滤,只输出一些安全的标签和属性

         * jsoup提供了一系列的whitelist基本配置,能满足大多数要求,但是如果有鼻炎,也可以进行修改, 不过要小心。

         * 

         * 这个cleaner非常好用,不仅可以避免XSS攻击,还可以限制用户可输入的标签范围。

         */

    }

}

====================================================================================
2016年7月7日23:03:31

小练习

package day02;

import java.io.*;

import org.jsoup.Jsoup;

import org.jsoup.nodes.Document;

import org.jsoup.nodes.Element;

import org.jsoup.select.Elements;

public class Test01 {

    public static void main(String[] args)

    {

        //获取Document对象

        Document doc = getDocument();

        fenge();

        //获取所有a元素

        Elements el = doc.select("a");

        print("所有a标签");

        print(el);

        fenge();

        //获取id=content的标签元素

        print("id=content的元素");

        Elements content = doc.select("#content");

        print(content);

        fenge();

        //获取class=header的元素

        print("class=header的元素");

        Elements header = doc.select(".header");

        print(header);

        fenge();

        //获取属性为href的元素

        print("属性为href的元素");

        Elements href = doc.select("[href]");

        print(href);

        fenge();

        //获取aa="aa"的元素

        print("aa=\"aa\"的元素");

        Elements aa = doc.select("[aa=aa]");

        print(aa);

        fenge();

        //获取href属性包含"/s"的元素

        print("href属性包含/s的元素");

        Elements href_s = doc.select("[href*=/s]");

        print(href_s);

        fenge();

        //获取href属性开头是/b的标签

        print("href属性开头是/b的元素");

        Elements href_b = doc.select("[href^=/b]");

        print(href_b);

        fenge();

        //获取href结尾是s/的标签

        print("href属性结尾是/s的元素");

        Elements href_s2 = doc.select("[href$=/s]");

        print(href_s2);

        fenge();

        //匹配所有元素

        print("使用*匹配获取到的所有元素");

        Elements all = doc.select("*");

        print(aa);

        fenge();

        //选择器的组合使用

        //获取a标签中id=a的元素

        print("a标签中id=a的元素");

        Elements a_ida = doc.select("a#a");

        print(a_ida);

        fenge();

        //获取a标签中class=aa的元素

        print("a标签中class=aa的元素");

        Elements a_classaa = doc.select("a.aa");

        print(a_classaa);

        fenge();

        //获取a标签中包含id的元素

        print("a标签中包含id的元素");

        Elements aid = doc.select("a[id]");

        print(aid);

        fenge();

        //获取a标签中包含id且class=aa的元素

        print("a标签中包含id且class=aa的元素");

        Elements a_id_class = doc.select("a[id].aa");

        print(a_id_class);

        fenge();

        //查找a标签下的p标签

        print("a标签下的p标签");

        Elements a_p = doc.select("a p");

        print(a_p);

        fenge();

        //查找a标签下的直接子标签p

        print("a标签下的直接子标签p");

        Elements ap = doc.select("a > p");

        print(ap);

        fenge();

        //siblingA + siblingB

        //查找在A元素之前第一个同级元素B

        print("查找a.aa标签之前的第一个div");

        Elements a_div = doc.select("a.aa+div");

        print(a_div);

        fenge();

        //查找a.aa,div#div

        print("a.aa,div#div");

        Elements adiv = doc.select("a.aa,div.div");

        print(adiv);

        fenge();

        //查找索引值小于1的a元素

        print("索引值小于1的a元素");

        Elements a_1 = doc.select("a:lt(1)");

        print(a_1);

        fenge();

        //查找同级索引值大于2的a标签

        print("索引值大于2的a标签");

        Elements a_2 = doc.select("a:gt(2)");

        print(a_2);

        fenge();

        //查找同级索引值小于1的a标签

        print("索引值等于1的a标签");

        Elements a_3 = doc.select("a:eq(1)");

        print(a_3);

        fenge();

        //查找包含p标签的a标签

        print("包含p标签的a标签");

        Elements pa = doc.select("a:has(p)");

        print(pa);

        fenge();

        //查找不包含class=aa的a标签

        print("不包含class=aa的a标签");

        Elements aaa = doc.select("a:not(.aa)");

        print(aaa);

        fenge();

        //查找包含News文本的a标签

        print("包含News的a标签");

        Elements anews = doc.select("a:contains(news)");

        print(anews);

        fenge();

        //查找直接包含给定文本的a标签

        print("直接包含News的a标签");

        Elements aNews = doc.select("a:containsOwn(News)");

        print(aNews);

        fenge();

    }

    //获取Html对象

    private static Document getDocument()

    {

        try {

            return Jsoup.parse(new File("G:/爱帮网 - 电子地图,公交查询,打折·优惠券,城市黄页.html"),"utf-8");

        } catch (IOException e) {

            e.printStackTrace();

        }

        return null;

    }

    private static void fenge()

    {

        System.out.println("=============================分隔符=============================");

    }

    //普通输出

    private static void print(Object o)

    {

        System.out.println(o + ":\n");

    }

    //遍历元素

    private static void print(Elements el)

    {

        for(Element e : el)

        {

            System.out.println(e);

        }

    }

    //输出元素

    private static void print(Element e)

    {

        System.out.println(e);

    }

}