Jsoup使用
文章目录
- Jsoup使用
- Jsoup 是什么
- 开始使用
- 加载文档
- HTML字符串
- URL
- 文件
- Jsoup为何如此强大
- 网络请求
- cookie
- get post execute method
- URL
- Proxy
- data requestBody
- followRedirects
- userAgent
- ignoreContentType
- ignoreHttpErrors
- header headers
- referrer
- response request
- Document对象
- Node
- Element
- Document
- Jsoup实战
- 确认目标
- 获取css selector
- 编写代码
- 获取页面标题
- 获取整个页面的所有图片连接
- 获取排行榜列表
Jsoup 是什么
Jsoup是一款基于java语言的html解析器,可以直接对网页URL,文件,字符串文本进行解析,并且可对生成的DOM结构进行增删改查操作,官方包提供了dom及css 选择器的方式来进行解析,API十分简洁方便,对新手用户极好,并且由于Jsoup对网页请求,DOM解析有着很好的支持,常常是爬虫的不二首选
开始使用
使用之前需要先引用下maven依赖或者jar包,截至目前为止,最新的版本是 1.13.1 ,这里我们使用比较稳定的1.11.3版本
1 2 3 4 5 | <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.11.3</version> </dependency> |
需要下载jar包的小伙伴也可以直接打开页面 https://mvnrepository.com/artifact/org.jsoup/jsoup/1.11.3
点击jar 下载即可
加载文档
Jsoup提供了一个静态基础类Jsoup,可以通过这个类来进行文档加载,目前主要支持如下几种方式
HTML字符串
public static Document parse(String html)
1 2 3 4 5 6 7 8 | @Test public void html() throws IOException { Document document = Jsoup.parse("<html><body><p><span>111</span></p></body></html>"); Elements p = document.select("p span"); System.out.println(p.text()); } 111 |
URL
public static Connection connect(String url)
1 2 3 4 5 6 7 8 | @Test public void test() throws IOException { Document document = Jsoup.connect("https://gitee.com/").get(); String title = document.title(); System.out.println(title); } 码云 Gitee — 基于 Git 的代码托管和研发协作平台 |
文件
public static Document parse(File in, String charsetName) throws IOException
1 2 3 4 5 6 7 8 | @Test public void file() throws IOException { Document document = Jsoup.parse(new File("D:\\a.txt"),"utf-8"); Elements p = document.select("p span"); System.out.println(p.text()); } 111 |
Jsoup为何如此强大
Jsoup为何如此强大,关键在于Jsoup对常用的api做了很好的封装,并且通俗易懂,小白上手也很快,下面就主要介绍下常用的对象及API,
网络请求
jsoup封装了http请求所涉及的几乎所有api,在
cookie
1 2 3 | Connection cookie(String k, String v); Connection cookies(Map<String, String> cookieMap); |
支持添加kv形式的单个cookie,同时支持多个cookie的Map的添加,简单直接
get post execute method
1 2 3 4 5 6 7 | Document get() throws IOException; Document post() throws IOException; Connection.Response execute() throws IOException; Connection method(Method method); |
封装了常见的请求方式,execute请求默认为get请求
URL
1 2 3 | Connection url(URL var1); Connection url(String var1); |
支持多种url请求
Proxy
1 2 3 | Connection proxy(Proxy var1); Connection proxy(String var1, int var2); |
支持代理请求
data requestBody
1 2 3 4 5 6 7 8 9 10 11 12 13 | Connection data(String var1, String var2); Connection data(String var1, String var2, InputStream var3); Connection data(String var1, String var2, InputStream var3, String var4); Connection data(Collection<Connection.KeyVal> var1); Connection data(Map<String, String> var1); Connection data(String... var1); Connection requestBody(String body); |
支持各种各样的请求data入参
followRedirects
1 | Connection followRedirects(boolean var1); |
当当前请求返回状态码为302需要重定向时,是否自动重定向,默认为true即默认进行重定向请求
userAgent
1 | Connection userAgent(String userAgent); |
添加请求头部的UserAgent客户端信息
ignoreContentType
1 | Connection ignoreContentType(boolean ignoreContentType); |
是否忽略请求返回的数据类型,默认为false,当请求类型不支持时会抛出异常(Unhandled content type. Must be text/, application/xml, or application/+xml),设置为true则忽略
ignoreHttpErrors
1 | Connection ignoreHttpErrors(boolean ignoreHttpErrors); |
header headers
1 2 3 | Connection header(String name, String value); Connection headers(Map<String,String> headers); |
添加请求头部
referrer
1 | Connection referrer(String referrer); |
设置请求头referrer来源
response request
1 2 3 | Response response(); Request request(); |
获取当前请求的request response对象
Document对象
在上面加载文档后会生成一个Document对象,这个对象继承自Element对象和Node对象,
Node
Node是节点的抽象模型并且实现了Cloneable接口,抽象了节点的通用模型,对应的Document,Element,TextNode等为Node节点的具体实例
Element
Element是一个节点和节点属性及其子类集合的描述,最直观的表达就是他的内部属性表示,Tag表示当前HTML节点的标签描述,比如p,a,span,div等等这些标签,childNodes表示其内部子节点,Attributes表示当前HTML节点的属性合集 ,同时内部封装了常见的DOM增删改查操作,其中包括最常见的
1 2 3 4 5 6 7 8 9 10 11 12 13 | private static final List<Node> EMPTY_NODES = Collections.emptyList(); private static final Pattern classSplit = Pattern.compile("\\s+"); private static final String baseUriKey = Attributes.internalKey("baseUri"); private Tag tag; private WeakReference<List<Element>> shadowChildrenRef; // points to child elements shadowed from node children List<Node> childNodes; private Attributes attributes; |
Document
Document继承自Element,Document是一个特殊的Element,因为他表示整个DOM的根节点,上面加载文档返回的类型就是Document对象,Docuement中有一个很重要的对象parser,表示解析当前DOM树的Parse解析器
以下是document常用方法,更多方法可以参考Jsoup中文文档 https://www.open-open.com/jsoup/
- body(),获取body元素节点
- select(),强大的select选择器,支持通过css获取对应的节点元素信息
- getElementById(),通过ID获取元素节点
- attr(String),获取当前节点对应的属性信息
- attr(String,String),设置当前节点属性信息
- text(),获取当前节点内容信息
- text(String),设置当前节点内容信息
- outerHtml(),获取整个html节点信息
- children(),获取当前节点下的所有子节点
- className(),获取当前节点class名称
- …
Jsoup实战
确认目标
这里我们就以腾讯阅读为例子
获取css selector
分析它的dom结构,一顿F12操作后发现,主要信息是在一个class为rankListWrap的div 的 ul下面,class为
直接右键 ul ,选择copy -> copy selector,获取当前UL的dom css 选择器
我这边儿复制出来的是
body > div.pageCenter > div:nth-child(6) > div.rightBox.fr > div.rankListWrap > ul:nth-child(1)
编写代码
我们直接使用Jsoup解析url的方法connect进行请求,获取整体的dom信息
1 | Document document = Jsoup.connect("http://book.qq.com/").get(); |
获取页面标题
1 2 3 4 5 | String title = document.title(); System.out.println("title : "+ title); title : QQ阅读 - 腾讯文学 - 文字之美,感动心灵 |
获取整个页面的所有图片连接
图片连接都是基于img标签来展示的,我们可以直接通过css选择器来获取所有的img元素
1 | Elements imgs = document.select("img"); |
获取到所有的img元素后,我们需要获取每个img元素的src的值也就是最终的图片连接
1 | List<String> srcs = imgs.stream().map(element -> element.attr("src")).collect(Collectors.toList()); |
最终打印我们获取的所有图片连接
1 | srcs.forEach(System.out::println); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | http://img1.chuangshi.qq.com/book/p1/txwxLogo.jpg http://img1.chuangshi.qq.com/chuangshi/p1/code03.png //bossaudioandcomic-1252317822.image.myqcloud.com/activity/document/758e5004aa42f91d22f191122b6ae5ec.jpg //bossaudioandcomic-1252317822.image.myqcloud.com/activity/document/b3a3520112e70678e4a638a0257c0ea4.jpg //bossaudioandcomic-1252317822.image.myqcloud.com/activity/document/862f865fa574e0bc492332ea145e869d.jpg //bossaudioandcomic-1252317822.image.myqcloud.com/activity/document/235937bdfc1c35f62fce27e9367a05f3.jpg //bossaudioandcomic-1252317822.image.myqcloud.com/activity/document/a534924729a16f91053d94730e9cbe07.jpg //bossaudioandcomic-1252317822.image.myqcloud.com/activity/document/950076aefee4a1d5e3897eab8ae22110.jpg //wfqqreader-1252317822.image.myqcloud.com/cover/485/24180485/t5_24180485.jpg //wfqqreader-1252317822.image.myqcloud.com/cover/787/23451787/t5_23451787.jpg //wfqqreader-1252317822.image.myqcloud.com/cover/746/21526746/t5_21526746.jpg //wfqqreader-1252317822.image.myqcloud.com/cover/661/421661/t5_421661.jpg //wfqqreader-1252317822.image.myqcloud.com/cover/22/20307022/s_20307022.jpg //wfqqreader-1252317822.image.myqcloud.com/cover/412/23240412/s_23240412.jpg //wfqqreader-1252317822.image.myqcloud.com/cover/963/648963/s_648963.jpg .... ... .. . http://img1.chuangshi.qq.com/book/p1/footer_img6.png |
打印出来的部分图片信息的url是不完整的,缺少http协议,我们可以换一种写法
1 | List<String> srcs = imgs.stream().map(element -> element.attr("abs:src")).collect(Collectors.toList()); |
较上面的写法,我们多了一个
整体代码如下
1 2 3 4 5 6 7 | Document document = Jsoup.connect("http://book.qq.com/").get(); Elements imgs = document.select("img"); List<String> srcs = imgs.stream().map(element -> element.attr("abs:src")).collect(Collectors.toList()); srcs.forEach(System.out::println); |
简单几句就获取到了所有图片的连接信息,Jsoup还是很强大的
同样的如果我们需要获取到整个页面的a标签的href信息,可以直接修改如下即可
1 2 3 4 5 6 7 | Document document = Jsoup.connect("http://book.qq.com/").get(); Elements imgs = document.select("a"); List<String> links = imgs.stream().map(element -> element.attr("abs:href")).collect(Collectors.toList()); links.forEach(System.out::println); |
获取排行榜列表
回到正题,我们是要获取到人气榜单书籍及相关信息,第二步的时候我们已经获取到了他的css 选择器
body > div.pageCenter > div:nth-child(6) > div.rightBox.fr > div.rankListWrap > ul:nth-child(1)
上面的css选择器是获取到了对应ul,我们需要获取的其实是ul下面的li标签里面的东西,所以在上面的css选择器的后面 加一个
body > div.pageCenter > div:nth-child(6) > div.rightBox.fr > div.rankListWrap > ul:nth-child(1) li
我们需要获取 排行,书名,作者,分类,人气量,这几个关键指标
- 排名,在class为detailWrap的div下面span标签的内容,css选择器为
div.detailWrap span - 书名,h4标签下面的a标签内容,css选择器为
h4 > a ,其中> 表示直接下级元素 - 作者,p标签下的a标签内容,css选择器为
p > a - 分类,p标签下的a标签内容,css选择器为
p > a ,作者和分类是同一个css标签,所以可以公用 - 人气量,em标签内容,css选择器为
em
整体代码如下, 其中text方法是获取对应元素内的文本信息,select方法主要是用来获取对应元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | @Test public void read() throws IOException { Document document = Jsoup.connect("http://book.qq.com/").get(); Elements lis = document.select("body > div.pageCenter > div:nth-child(6) > div.rightBox.fr > div.rankListWrap > ul:nth-child(1) li"); for (Element li : lis) { String order = li.select("div.detailWrap span").text(); System.out.print(order+"\t"); String bookName= li.select("h4 > a").text(); System.out.print(bookName+"\t"); Elements nodes = li.select("p > a"); String author = nodes.get(0).text(); String type = nodes.get(1).text(); System.out.print(author+"\t"+type+"\t"); String em = li.select("em").text(); System.out.println(em); } } |
结果
1 2 3 4 5 6 7 8 9 10 | 1 邪王追妻 苏小暖 穿越奇情 7837331 2 神医弃女 MS芙子 东方玄幻 2819006 3 这个大佬画风不对 墨泠 时空穿梭 1071361 4 神医凰后 苏小暖 穿越奇情 1012406 5 快穿之炮灰女配逆袭记 很是矫情 时空穿梭 757821 6 电竞大神暗恋我 战七少 婚恋情缘 708821 7 云家小九超皮哒 水清竹 东方玄幻 660780 8 医妃惊世 顾染锦 穿越奇情 591343 9 锦绣农女种田忙 巅峰小雨 经商种田 589633 10 娱乐圈之女王在上 迷路的龙 娱乐明星 535095 |