爬虫系列-jsoup爬取网页

  • 概述
    • 解析和遍历文档
    • 文档的对象模型
  • 加载HTML数据
    • 从String解析文档
    • 从String中加载解析片段
    • 从URL加载文档
      • 描述
    • 从文件加载文档
      • 描述
  • 提取数据
    • 使用DOM方法导航文档
      • 描述
      • 寻找元素
      • 元素数据
      • 处理HTML和文本
    • 使用selector-syntax查找元素
      • 描述
      • 选择器概述
      • 选择器组合
      • 伪选择器
    • 从元素中提取属性,文本和HTML
      • 描述
    • 解析URL
      • 描述
  • 案例:列出链接
  • 修改数据
    • 修改属性值
      • 描述
    • 修改元素的HTML
      • 其他方法
    • 设置元素的文本内容
      • 扩展
  • 清理不受信任的HTML(以防止XSS)
    • 扩展

概述

解析和遍历文档

无论HTML是否格式正确,解析器都会尝试从您提供的HTML中创建一个干净的解析。它处理:

  • 未封闭的标签(例如<p>Lorem <p>Ipsum解析<p>Lorem</p> <p>Ipsum</p>
  • 隐式标签(例如裸体<td>Table data</td>被包裹成a <table><tr><td>...
  • 可靠地创建文档结构(html含有head和body,只有适当的头部内的元件)

文档的对象模型

  • 文档由Elements和TextNodes(以及其他几个misc节点组成)。
  • 继承关系为: Document extends Element extends Node, TextNode extends Node.
  • 元素包含子节点列表,并具有一个父元素。它们还仅提供子元素的筛选列表。

加载HTML数据

我们的HTML文档 可能来自用户输入,文件或来自Web。

从String解析文档

使用静态Jsoup.parse(String html)方法,或者Jsoup.parse(String html, String baseUri)如果页面来自Web,希望您获得绝对URL。例如:

String html = "<html><head><title>First parse</title></head>"+ "<body><p>Parsed HTML into a doc.</p></body></html>";
Document doc = Jsoup.parse(html);

该parse(String html, String baseUri)方法将输入HTML解析为新的Document。该base URI参数用于将相对URL解析为绝对URL,并应设置为从中获取文档的URL。如果这不适用,或者您知道HTML有base元素,则可以使用该parse(String html)方法。
只要传入一个非空字符串,就可以保证有一个成功的,合理的解析,一个包含(至少)a head和一个body元素的Document 。

获得Document后,您可以使用Document及其supers Element和中的相应方法获取数据Node。

从String中加载解析片段

您有一个要解析的正文HTML片段(例如,div包含几个p标记;而不是完整的HTML文档)。也许它是由用户提交评论或在CMS中编辑页面正文提供的。
使用该Jsoup.parseBodyFragment(String html)方法。:

String html = "<div><p>Lorem ipsum.</p>";
Document doc = Jsoup.parseBodyFragment(html);
Element body = doc.body();

该parseBodyFragment方法创建一个空shell文档,并将解析后的HTML插入该body元素中。如果您使用普通Jsoup.parse(String html)方法,通常会得到相同的结果,但明确将输入视为正文片段可确保将用户提供的任何bozo HTML解析为body元素。
该Document.body()方法检索文档body元素的元素子元素; 它相当于doc.getElementsByTag(“body”)。

从URL加载文档

您需要从Web获取并解析HTML文档,并在其中查找数据(屏幕抓取)。
使用Jsoup.connect(String url)方法:

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

描述

该connect(String url)方法创建一个新的Connection,并get()提取和解析HTML文件。如果在获取URL时发生错误,它将抛出一个IOException,您应该适当处理。

该Connection接口设计用于方法链接以构建特定请求:

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

此方法仅支持Web URL(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", "http://example.com/");

描述

该parse(File in, String charsetName, String baseUri)方法加载并解析HTML文件。如果在加载文件时发生错误,它将抛出一个IOException,你应该适当处理。

baseUri解析器使用该参数在<base href>找到元素之前解析文档中的相对URL 。如果您不关心这一点,则可以传递空字符串。

有一个姐妹方法parse(File in, String charsetName)使用文件的位置作为baseUri。如果您正在处理文件系统本地站点并且它指向的相对链接也在文件系统上,这将非常有用。

提取数据

使用DOM方法导航文档

您有一个要从中提取数据的HTML文档。您通常知道HTML文档的结构。

File input = new File("/tmp/input.html");
Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/");Element content = doc.getElementById("content");
Elements links = content.getElementsByTag("a");
for (Element link : links) {String linkHref = link.attr("href");String linkText = link.text();
}

描述

元素提供了一系列类似DOM的方法来查找元素,并提取和操作它们的数据。DOM getter是上下文的:在父文档上调用它们在文档下找到匹配的元素; 他们在一个子元素上调用了那个孩子下面的元素。通过这种方式,您可以了解所需的数据。

寻找元素

  • getElementById(String id)
  • getElementsByTag(String tag)
  • getElementsByClass(String className)
  • getElementsByAttribute(String key) (及相关方法)
  • 元素的兄弟姐妹:siblingElements(),firstElementSibling(),lastElementSibling(),nextElementSibling(),previousElementSibling()
  • 图:parent(),children(),child(int index)

元素数据

  • attr(String key)获取和attr(String key, String value)设置属性
  • attributes() 获得所有属性
  • id(),className()和classNames()
  • text()获取和text(String value)设置文本内容
  • html()获取和html(String value)设置内部HTML内容
  • outerHtml() 获取外部HTML值
  • data()获取数据内容(例如script和style标签)
  • tag() 和 tagName()

处理HTML和文本

  • append(String html), prepend(String html)
  • appendText(String text), prependText(String text)
  • appendElement(String tagName), prependElement(String tagName)
  • html(String value)

使用selector-syntax查找元素

您希望使用CSS或类似jquery的选择器语法来查找或操作元素。
使用Element.select(String selector)和Elements.select(String selector)方法:

File input = new File("/tmp/input.html");
Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/");Elements links = doc.select("a[href]"); // a with href
Elements pngs = doc.select("img[src$=.png]");// img with src ending .pngElement masthead = doc.select("div.masthead").first();// div with class=mastheadElements resultLinks = doc.select("h3.r > a"); // direct a after h3

描述

jsoup元素支持CSS(或jquery)之类的选择器语法来查找匹配元素,从而允许非常强大和健壮的查询。

该select方法在一个可用Document,Element或在Elements。它是上下文的,因此您可以通过从特定元素中进行选择或通过链接选择调用来进行过滤。

Select返回一个Elements列表(as Elements),它提供了一系列提取和操作结果的方法。

选择器概述

  • tagname:按标签查找元素,例如 a
  • ns|tag:在命名空间中按标记fb|name查找<fb:name>元素,例如查找元素
  • #id:按ID查找元素,例如 #logo
  • .class:按类名查找元素,例如 .masthead
  • [attribute]:具有属性的元素,例如 [href]
  • [attr]:具有属性名称前缀的[data-]元素,例如查找具有HTML5数据集属性的元素
  • [attr=value]:具有属性值的元素,例如[width=500](也是可引用的[data-name=‘launch sequence’])
  • [attr^=value],[attr$=value],[attr*=value]:用与启动属性,以结束,或包含所述的值,例如元素[href*=/path/]
  • [attr~=regex]:具有与正则表达式匹配的属性值的元素; 例如img[src~=(?i).(png|jpe?g)]
  • *:所有元素,例如 *

选择器组合

  • el#id:具有ID的元素,例如 div#logo
  • el.class:带有类的元素,例如 div.masthead
  • el[attr]:具有属性的元素,例如 a[href]
  • 任何组合,例如 a[href].highlight
  • ancestor child:从祖先下降的子元素,例如在类“body”的块下的任何位置.body p查找p元素
  • parent > child:直接从父级下降的子元素,例如div.content > p查找p元素; 并body > *找到body标签的直接子节点
  • siblingA + siblingB:找到兄弟B元素之后紧接着兄弟A,例如 div.head + div
  • siblingA ~ siblingX:找到兄弟A前面的兄弟X元素,例如 h1 ~ p
  • el, el, el:对多个选择器进行分组,找到与任何选择器匹配的唯一元素; 例如div.masthead, div.logo

伪选择器

  • :lt(n):找到其兄弟索引(即它在DOM树中相对于其父节点的位置)小于的元素n; 例如td:lt(3)
  • :gt(n):查找兄弟索引大于的元素n; 例如div p:gt(2)
  • :eq(n):查找兄弟索引等于的元素n; 例如form input:eq(1)
  • :has(selector):查找包含与选择器匹配的元素的元素; 例如div:has§
  • :not(selector):查找与选择器不匹配的元素; 例如div:not(.logo)
  • :contains(text):查找包含给定文本的元素。搜索不区分大小写; 例如p:contains(jsoup)
  • :containsOwn(text):查找直接包含给定文本的元素
  • :matches(regex):查找文本与指定正则表达式匹配的元素; 例如div:matches((?i)login)
  • :matchesOwn(regex):查找自己的文本与指定正则表达式匹配的元素
    注意,上面的索引伪选择器是基于0的,即第一个元素是索引0,第二个元素是1,等等
    有关Selector完整支持的列表和详细信息,请参阅API参考。

从元素中提取属性,文本和HTML

在解析文档并找到一些元素之后,您将需要获取这些元素中的数据。

  • 要获取属性的值,请使用该Node.attr(String key)方法
  • 对于元素(及其组合子元素)上的文本,请使用 Element.text()
  • 对于HTML,使用Element.html()或Node.outerHtml()适当
String html = "<p>An <a href='http://example.com/'><b>example</b></a> link.</p>";
Document doc = Jsoup.parse(html);
Element link = doc.select("a").first();String text = doc.body().text(); // "An example link"
String linkHref = link.attr("href"); // "http://example.com/"
String linkText = link.text(); // "example""String linkOuterH = link.outerHtml(); // "<a href="http://example.com"><b>example</b></a>"
String linkInnerH = link.html(); // "<b>example</b>"

描述

上述方法是元素数据访问方法的核心。还有其他:

  • Element.id()
  • Element.tagName()
  • Element.className() 和 Element.hasClass(String className)
  • 所有这些访问器方法都有相应的setter方法来更改数据。

解析URL

有一个包含相对URL的HTML文档,您需要将其解析为绝对URL。

  1. 确保base URI在解析文档时指定(在从URL加载时隐式),以及
  2. 使用abs:属性前缀解析属性的绝对URL:
Document doc = Jsoup.connect("http://jsoup.org").get();Element link = doc.select("a").first();
String relHref = link.attr("href"); // == "/"
String absHref = link.attr("abs:href"); // "http://jsoup.org/"

描述

在HTML元素中,URL通常是相对于文档的位置编写的:<a href="/download">...</a>。当您使用该Node.attr(String key)方法获取href属性时,它将按照源HTML中的指定返回。

如果要获取绝对URL,则会有一个属性键前缀abs:,该前缀将导致根据文档的基URI(原始位置)解析属性值:attr(“abs:href”)

对于此用例,在解析文档时指定基URI非常重要。

如果您不想使用abs:前缀,还有一个方法Node.absUrl(String key)可以执行相同的操作,但可以通过自然属性键进行访问。

案例:列出链接

此示例程序演示了如何从URL获取页面; 提取链接,图像和其他指针; 并检查他们的URL和文本。

指定要获取的URL作为程序的唯一参数。

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 {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));elseprint(" * %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) + ".";elsereturn s;}
}

修改数据

修改属性值

您有一个已解析的文档,您希望在将其保存到磁盘之前更新属性值,或者将其作为HTTP响应发送。
使用属性setter方法Element.attr(String key, String value),和Elements.attr(String key, String value)。

如果需要修改class元素的属性,请使用Element.addClass(String className)和Element.removeClass(String className)方法。

该Elements集合具有批量归属和类方法。例如,要为div中的rel="nofollow"每个a元素添加一个属性:
·doc.select(“div.comments a”).attr(“rel”, “nofollow”);·

描述

与其他方法一样Element,这些attr方法返回当前Element(或者Elements从select中处理集合时)。这允许方便的方法链接
doc.select("div.masthead").attr("title", "jsoup").addClass("round-box");

修改元素的HTML

使用HTML setter方法Element:

Element div = doc.select("div").first(); // <div></div>
div.html("<p>lorem ipsum</p>"); // <div><p>lorem ipsum</p></div>
div.prepend("<p>First</p>");
div.append("<p>Last</p>");
// now: <div><p>First</p><p>lorem ipsum</p><p>Last</p></div>Element span = doc.select("span").first(); // <span>One</span>
span.wrap("<li><a href='http://example.com/'></a></li>");
// now: <li><a href="http://example.com"><span>One</span></a></li>

其他方法

  • Element.html(String html) 清除元素中的任何现有内部HTML,并将其替换为已解析的HTML。
  • Element.prepend(String first)并分别Element.append(String last)将HTML添加到元素内部HTML的开头或结尾
  • Element.wrap(String around)围绕元素的外部 HTML 包装HTML 。
    您还可以使用Element.prependElement(String tag)和Element.appendElement(String tag)方法创建新元素,并将它们作为子元素插入到文档流中。

设置元素的文本内容

使用以下文本setter方法Element:

Element div = doc.select("div").first(); // <div></div>
div.text("five > four"); // <div>five &gt; four</div>
div.prepend("First ");
div.append(" Last");
// now: <div>First five &gt; four Last</div>

扩展

文本setter方法镜像HTML setter方法:

Element.text(String text) 清除元素中的任何现有内部HTML,并将其替换为提供的文本。
Element.prepend(String first)和Element.append(String last)添加文本节点到元素的内部HTML的开始或结束时,分别
文本应提供未编码:喜欢文字<,>等会为文字,而不是HTML处理。

清理不受信任的HTML(以防止XSS)

您希望允许不受信任的用户为您网站上的输出提供HTML(例如,作为评论提交)。您需要清理此HTML以避免跨站点脚本(XSS)攻击。
将jsoup HTML Cleaner与a指定的配置一起使用Whitelist。

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>

扩展

针对您网站的跨站点脚本攻击可能会毁了您的一天,更不用说您的用户了。许多站点通过不允许在用户提交的内容中使用HTML来避免XSS攻击:它们仅强制执行纯文本,或使用其他标记语法,如wiki-text或Markdown。这些对用户来说很少是最佳解决方案,因为它们会降低表现力,并迫使用户学习新语法。

更好的解决方案可能是使用富文本WYSIWYG编辑器(如CKEditor或TinyMCE)。这些输出HTML,并允许用户直观地工作。但是,它们的验证是在客户端完成的:您需要应用服务器端验证来清理输入并确保HTML可以安全地放置在您的站点上。否则,攻击者可以避免客户端Javascript验证并将不安全的HMTL直接注入您的站点

jsoup白名单清理程序通过解析输入HTML(在安全的沙盒环境中),然后遍历解析树并仅允许已知安全标记和属性(和值)进入清理后的输出来工作。

它不使用不适合此任务的正则表达式。

jsoup提供一系列Whitelist配置以满足大多数要求; 如有必要,可以对它们进行修改,但请注意。

清洁器是不仅用于避免XSS,而且在限制元件,用户可以提供的范围有用:您可以与文本行a,strong元素,但不是结构性div或table元件。

爬虫系列-jsoup爬取网页你需要了解的一切相关推荐

  1. 【java爬虫】jsoup爬取网页数据-搜索算法评测/竞品评测

    百度抽奖概率改4个小时频繁黑屏频繁弹出源码的前端FE T8李森:请云端高level的同学参加会议...对,我级别到了... 666666 业务背景:如何保证搜索算法的好坏?所以有了竞品评测,自己的AP ...

  2. Python爬虫系列之爬取微信公众号新闻数据

    Python爬虫系列之爬取微信公众号新闻数据 小程序爬虫接单.app爬虫接单.网页爬虫接单.接口定制.网站开发.小程序开发 > 点击这里联系我们 < 微信请扫描下方二维码 代码仅供学习交流 ...

  3. Python爬虫系列之爬取某奢侈品小程序店铺商品数据

    Python爬虫系列之爬取某奢侈品小程序店铺商品数据 小程序爬虫接单.app爬虫接单.网页爬虫接单.接口定制.网站开发.小程序开发> 点击这里联系我们 < 微信请扫描下方二维码 代码仅供学 ...

  4. Python爬虫系列之爬取某优选微信小程序全国店铺商品数据

    Python爬虫系列之爬取某优选微信小程序全国商品数据 小程序爬虫接单.app爬虫接单.网页爬虫接单.接口定制.网站开发.小程序开发 > 点击这里联系我们 < 微信请扫描下方二维码 代码仅 ...

  5. Python爬虫系列之爬取某社区团微信小程序店铺商品数据

    Python爬虫系列之爬取某社区团微信小程序店铺商品数据 如有问题QQ请> 点击这里联系我们 < 微信请扫描下方二维码 代码仅供学习交流,请勿用于非法用途 数据库仅用于去重使用,数据主要存 ...

  6. Python爬虫:Xpath爬取网页信息(附代码)

    Python爬虫:Xpath爬取网页信息(附代码) 上一次分享了使用Python简单爬取网页信息的方法.但是仅仅对于单一网页的信息爬取一般无法满足我们的数据需求.对于一般的数据需求,我们通常需要从一个 ...

  7. 如何使用PHP开发爬虫功能去爬取网页资讯

    如何使用PHP开发爬虫功能去爬取网页资讯 一.网页数据分析 A ) 爬取目标: 比如我们现在需要爬取网页https://brands.cnblogs.com/ 中资讯列表数据. 那我们现在应该怎么分析 ...

  8. java jsoup爬取动态网页_java通过Jsoup爬取网页(入门教程)

    一,导入依赖 org.jsoup jsoup 1.10.3 org.apache.httpcomponents httpclient 二,编写demo类 注意不要导错包了,是org.jsoup.nod ...

  9. Python实训day04am【爬虫介绍、爬取网页测试、Python第三方库】

    Python实训-15天-博客汇总表 目录 1.文本文件编程题 2.爬虫(Scrapy) 2.1.安装第三方库 2.2.爬取网页测试 2.2.1.样例1 2.2.2.样例2 3.PyCharm导入第三 ...

最新文章

  1. pytorch统计矩阵非0的个数_PyTorch常见的12坑
  2. 那些年,我们一起做过的性能优化
  3. Node.js Undocumented(2)
  4. ghelper失效_Ghelper账号+网易云音乐领黑胶会员35天
  5. C#:winform使用chart控件绘制折线图,时间轴可缩放
  6. 主仆模式的一点小理解
  7. 数据结构与算法python—13.堆及python实现与leetcode总结
  8. 一文弄懂数据挖掘的十大算法,数据挖掘算法原理讲解
  9. DBeaver初次使用教程(强大的数据库连接工具)
  10. 正则表达式匹配中文及符号、英文及符号数字空格换行符及常用正则表达式
  11. Excel Rate 函数的JavaScript 实现,等额本息计算反推利率
  12. 计算机主机配置科普,一秒看懂电脑配置,组装电脑不求人
  13. Java数据结构之二叉树及其源码实现
  14. Mobaxterm连接虚拟机中Linux
  15. Tomcat7.0源码分析——请求原理分析(上)
  16. 了解串口协议,及完成STM32的USART串口通讯程序,并用keil观察波形
  17. Windows10+Cuda10.0.130+Cudnn 10.0出现CUDA安装失败的情况
  18. 7-56 365次方
  19. 工业级参数8.4V-24V电压降压到5V或3.3V降压芯片
  20. vue 点击增大字号

热门文章

  1. linux实验:基于mykernel的一个简单的时间片轮转多道程序内核代码分析
  2. C语言求班级成绩案例教程
  3. BMV格式用什么软件打开
  4. 理解内存和文件系统缓存
  5. 怎么讲计算机屏幕录制,怎么在电脑上录屏?屏幕录制软件是什么?
  6. KGB SFX 脱壳
  7. 携win32api给大家拜个早年
  8. java 文件io操作_java文件IO操作。
  9. 深度学习项目实战——基于多模态场景监控系统
  10. FlashFXP使用