文章目录
Jsoup简介
- Jsoup是一种Java 的HTML(html也是XML文档)解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套易于操作的API,可通过DOM,CSS以及类似于jQuery选择器的操作方法来取出和操作数据。使用jsoup就可以解析HTML。
- Jsoup使用的是DOM解析方式,把整个HTML文档(XML文档)加载到内存中形成一棵DOM树,得到文档的Document对象。HTML里的标签,会转换成Element对象。
Jsoup的基本使用步骤
1.引入依赖
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.2</version>
</dependency>
2.解析HTML,得到文档的Document对象
- 读取字符串,得到Document:
Document document = Jsoup.parse(String html);
- 读取文件,得到Document:
Document document = Jsoup.parse(File file, String charset);
- 读取url,得到Document:
Document document = Jsoup.connect(String url).get();
//Jsoup获取Document的方式
public class JsoupDocument {
//读取字符串,得到Document
@Test
public void test1(){
String html="\n" +
"<!DOCTYPE html>\n" +
"<html>\n" +
"<head>\n" +
" <meta charset=\"utf-8\">\n" +
" <title>测试</title>\n" +
"</head>\n" +
"<body>\n" +
"<!-- 职位列表 -->\n" +
"<div class=\"s_position_list \" id=\"s_position_list\">\n" +
" <ul class=\"item_con_list\">\n" +
" <li>\n" +
" <div class=\"list_item_top\">\n" +
" <div class=\"position\">\n" +
" <div class=\"p_top\">\n" +
" <a class=\"position_link\" href=\"\">\n" +
" <!-- 工作地点 -->\n" +
" <h3>高级Java开发工程师(上海、深圳、新加坡)</h3>\n" +
" <span class=\"add\">[<em>上海·浦东新区</em>]</span>\n" +
" </a>\n" +
" <span class=\"format-time\">2020-02-26</span>\n" +
" </div>\n" +
" <div class=\"p_bot\">\n" +
" <div class=\"li_b_l\">\n" +
" <span class=\"money\">25k-50k</span>\n" +
" <!-- 工作经验及学历要求 -->\n" +
" 经验3-5年 / 本科\n" +
" </div>\n" +
" </div>\n" +
" </div>\n" +
" <div class=\"company\">\n" +
" <div class=\"company_name\">\n" +
" <!-- 公司名称 -->\n" +
" <a href=\"\" >蚂蚁金服集团</a>\n" +
" </div>\n" +
" <div class=\"industry\">\n" +
" <!-- 行业领域 融资阶段 公司规模-->\n" +
" 金融,移动互联网 / B轮 / 2000人以上\n" +
" </div>\n" +
" </div>\n" +
" <div class=\"com_logo\">\n" +
" <a href=\"\">\n" +
" <!-- 图标logo -->\n" +
" <img src=\"//www.lgstatic.com/thumbnail_120x120/i/image/M00/1F/54/CgpFT1kRuMmASL74AAAg3WZnNI005.jpeg\" alt=\"蚂蚁金服集团\"\n" +
" width=\"60\" height=\"60\">\n" +
" </a>\n" +
" </div>\n" +
" </div>\n" +
" <div class=\"list_item_bot\">\n" +
" <div class=\"li_b_l\">\n" +
" <!-- 职位描述 -->\n" +
" <span>互联网金融</span>\n" +
" <span>后端</span>\n" +
" <span>分布式</span>\n" +
" </div>\n" +
" <!-- 福利 -->\n" +
" <div class=\"li_b_r\">“全球化视野”</div>\n" +
" </div>\n" +
" </li>\n" +
" </ul>\n" +
"\n" +
"</body>\n" +
"</html>";
Document document = Jsoup.parse(html);
System.out.println(document);
}
//读取文件,得到Document
@Test
public void test2() throws IOException {
String path = this.getClass().getClassLoader().getResource("test.html").getPath();
Document document = Jsoup.parse(new File(path),"UTF-8");
System.out.println(document);
}
//读取url,得到Document
@Test
public void test3() throws IOException {
Document document = Jsoup.connect("https://blog.csdn.net/qq_45615417").get();
System.out.println(document);
}
}
test.html(要解析的html文档):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<!-- 职位列表 -->
<div class="s_position_list " id="s_position_list">
<ul class="item_con_list">
<li>
<div class="list_item_top">
<div class="position">
<div class="p_top">
<a class="position_link" href="">
<!--职位-->
<h3>高级Java开发工程师(上海、深圳、新加坡)</h3>
<!-- 工作地点 -->
<span class="add">[<em>上海·浦东新区</em>]</span>
</a>
<span class="format-time">2020-02-26</span>
</div>
<div class="p_bot">
<div class="li_b_l">
<span class="money">25k-50k</span>
<!-- 工作经验及学历要求 -->
经验3-5年 / 本科
</div>
</div>
</div>
<div class="company">
<div class="company_name">
<!-- 公司名称 -->
<a href="" >蚂蚁金服集团</a>
</div>
<div class="industry">
<!-- 行业领域 融资阶段 公司规模-->
金融,移动互联网 / B轮 / 2000人以上
</div>
</div>
<div class="com_logo">
<a href="">
<!-- 图标logo -->
<img src="//www.lgstatic.com/thumbnail_120x120/i/image/M00/1F/54/CgpFT1kRuMmASL74AAAg3WZnNI005.jpeg" alt="蚂蚁金服集团"
width="60" height="60">
</a>
</div>
</div>
<div class="list_item_bot">
<div class="li_b_l">
<!-- 职位描述 -->
<span>互联网金融</span>
<span>后端</span>
<span>分布式</span>
</div>
<!-- 福利 -->
<div class="li_b_r">“全球化视野”</div>
</div>
</li>
</ul>
</body>
</html>
3.从Document里找到标签Element对象
获取Element对象的两种方式
①使用类似js的方式
- 根据id找到Element对象:
Element element = document.getElementById(String id)
- 根据标签找到Element对象:
Elements elements = document.getElementsByTag(String tagName);
- 根据类名找到Element对象:
Elements elements = document.getElementsByClass(String className);
- 根据属性找到Element对象:
Elements elements = document.getElementsByAttribute(String attrName);
- 获取当前元素的父节点对象:
Element parentElement = element.parent();
- 获取当前元素的子元素列表:
Elements elements = element.children();
- Element是标签转换成的一个对象。
- Elements本质是
ArrayList<Element>
,是一个Element的集合。
//Jsoup获取Element标签
public class JsoupElement {
private Document document;
@Before
public void init() throws IOException {
String path = this.getClass().getClassLoader().getResource("test.html").getPath();
document = Jsoup.parse(new File(path),"UTF-8");
}
//使用类似js的方法获取Element标签
@Test
public void testJS1(){
//查找id为s_position_list的元素
Element element = document.getElementById("s_position_list");
System.out.println(element);
}
@Test
public void testJS2(){
//查找所有的span标签
Elements elements = document.getElementsByTag("span");
/*输出结果:
<span class="add">[<em>上海·浦东新区</em>]</span>
<span class="format-time">2020-02-26</span>
<span class="money">25k-50k</span>
<span>互联网金融</span>
<span>后端</span>
<span>分布式</span>
*/
//查询所有类名为company的元素
elements = document.getElementsByClass("company");
/*
<div class="company">
<div class="company_name">
<!-- 公司名称 -->
<a href="">蚂蚁金服集团</a>
</div>
<div class="industry">
<!-- 行业领域 融资阶段 公司规模-->
金融,移动互联网 / B轮 / 2000人以上
</div>
</div>
*/
//查找所有包含href属性的元素
elements = document.getElementsByAttribute("href");
/*
<a class="position_link" href="">
<h3>高级Java开发工程师(上海、深圳、新加坡)</h3>
<span class="add">[<em>上海·浦东新区</em>]</span>
</a>
<a href="">蚂蚁金服集团</a>
<a href="">
<img src="//www.lgstatic.com/thumbnail_120x120/i/image/M00/1F/54/CgpFT1kRuMmASL74AAAg3WZnNI005.jpeg" alt="蚂蚁金服集团" width="60" height="60">
</a>
*/
for (Element element : elements) {
System.out.println(element);
}
}
}
②使用类似jQuery选择器的方式
常用选择器
div.cls
:获取类名为cls的div元素:has(selector)
:获取包含有selector结果的元素。比如:li:has(a)
获取文档中有a元素的li元素:not(selector)
:包含有selector选择的结果不要。比如:li:not(a)
获取文档中没有a元素的li元素
Document对执行选择器的方法
Elements elements = document.select(String cssQuery);
Elements elements = element.select(String cssQuery);
Elements elementsResult = elements.select(String cssQuery);
//cssQuery:选择器
//Document对象使用此方法:从整个html文档里查找
//Element对象使用此方法:从该Element标签内部查找
//Elements对象使用此方法:从该Elements标签内部查找
代码示例:
//Jsoup获取Element标签
public class JsoupElement {
private Document document;
@Before
public void init() throws IOException {
String path = this.getClass().getClassLoader().getResource("test.html").getPath();
document = Jsoup.parse(new File(path),"UTF-8");
}
//使用类似JQ选择器方法获取Element标签
@Test
public void testJQ1(){
//通过标签选择器的方式获取Element对象
Elements elements = document.select("#s_position_list");
System.out.println(elements);
}
@Test
public void testJQ2(){
//标签选择器查找span元素
Elements elements = document.select("span");
/*输出结果:
<span class="add">[<em>上海·浦东新区</em>]</span>
<span class="format-time">2020-02-26</span>
<span class="money">25k-50k</span>
<span>互联网金融</span>
<span>后端</span>
<span>分布式</span>
*/
//组合选择器查找类名为li_b_l的div元素
elements = document.select("div.li_b_l");
/*
<div class="li_b_l">
<span class="money">25k-50k</span>
经验3-5年 / 本科
</div>
<div class="li_b_l">
<span>互联网金融</span>
<span>后端</span>
<span>分布式</span>
</div>
*/
//获取role属性值为listbox的div元素
elements = document.select("div[class='list_item_bot']");
/*
<div class="list_item_bot">
<div class="li_b_l">
<span>互联网金融</span>
<span>后端</span>
<span>分布式</span>
</div>
<div class="li_b_r">
“全球化视野”
</div>
</div>
*/
//获取索引小于1的li元素
elements = document.select("li:lt(1)");//注意:这个找的是整个文档每一部分出现li元素的第一个
//扩展:这个方法找的才是整个文档的第一个li元素
elements = document.select("li");
elements.get(0);
for (Element element : elements) {
System.out.println(element);
}
}
}
4.从Element上获取数据
- 获取标签体:
html()
- 获取标签体里文本:
text()
- 获取属性值:
attr(String attrName)
//Jsoup获取标签上的数据
public class JsoupData {
private Document document;
@Before
public void init() throws IOException {
String path = this.getClass().getClassLoader().getResource("test.html").getPath();
document = Jsoup.parse(new File(path), "UTF-8");
}
@Test
public void test1(){
//获取类名为company_name的元素
Elements elements = document.select(".company_name");
//获取标签体内容
String html = elements.html();
System.out.println(html);
/*
<!-- 公司名称 -->
<a href="">蚂蚁金服集团</a>
*/
//获取标签体文本内容
String text = elements.text();
System.out.println(text);
/*
蚂蚁金服集团
*/
//获取类名为com_logo的后代元素img的placeholder属性值
//1.使用层级选择器,获取类名为com_logo的后代元素img
elements = document.select(".com_logo img");
System.out.println(elements);
/*
<img src="//www.lgstatic.com/thumbnail_120x120/i/image/M00/1F/54/CgpFT1kRuMmASL74AAAg3WZnNI005.jpeg" alt="蚂蚁金服集团" width="60" height="60">
*/
//2.获取img的placeholder属性值
String src = elements.attr("src");
System.out.println(src);
/*
//www.lgstatic.com/thumbnail_120x120/i/image/M00/1F/54/CgpFT1kRuMmASL74AAAg3WZnNI005.jpeg
*/
}
}
基于Jsoup的拓展——jsoupXPath的使用
- jsoupXPath:使用xpath解析HTML的解析器,html的DOM树借助jsoup生成。
- XPath:使用路径表达式来选取HTML文档中的元素节点或属性节点。
常用的XPath表达式
XPath表达式:用于选取HTML文档中节点的表达式字符串。
获取XML文档节点元素一共有如下4种XPath语法方式:
- 绝对路径表达式方式:以
/
开头,一级一级描述标签的层级路径,不可以跨层级.。
/body/ul/li: 查找html里根标签下body,body下的ul,ul下的li
注:开头的“/”代表HTML文档根元素,所以在绝对路径中不可以写根元素路径。
- 全文搜索路径表达式方式:以
//
开头
//li:全文搜索所有的li标签
- 条件筛选方式:以
//
开头,根据条件过滤判断进行选取节点。
//a[@id='rname']:查找id属性值为rname的a元素
//a[@id='rname']/@href:查找id属性值为rname的a元素,获取a元素的href属性
//a[@id='rname']/text():查找id属性值为rname的a元素,获取元素里自有的文本
自有的文本:该标签的文本,不包含该标签子标签的文本。
//a[@id='rname']/allText():查找id属性值为rname的a元素,获取元素里所有的文本
所有的文本:该标签文本与其子标签文本都会获取。
//a[@id='rname']/html():查找id属性值为rname的a元素,获取元素的标签体
jsoupXPath使用步骤
1. jsoupXPath核心类JXDocument和执行Xpath表达式字符串的API方法介绍
JXDocument是Document的包装类,额外增加了XPath表达式的支持
-
构造方法:
JXDocument jxDocument = new JXDocument(Document document)
-
执行Xpath表达式字符串常用方法:
List<Object> list = jxDocument.sel(String xpath)
2.使用步骤
①引入依赖
<dependency>
<groupId>cn.wanghaomiao</groupId>
<artifactId>JsoupXpath</artifactId>
<version>2.2</version>
</dependency>
②创建JXDocument对象
③使用sel()方法,执行xpath表达式,获取结果
示例:
public class TestJsoupXpath {
@Test
public void testJsoupXpath() throws IOException {
String path = this.getClass().getClassLoader().getResource("test.html").getPath();
Document document = Jsoup.parse(new File(path), "utf-8");
//创建JXDocument对象
JXDocument jxDocument = new JXDocument(document);
//使用sel()方法,得到结果
//绝对路径表达式方式,获取html里 /body/div/ul/li/div/div/a/h3
List<Object> objects = jxDocument.sel("/body/div/ul/li/div/div/div/a/h3");
/*输出结果:
<h3>高级Java开发工程师(上海、深圳、新加坡)</h3>
*/
//全文搜索路径表达式方式,获取所有的img标签
objects = jxDocument.sel("//img");
/*
<img src="//www.lgstatic.com/thumbnail_120x120/i/image/M00/1F/54/CgpFT1kRuMmASL74AAAg3WZnNI005.jpeg" alt="蚂蚁金服集团" width="60" height="60">
*/
//条件筛选方式:获取class属性值是industry的div元素
objects = jxDocument.sel("//div[@class='industry']");
/*
<div class="industry">
<!-- 行业领域 融资阶段 公司规模-->
金融,移动互联网 / B轮 / 2000人以上
</div>
*/
//条件筛选方式:获取class属性值是li_b_l的div元素的标签体文本(自有文本)
objects = jxDocument.sel("//div[@class='li_b_l']/text()");
/*
经验3-5年 / 本科
*/
//条件筛选方式:获取class属性值是li_b_l的div元素的标签体文本(所有文本)
objects = jxDocument.sel("//div[@class='li_b_l']/allText()");
/*
25k-50k
经验3-5年 / 本科
互联网金融 后端 分布式
*/
//条件筛选方式:获取class属性值是li_b_l的div元素的标签体
objects = jxDocument.sel("//div[@class='li_b_l']/html()");
/*
<span class="money">25k-50k</span>
<!-- 工作经验及学历要求 -->
经验3-5年 / 本科
<!-- 职位描述 -->
<span>互联网金融</span>
<span>后端</span>
<span>分布式</span>
*/
for (Object object : objects) {
if (object instanceof Element) {
Element element = (Element) object;
System.out.println(element);
}else{
System.out.println(object);
}
}
}
}
test.html(要解析HTML文档)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>测试</title>
</head>
<body>
<!-- 职位列表 -->
<div class="s_position_list " id="s_position_list">
<ul class="item_con_list">
<li>
<div class="list_item_top">
<div class="position">
<div class="p_top">
<a class="position_link" href="">
<!--职位-->
<h3>高级Java开发工程师(上海、深圳、新加坡)</h3>
<!-- 工作地点 -->
<span class="add">[<em>上海·浦东新区</em>]</span>
</a>
<span class="format-time">2020-02-26</span>
</div>
<div class="p_bot">
<div class="li_b_l">
<span class="money">25k-50k</span>
<!-- 工作经验及学历要求 -->
经验3-5年 / 本科
</div>
</div>
</div>
<div class="company">
<div class="company_name">
<!-- 公司名称 -->
<a href="" >蚂蚁金服集团</a>
</div>
<div class="industry">
<!-- 行业领域 融资阶段 公司规模-->
金融,移动互联网 / B轮 / 2000人以上
</div>
</div>
<div class="com_logo">
<a href="">
<!-- 图标logo -->
<img src="//www.lgstatic.com/thumbnail_120x120/i/image/M00/1F/54/CgpFT1kRuMmASL74AAAg3WZnNI005.jpeg" alt="蚂蚁金服集团"
width="60" height="60">
</a>
</div>
</div>
<div class="list_item_bot">
<div class="li_b_l">
<!-- 职位描述 -->
<span>互联网金融</span>
<span>后端</span>
<span>分布式</span>
</div>
<!-- 福利 -->
<div class="li_b_r">“全球化视野”</div>
</div>
</li>
</ul>
</body>
</html>