欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Jsoup解析HTML实例及文档方法详解

程序员文章站 2024-02-15 09:23:34
解析和遍历一个html文档 如何解析一个html文档: 复制代码 代码如下:string html = "

解析和遍历一个html文档

如何解析一个html文档

复制代码 代码如下:

string html = "<html><head><title>first parse</title></head>"
  + "<body><p>parsed html into a doc.</p></body></html>";
document doc = jsoup.parse(html);

其解析器能够尽最大可能从你提供的html文档来创见一个干净的解析结果,无论html的格式是否完整。比如它可以处理:

1、没有关闭的标签 (比如: <p>lorem <p>ipsum parses to <p>lorem</p> <p>ipsum</p>)
2、隐式标签 (比如. 它可以自动将 <td>table data</td>包装成<table><tr><td>?)
3、创建可靠的文档结构(html标签包含head 和 body,在head只出现恰当的元素)

一个文档的对象模型

1、文档由多个elements和textnodes组成 (以及其它辅助nodes).
2、其继承结构如下:document继承element继承node. textnode继承 node.
3、一个element包含一个子节点集合,并拥有一个父element。他们还提供了一个唯一的子元素过滤列表。

从一个url加载一个document

存在问题
你需要从一个网站获取和解析一个html文档,并查找其中的相关数据。你可以使用下面解决方法:

解决方法
使用 jsoup.connect(string url)方法:

复制代码 代码如下:

document doc = jsoup.connect("//www.jb51.net/").get();
string title = doc.title();

说明
connect(string url) 方法创建一个新的 connection, 和 get() 取得和解析一个html文件。如果从该url获取html时发生错误,便会抛出 ioexception,应适当处理。

connection 接口还提供一个方法链来解决特殊请求,具体如下:

复制代码 代码如下:

document doc = jsoup.connect("//www.jb51.net")
  .data("query", "java")
  .useragent("mozilla")
  .cookie("auth", "token")
  .timeout(3000)
  .post();

这个方法只支持web urls (http和https 协议); 假如你需要从一个文件加载,可以使用parse(file in, string charsetname) 代替。

从一个文件加载一个文档

问题
在本机硬盘上有一个html文件,需要对它进行解析从中抽取数据或进行修改。

办法
可以使用静态 jsoup.parse(file in, string charsetname, string baseuri) 方法:

复制代码 代码如下:

file input = new file("/tmp/input.html");
document doc = jsoup.parse(input, "utf-8", "//www.jb51.net/");

说明
parse(file in, string charsetname, string baseuri) 这个方法用来加载和解析一个html文件。如在加载文件的时候发生错误,将抛出ioexception,应作适当处理。
baseuri 参数用于解决文件中urls是相对路径的问题。如果不需要可以传入一个空的字符串。
另外还有一个方法parse(file in, string charsetname) ,它使用文件的路径做为 baseuri。 这个方法适用于如果被解析文件位于网站的本地文件系统,且相关链接也指向该文件系统。


使用dom方法来遍历一个文档

问题
你有一个html文档要从中提取数据,并了解这个html文档的结构。

方法
将html解析成一个document之后,就可以使用类似于dom的方法进行操作。示例代码:

复制代码 代码如下:

file input = new file("/tmp/input.html");
document doc = jsoup.parse(input, "utf-8", "//www.jb51.net/");

element content = doc.getelementbyid("content");
elements links = content.getelementsbytag("a");
for (element link : links) {
  string linkhref = link.attr("href");
  string linktext = link.text();
}

说明
elements这个对象提供了一系列类似于dom的方法来查找元素,抽取并处理其中的数据。具体如下:
查找元素
getelementbyid(string id)
getelementsbytag(string tag)
getelementsbyclass(string classname)
getelementsbyattribute(string key) (and related methods)
element siblings: siblingelements(), firstelementsibling(), lastelementsibling();nextelementsibling(), previouselementsibling()
graph: parent(), children(), child(int index)

元素数据
attr(string key)获取属性attr(string key, string value)设置属性
attributes()获取所有属性
id(), classname() and classnames()
text()获取文本内容text(string value) 设置文本内容
html()获取元素内htmlhtml(string value)设置元素内的html内容
outerhtml()获取元素外html内容
data()获取数据内容(例如:script和style标签)
tag() and tagname()

操作html和文本
append(string html), prepend(string html)
appendtext(string text), prependtext(string text)
appendelement(string tagname), prependelement(string tagname)
html(string value)


使用选择器语法来查找元素
问题
你想使用类似于css或jquery的语法来查找和操作元素。

方法
可以使用element.select(string selector) 和 elements.select(string selector) 方法实现:

复制代码 代码如下:

file input = new file("/tmp/input.html");
document doc = jsoup.parse(input, "utf-8", "//www.jb51.net./");

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元素

说明
jsoup elements对象支持类似于css (或jquery)的选择器语法,来实现非常强大和灵活的查找功能。.
这个select 方法在document, element,或elements对象中都可以使用。且是上下文相关的,因此可实现指定元素的过滤,或者链式选择访问。
select方法将返回一个elements集合,并提供一组方法来抽取和处理结果。

selector选择器概述
tagname: 通过标签查找元素,比如:a
ns|tag: 通过标签在命名空间查找元素,比如:可以用 fb|name 语法来查找 <fb:name> 元素
#id: 通过id查找元素,比如:#logo
.class: 通过class名称查找元素,比如:.masthead
[attribute]: 利用属性查找元素,比如:[href]
[^attr]: 利用属性名前缀来查找元素,比如:可以用[^data-] 来查找带有html5 dataset属性的元素
[attr=value]: 利用属性值来查找元素,比如:[width=500]
[attr^=value], [attr$=value], [attr*=value]: 利用匹配属性值开头、结尾或包含属性值来查找元素,比如:[href*=/path/]
[attr~=regex]: 利用属性值匹配正则表达式来查找元素,比如: img[src~=(?i)\.(png|jpe?g)]
*: 这个符号将匹配所有元素

selector选择器组合使用
el#id: 元素+id,比如: div#logo
el.class: 元素+class,比如: div.masthead
el[attr]: 元素+class,比如: a[href]
任意组合,比如: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

伪选择器selectors
:lt(n): 查找哪些元素的同级索引值(它的位置在dom树中是相对于它的父节点)小于n,比如:td:lt(3) 表示小于三列的元素
:gt(n):查找哪些元素的同级索引值大于n,比如: div p:gt(2)表示哪些div中有包含2个以上的p元素
:eq(n): 查找哪些元素的同级索引值与n相等,比如:form input:eq(1)表示包含一个input标签的form元素
: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): 查找自身包含文本匹配指定正则表达式的元素
注意:上述伪选择器索引是从0开始的,也就是说第一个元素索引值为0,第二个元素index为1等
可以查看selector api参考来了解更详细的内容


从元素抽取属性,文本和html

问题
在解析获得一个document实例对象,并查找到一些元素之后,你希望取得在这些元素中的数据。

方法
要取得一个属性的值,可以使用node.attr(string key) 方法
对于一个元素中的文本,可以使用element.text()方法
对于要取得元素或属性中的html内容,可以使用element.html(), 或 node.outerhtml()方法
示例:

复制代码 代码如下:

string html = "<p>an <a href='//www.jb51.net/'><b>www.jb51.net</b></a> link.</p>";
document doc = jsoup.parse(html);//解析html字符串返回一个document实现
element link = doc.select("a").first();//查找第一个a元素

string text = doc.body().text(); // "an www.jb51.net link"//取得字符串中的文本
string linkhref = link.attr("href"); // "//www.jb51.net/"//取得链接地址
string linktext = link.text(); // "www.jb51.net""//取得链接地址中的文本

string linkouterh = link.outerhtml();
    // "<a href="//www.jb51.net"><b>www.jb51.net</b></a>"
string linkinnerh = link.html(); // "<b>www.jb51.net</b>"//取得链接内的html内容

说明
上述方法是元素数据访问的核心办法。此外还其它一些方法可以使用:

element.id()
element.tagname()
element.classname() and element.hasclass(string classname)
这些访问器方法都有相应的setter方法来更改数据.


示例程序: 获取所有链接
这个示例程序将展示如何从一个url获得一个页面。然后提取页面中的所有链接、图片和其它辅助内容。并检查urls和文本信息。
运行下面程序需要指定一个urls作为参数

复制代码 代码如下:

package org.jsoup.www.jb51.nets;

import org.jsoup.jsoup;
import org.jsoup.helper.validate;
import org.jsoup.nodes.document;
import org.jsoup.nodes.element;
import org.jsoup.select.elements;

import java.io.ioexception;

/**
 * www.jb51.net program to list links from a url.
 */
public class listlinks {
    public static void main(string[] args) throws ioexception {
        validate.istrue(args.length == 1, "usage: supply url to fetch");
        string url = args[0];
        print("fetching %s...", url);

        document doc = jsoup.connect(url).get();
        elements links = doc.select("a[href]");
        elements media = doc.select("[src]");
        elements imports = doc.select("link[href]");

        print("\nmedia: (%d)", media.size());
        for (element src : media) {
            if (src.tagname().equals("img"))
                print(" * %s: <%s> %sx%s (%s)",
                        src.tagname(), src.attr("abs:src"), src.attr("width"), src.attr("height"),
                        trim(src.attr("alt"), 20));
            else
                print(" * %s: <%s>", src.tagname(), src.attr("abs:src"));
        }

        print("\nimports: (%d)", imports.size());
        for (element link : imports) {
            print(" * %s <%s> (%s)", link.tagname(),link.attr("abs:href"), link.attr("rel"));
        }

        print("\nlinks: (%d)", links.size());
        for (element link : links) {
            print(" * a: <%s>  (%s)", link.attr("abs:href"), trim(link.text(), 35));
        }
    }

    private static void print(string msg, object... args) {
        system.out.println(string.format(msg, args));
    }

    private static string trim(string s, int width) {
        if (s.length() > width)
            return s.substring(0, width-1) + ".";
        else
            return s;
    }
}
org/jsoup/www.jb51.nets/listlinks.java