欢迎使用CSDN-markdown编辑器

来源:互联网 发布:pychram软件运行环境 编辑:程序博客网 时间:2024/06/14 22:57

Jsoup

by bcli


简介


用于解析HTML5文本的JAVA类。对于未封闭的HTML如<p>paragraph也可以正确处理。简单应用举例:

// 获得维基百科主页Document doc = Jsoup.connect("http://en.wikipedia.org/").get();// 获得id为mp-itn,中,<b>中的<a> (使用类CSS语法)Elements newsHeadlines = doc.select("#mp-itn b a");

在开头标有?的表示不能完全理解,存在疑惑。这篇文档完全根据jsoup官方文档翻译、整理而来原文档请看文章结尾的参考资料->jsoup官网,API请查看参考资料->jsoup API

安装


eclipse添加jsoup类

  1. 官网http://jsoup.org/download下载jar包
  2. 将jar包拷贝到一个易于管理的目录下
  3. 右键点击项目目录,选择Build Path->Configure Build Path->Add External JAR->选择jsoup JAR包
  4. 在java类中import org.jsoup.*就可以使用jsoup的所有类了

常用函数


Jsoup.parse(html)

解析DOM

// 定义DOM文本String html = "<html><head><title>First parse</title></head>" + "<body><p>Parsed HTML into a doc.</p></body></html>";// 解析DOM文本Document doc = Jsoup.parse(html);

Jsoup.parseBodyFragment(String html_body)

解析<body>中的的DOM,比如:

// 定义一个未闭合的DOM文本(无<head>)String html = "<div><p>Lorem ipsum.</p>";// 将文本按照body中的内容解析Document doc = Jsoup.parseBodyFragment(html);// 获得解析后的DOMElement body = doc.body();

这个函数等同于

// 定义一个完整的HTML DOMString html = "<html><head><title>TITLE</title></head><body><div><p>Lorem ipsum.</p></body></html>";// 解析此HTML DOMDocument doc = Jsoup.parse(html);// 获得此DOM的body部分doc.getElementsByTag("body");

Jsoup.connect(String url)

从URL获取DOM

Document doc = Jsoup.connect("http://example.com/").get();String title = doc.title();

可设置HTTP请求参数,比如method, userAgent等:

Document doc = Jsoup.connect("http://www.baidu.com")    .data("query", "Java")    .userAgent("Mozilla")    .cookie("auth", "token")    .timeout(3000)    .post();

Jsoup.parse(File in, String charsetName, String baseUri)

从文件中解析DOM

File input = new File("/tmp/input.html");// 读取文本,按照UTF-8解析Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/");// 获得id为content的元素Element content = doc.getElementById("content");// 在content中,获得所有tag为<a>的元素Elements links = content.getElementsByTag("a");for (Element link : links) {    // 对于每个tag为<a>的元素,获得其链接指向的URL    String linkHref = link.attr("href");    // 获得其链接文本    String linkText = link.text();}

CSS元素选择函数

使用Element.select(String selector)Elements.select(String selector)进行CSS选择,其中selector使用类CSS语法。如

File input = new File("/tmp/input.html");Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/");// 获得所有带有href属性的<a>Elements links = doc.select("a[href]");// 获得所有带有src属性,且src属性中含有.png的<img>Elements pngs = doc.select("img[src$=.png]");// 获得第一个,类为masthead的<div>Element masthead = doc.select("div.masthead").first();// 获得<h3>后面的<a>Elements resultLinks = doc.select("h3.r > a");

* 选择器
* 按TAG:select(“div”)选择所有div
* ? select(div|name)选择<div:name>
* 按ID:select("#container")选择id="container"
* 按类:select(".col")选择class="col"
* 按属性:select("a[href]")选择带href属性的<a>
* 按属性前缀:^=
* select("div[^data-]")选择带data-....属性的<div>
* select("div[class^=col-]")选择类为col-....<div>
* 按属性后缀:$=
* select("input[$ed]")选择带....ed属性的<input>
* select("img[img$=.png]")选择格式为png<img>
* 按属性等于:=
* select("div[width=500px]")选择带有width属性且width=500px<div>
* 按属性包含:*=
* select("a[href*=/upload/]")选择链接中含有/upload/<a>
* 按属性符合正则表达式:~=
* select("img[src~=(?i)\.(png|jpe?g)]")选择为png,jpg或jpeg格式的<img>
* 选择所有元素:*
* 选择器组合:
* div#logo:获得id=logo<div>
* div.masthead:获得class=masthead<div>
* a[href]:获得含有href属性的<a>
* a[href].active获得含有href属性和class=active<a>
* a[href]#nav.active获得含有href属性,id=nav,class=active<a>
* .conatiner p获得类为container的元素,的标签为<p>的子元素
* .container > p获得类为container的元素,的标签为<p>第一层子元素
* .container > *获得类为container的元素,的所有第一层子元素
* ? div.head + div 获得A 和 B(A和B互为同层元素且相邻)
* ? h1 ~ p 获得A ~ B的同层元素
* div.masthead,div.logo,...若使用逗号隔开各个条件,条件之间为关系,选择满足任意一个条件的元素

  • 伪选代码择器(注意index0开头)
    • td:lt(3):选择相对于父元素<tr>index小于3<td>元素
    • div p:gt(2):选择相对于父元素<div>,index大于2的<p>元素
    • form input:eq(1):选择相对于父元素<form>index等于1的<input>元素
    • div:has(p)获得含有<p><div>
    • div:not(.logo)获得类名不为logo<div>
    • p:contains(jsoup)获得含有jsoup<p>,不分大小写
    • ? p:containsOwn(jsoup)获得下一层含有jsoup<p>,不分大小写
    • ?div:matches((?i)login)获得符合正则表达式(?i)login<div>
    • ?div:matchesOwn((?i)login)获得下一层符合正则表达式(?i)login<div>

元素操作函数

  • 寻找元素

    • 按ID查找 getElementById(String id)
    • 按TAG查找 getElementsByTag(String tag)
    • 按类查找 getElementsByClass(String className)
    • 按属性查找 getElementsByAttribute(String key)
    • 查找同层元素

      • 比如下面的<li>是同层元素,又称sibling兄弟元素

        <ul>    <li> A </li>    <li> B </li></ul>
      • 获得所有同层元素siblingElements()

      • 获得第一个同层元素firstElementSibling()
      • 获得最后一个同层元素lastElementSibling()
      • 获得下一个同层元素nextElementSibling()
      • 获得上一个同层元素previousElementSibling()
    • 查找父元素或子元素:parent(), children(), child(int index)
  • 元素数据

    • 获得属性:attr(String key)
    • 设置属性:attr(String key, String value)
    • 获得所有属性:attributes()
    • 获得id:id()
    • 获得类名:className()
    • 批量获得类名:classNames()
    • 获得文本:text()
    • 设置文本:text(String value)
    • 获得HTML:html()
    • 设置HTML:html(String value)
    • 获得外层HTML:outerHtml()
    • 获得scriptstyle之类属性中的数据:data()
    • 获得tag:tag()
    • 获得tag名称(如div):tagName()
  • 复制HTML和文本

    • 前添加HTML:prepend(String html)
    • 前添加文本: prependText(String text)
    • 后添加HTML:append(String html)
    • 后添加HTML:appendText(String text)
    • 前添加元素: prependElement(String tagName)
    • 后添加元素: appendElement(String tagName)

获得值、文本和HTML

  • 获得属性值:Node.attr(String key)
  • 获得元素文本:Element.text()
  • 获得HTML:Element.html()
  • 获得元素id:Element.id()
  • 获得tag名:Element.tagName()
  • 获得类名:Element.className()
  • 是否是某个类:Element.hasClass(String className)

    // 定义HTML文本String html = "<p>An <a href='http://example.com/'><b>example</ b></a> link.</p>";// 解析DOMDocument doc = Jsoup.parse(html);// 获得第一个<a>Element link = doc.select("a").first();// 获得内容String text = doc.body().text(); // An example linkString linkHref = link.attr("href"); // http://example.com/String linkText = link.text(); // exampleString linkOuterH = link.outerHtml(); // <a href="http://example.com"><b>example</b></a>String linkInnerH = link.html(); // <b>example</b>

URL操作

有些情况下网站会使用相对URL,比如/img/profile.png。这时,如果你已经指定了域名(使用connect命令时jsoup会自动解析域名,使用file时需要手动指定域名),你就可以使用String absHref = link.attr("abs:href");来获得绝对路径的URL了,举例:

// 获得网站页面Document doc = Jsoup.connect("http://jsoup.org").get();// 获得第一个<a>Element link = doc.select("a").first();// 获得第一个<a>的链接String relHref = link.attr("href"); // 链接为相对链接: "/"String absHref = link.attr("abs:href"); // 使用abs:href转化为绝对链接://"http://jsoup.org/"

应用举例

程序

package org.jsoup.examples;// jsoup引用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;/** * Example program to list links from a URL.*/public class ListLinks {    public static void main(String[] args) throws IOException     {        // 接受用户URL输入(只接受1个参数)        Validate.isTrue(args.length == 1, "usage: supply url to fetch");        // 为URL赋值        String url = args[0];        // 打印正在获取页面        print("Fetching %s...", url);        // 按照URL获取页面        Document doc = Jsoup.connect(url).get();        // 获取所有含有href属性的<a>        Elements links = doc.select("a[href]");        // 获取所有含有src的多媒体元素(主要应为图片)        Elements media = doc.select("[src]");        // 获得所有含有href属性的link        Elements imports = doc.select("link[href]");        // 输出多媒体元素的个数        print("\nMedia: (%d)", media.size());        // 处理多媒体元素        for (Element src : media)        {            // 获得<img>标签            if (src.tagName().equals("img"))            {                // 输出<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            {                //输出非<img>多媒体标签                print(                        " * %s: <%s>",                         src.tagName(),                        src.attr("abs:src")                    );            }        }        // 显示引用CSS的个数        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;    }}

输出

Fetching http://news.ycombinator.com/...Media: (38)* img: <http://ycombinator.com/images/y18.gif> 18x18 ()* img: <http://ycombinator.com/images/s.gif> 10x1 ()* img: <http://ycombinator.com/images/grayarrow.gif> x ()* img: <http://ycombinator.com/images/s.gif> 0x10 ()* script: <http://www.co2stats.com/propres.php?s=1138>* img: <http://ycombinator.com/images/s.gif> 15x1 ()* img: <http://ycombinator.com/images/hnsearch.png> x ()* img: <http://ycombinator.com/images/s.gif> 25x1 ()* img: <http://mixpanel.com/site_media/images/mixpanel_partner_logo_borderless.gif> x (Analytics by Mixpan.)Imports: (2)* link <http://ycombinator.com/news.css> (stylesheet)* link <http://ycombinator.com/favicon.ico> (shortcut icon)Links: (141)* a: <http://ycombinator.com>  ()* a: <http://news.ycombinator.com/news>  (Hacker News)* a: <http://news.ycombinator.com/newest>  (new)* a: <http://news.ycombinator.com/newcomments>  (comments)* a: <http://news.ycombinator.com/leaders>  (leaders)* a: <http://news.ycombinator.com/jobs>  (jobs)* a: <http://news.ycombinator.com/submit>  (submit)* a: <http://news.ycombinator.com/x?fnid=JKhQjfU7gW>  (login)* a: <http://news.ycombinator.com/vote?for=1094578&dir=up&whence=%6e%65%77%73>  ()* a: <http://www.readwriteweb.com/archives/facebook_gets_faster_debuts_homegrown_php_compiler.php?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+readwriteweb+%28ReadWriteWeb%29&utm_content=Twitter>  (Facebook speeds up PHP)* a: <http://news.ycombinator.com/user?id=mcxx>  (mcxx)* a: <http://news.ycombinator.com/item?id=1094578>  (9 comments)* a: <http://news.ycombinator.com/vote?for=1094649&dir=up&whence=%6e%65%77%73>  ()* a: <http://groups.google.com/group/django-developers/msg/a65fbbc8effcd914>  ("Tough. Django produces XHTML.")* a: <http://news.ycombinator.com/user?id=andybak>  (andybak)* a: <http://news.ycombinator.com/item?id=1094649>  (3 comments)* a: <http://news.ycombinator.com/vote?for=1093927&dir=up&whence=%6e%65%77%73>  ()* a: <http://news.ycombinator.com/x?fnid=p2sdPLE7Ce>  (More)* a: <http://news.ycombinator.com/lists>  (Lists)* a: <http://news.ycombinator.com/rss>  (RSS)* a: <http://ycombinator.com/bookmarklet.html>  (Bookmarklet)* a: <http://ycombinator.com/newsguidelines.html>  (Guidelines)* a: <http://ycombinator.com/newsfaq.html>  (FAQ)* a: <http://ycombinator.com/newsnews.html>  (News News)* a: <http://news.ycombinator.com/item?id=363>  (Feature Requests)* a: <http://ycombinator.com>  (Y Combinator)* a: <http://ycombinator.com/w2010.html>  (Apply)* a: <http://ycombinator.com/lib.html>  (Library)* a: <http://www.webmynd.com/html/hackernews.html>  ()* a: <http://mixpanel.com/?from=yc>  ()

设置属性值

  • Element.attr(String key, String value)设置元素某一个属性的值
  • Element.addClass(String className)为元素添加一个类
  • Element.removeClass(String className)为元素删除一个类
  • 批量添加属性:doc.select("div.comments input").attr("value","someVal");
  • 因为attr返回修改后的该Element,所以可以多命令叠加如:doc.select("div.masthead").attr("title", "jsoup").addClass("round-box");

设置HTML

  • Element.html(String html)将元素内部的html替换为指定的html
  • Element.prepend(String first)在元素内部的html前面添加新的html
  • Element.append(String last)在元素内部的html结尾添加新的html
  • Element.wrap(String arond)在元素自身html外再包一层新的html
  • Element.prependElement(String tag)在元素内部的开头插入一个新的tag
  • Element.appendElement(String tag)在元素内部的结尾插入一个新的tag

举例:

// 选择第一个<div>// 假设得到: <div>Hello</div>Element div = doc.select("div").first();// 将第一个div中的html替换为<p>lorem ipsum</p>,得到// <div><p>lorem ipsum</p></div>div.html("<p>lorem ipsum</p>");// 在div的头尾插入新的内容div.prepend("<p>First</p>");div.append("<p>Last</p>");//得到: <div><p>First</p><p>lorem ipsum</p><p>Last</p></div>// 获得第一个<span>// 假设得到: <span>One</span>Element span = doc.select("span").first();// 在span外包裹新的内容span.wrap("<li><a href='http://example.com/'></a></li>");//生成: <li><a href="http://example.com"><span>One</span></a></li>

设置元素文本内容


Element.html()最大的不同在于,< >会被直接转化为文本而不是HTML元素

  • Element.text(String text) 将元素内部html改变为指定文本
  • Element.prepend(String first)在元素内部的html之前添加指定文本
  • Element.append(String last)在元素内部的html之后添加指定文本

举例:

// 选择第一个<div>// 假定获得: <div>Hello</div>Element div = doc.select("div").first();// 替换div中html为文本div.text("five > four"); // 获得: <div>five &gt; four</div>// 在div中首尾添加内容div.prepend("First ");div.append(" Last");// 获得// <div>First five &gt; four Last</div>

防御XSS

XSS = Cross Site Scripting跨站脚本攻击。大致上跨域攻击和数据库注入攻击(SQL Injection)都是在提交给服务器的内容中输入了代码。比如XSS攻击可能在表单中输入一段javascript,并在验证不严密的服务器中被存储到了数据库中,下一次用户读取这些数据的时候就会自动调用非法的javascript从而造成信息泄露等。而数据库注入攻击则是在提交的内容
中插入了SQL语句,检查不严的网站接受了这些语句并作为合法SQL的一部分对MYSQL执行,从而可能造成表被删除等后果。

防御XSS的方法:

  1. 使用加密的session来验证提交表单用户的身份
  2. 永远不相信客户端发送来的数据,对其进行严格检查
  3. 一些框架(比如PHP的CodeIgniter)可以使用框架自带的XSS过滤和数据库注入过滤函数

jsoup XSS防御:
使用jsoup.clean()函数,举例:

String unsafe = "<p><a href='http://example.com/' onclick='stealCookies()'>Link</a></p>";String safe = Jsoup.clean(unsafe, Whitelist.basic());// now: <p><a href="http://example.com/" rel="nofollow">Link</a></p>

参考资料

  • jsoup官网

    http://jsoup.org

  • jsoup API 列表

    http://jsoup.org/apidocs/


bcli 2016-1-21

0 0
原创粉丝点击