利用 Jsoup 进行高效 Web 抓取与 HTML 处理

Jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 JQuery 的操作方法来取出和操作数据。

官网:https://jsoup.org/

中文文档:Jsoup 快速入门 | JAVA-TUTORIAL

1. Jsoup相关概念

1. Document

  • 定义:Document 对象表示整个 HTML 文档。
  • 用途:用于解析 HTML 字符串或从 URL 获取 HTML 内容。

2. Element

  • 定义:Element 对象表示 HTML 中的一个标签元素。
  • 用途:用于选择和操作具体的 HTML 元素。

3. Elements

  • 定义:Elements 对象是一个 Element 对象的集合。
  • 用途:用于存储多个匹配的元素。

4. Node

  • 定义:Node 是 Element 和 Text 的基类,表示 HTML 文档中的节点。
  • 用途:用于更细粒度的操作,如处理注释、文档类型声明等。

5. TextNode

  • 定义:TextNode 表示 HTML 文档中的纯文本节点。
  • 用途:用于处理元素内的文本内容。

6. CSS 选择器

  • 定义:CSS 选择器是一种用于选择 HTML 元素的语法。
  • 用途:用于精确选择文档中的特定元素。
  • 常用选择器:
    • #id:选择具有指定 ID 的元素。
    • .class:选择具有指定类的元素。
    • tag:选择指定标签的元素。
    • tag[attr]:选择具有指定属性的元素。
    • tag[attr=value]:选择具有指定属性值的元素。

7. 连接和请求

  • 定义:Jsoup 提供了连接到 URL 并获取 HTML 文档的功能。
  • 用途:用于从远程服务器获取 HTML 内容。

2. Jsoup 的优点

1. 易用性:

  • 简洁的 API:Jsoup 提供了非常简洁和直观的 API,使得开发者可以快速上手。
  • 链式调用:支持链式调用,使代码更加简洁和可读。

2. 强大的解析能力:

  • HTML 解析:能够解析不规范的 HTML,即使 HTML 结构不完整也能正确解析。
  • CSS 选择器:支持类似于 jQuery 的 CSS 选择器,方便提取和操作 HTML 元素。

3. 网络请求:

  • HTTP 请求:内置了简单的 HTTP 客户端,可以方便地发送 GET 和 POST 请求。
  • 自动处理重定向:支持自动处理 HTTP 重定向。

4. 安全性:

  • HTML 清洗:提供了 Jsoup.clean 方法,可以清理 HTML 以防止 XSS 攻击,确保输出的安全性。

3. Jsoup 的缺点

1. 性能问题:

  • 内存消耗:在处理大文件或大量数据时,Jsoup 可能会消耗较多的内存,尤其是在解析复杂的 HTML 文档时。
  • 速度较慢:与一些低级别的解析库相比,Jsoup 的解析速度可能稍慢,特别是在高并发场景下。

2. 功能限制:

  • 有限的 HTTP 功能:虽然内置了 HTTP 客户端,但功能相对简单,对于复杂的需求(如多线程请求、高级认证等)可能需要额外的库支持。
  • 缺乏高级特性:相比于一些更专业的爬虫框架(如 Scrapy),Jsoup 缺乏一些高级特性,如分布式爬取、自动反爬机制等。

3. 依赖管理:

  • 依赖项:Jsoup 本身依赖较少,但在实际项目中可能需要引入其他库来补充其功能,增加了项目的复杂性。

4. 错误处理:

  • 异常处理:Jsoup 的异常处理机制较为简单,对于一些复杂的错误情况可能需要开发者自行处理。

4. 执行流程

4.1. 添加依赖

<dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.14.3</version>
</dependency>

4.2. 获取 Document

Jsoup 类方法列表:

方法名称

是否静态

参数

返回值

描述

parse(String html)

是

String html

Document

从字符串中解析 HTML 并返回一个 Document 对象。

parse(File in, String charsetName)

是

File in, String charsetName

Document

从文件中解析 HTML 并返回一个 Document 对象。

parse(URL url, int timeoutMillis)

是

URL url, int timeoutMillis

Document

从 URL 中解析 HTML 并返回一个 Document 对象。

connect(String url)

是

String url

Connection

创建一个新的 Connection 对象,用于发送 HTTP 请求。

 Connection 类方法列表:

方法名称

是否静态

参数

返回值

描述

method(Method method)

否

Method method

Connection

设置请求方法(GET、POST 等)。

url(URL url)

否

URL url

Connection

设置请求的 URL。

requestBody(String requestBody)

否

String requestBody

Connection

设置请求体内容。

data(String key, String value)

否

String key, String value

Connection

添加表单数据。

header(String key, String value)

否

String key, String value

Connection

添加请求头。

userAgent(String userAgent)

否

String userAgent

Connection

设置 User-Agent。

referrer(String referrer)

否

String referrer

Connection

设置 Referer。

timeout(int millis)

否

int millis

Connection

设置连接超时时间(毫秒)。

followRedirects(boolean follow)

否

boolean follow

Connection

设置是否自动跟随重定向。

ignoreHttpErrors(boolean ignore)

否

boolean ignore

Connection

设置是否忽略 HTTP 错误(如 404)。

ignoreContentType(boolean ignore)

否

boolean ignore

Connection

设置是否忽略内容类型检查。

maxBodySize(int maxSize)

否

int maxSize

Connection

设置响应体的最大大小(字节)。

cookie(String key, String value)

否

String key, String value

Connection

添加 Cookie。

cookies(Map<String, String> cookies)

否

Map<String, String> cookies

Connection

添加多个 Cookie。

execute()

否

无

Connection.Response

执行请求并返回响应对象。

get()

否

无

Document

发送 GET 请求并返回解析后的 Document 对象。

post()

否

无

Document

发送 POST 请求并返回解析后的 Document 对象。

 Connection.Response 类方法列表:

方法名称

是否静态

参数

返回值

描述

body()

否

无

String

获取响应体内容。

parse()

否

无

Document

解析响应体为 Document 对象。

statusCode()

否

无

int

获取响应状态码。

statusMessage()

否

无

String

获取响应状态消息。

url()

否

无

URL

获取最终请求的 URL(可能经过重定向)。

headers()

否

无

Map<String, List<String>>

获取响应头。

header(String key)

否

String key

String

获取指定响应头的值。

cookies()

否

无

Map<String, String>

获取响应中的 Cookie。

cookie(String key)

否

String key

String

获取指定 Cookie 的值。

 4.3. 获取Element 或 Elements 及 文本内容

Document 类方法列表:

方法名称

是否静态

参数

返回值

描述

title()

否

无

String

获取文档的标题。

select(String cssQuery)

否

String cssQuery

Elements

使用 CSS 选择器选择元素。

getElementsByTag(String tagName)

否

String tagName

Elements

获取指定标签名的所有元素。

getElementById(String id)

否

String id

Element

获取指定 ID 的元素。

html()

否

无

String

获取文档的 HTML 内容。

text()

否

无

String

获取文档的文本内容。

Elements 类方法列表:

方法名称

是否静态

参数

返回值

描述

first()

否

无

Element

获取第一个元素。

last()

否

无

Element

获取最后一个元素。

size()

否

无

int

获取元素的数量。

get(int index)

否

int index

Element

获取指定索引的元素。

eachText()

否

无

List<String>

获取所有元素的文本内容列表。

eachAttr(String attributeKey)

否

String attributeKey

List<String>

获取所有元素的指定属性值列表。

 Element 类方法列表:

方法名称

是否静态

参数

返回值

描述

attr(String key)

否

String key

String

获取元素的属性值。

removeAttr(String key)

否

String key

Element

移除元素的属性。

addClass(String className)

否

String className

Element

添加 CSS 类。

removeClass(String className)

否

String className

Element

移除 CSS 类。

text()

否

无

String

获取元素的文本内容。

html()

否

无

String

获取元素的 HTML 内容。

append(String html)

否

String html

Element

在元素末尾追加 HTML。

prepend(String html)

否

String html

Element

在元素开头插入 HTML。

select(String cssQuery)

否

String cssQuery

Elements

使用 CSS 选择器选择子元素。

5. CSS 选择器

5.1.  基本选择器

1. 标签选择器

  • 选择所有 <div> 标签:div
  • 选择所有 <a> 标签:a

2. 类选择器

  • 选择所有带有 class="example" 的元素:.example

3. ID 选择器

  • 选择 ID 为 example 的元素:#example

4. 属性选择器

  • 选择所有带有 href 属性的 <a> 标签:a[href]
  • 选择所有 href 属性值为 http://example.com 的 <a> 标签:a[href="http://example.com"]
  • 选择所有 href 属性值包含 example 的 <a> 标签:a[href*="example"]
  • 选择所有 href 属性值以 http 开头的 <a> 标签:a[href^="http"]
  • 选择所有 href 属性值以 .html 结尾的 <a> 标签:a[href$=".html"]
  • 选择所有 src 属性值匹配正则表达式的 <img> 标签:img[src~=(?i)(png|jpe?g)]

5. 命名空间选择器

  • 选择所有在 fb 命名空间中的 name 标签:fb|name

6. 通配符选择器

  • 选择所有元素:*

5.2. 组合选择器

1. 后代选择器

  • 选择所有在 <div> 内部的 <p> 标签:div p

2. 子选择器

  • 选择所有直接在 <div> 内部的 <p> 标签:div > p

3. 相邻兄弟选择器

  • 选择所有紧接在 <h1> 后面的 <p> 标签:h1 + p

4. 通用兄弟选择器

  • 选择所有在 <h1> 后面的 <p> 标签:h1 ~ p

5. 元素+ID

  • 选择所有带有 ID 为 logo 的 <div> 标签:div#logo

6. 元素+类

  • 选择所有带有 class="title" 的 <div> 标签:div.title

7. 元素+属性

  • 选择所有带有 href 属性的 <a> 标签:a[href]

8. 多个类选择器

  • 选择所有同时带有 class="info" 和 class="active" 的元素:.info.active

9. 多个选择器组合

  •  选择所有带有 class="highlight" 且带有 href 属性的 <a> 标签:a[href].highlight

5.3. 伪类选择器

1. 索引选择器

  • 选择索引值小于 3 的 <td> 标签:td:lt(3)
  • 选择索引值大于 2 的 <p> 标签:div p:gt(2)
  • 选择索引值等于 1 的 <input> 标签:form input:eq(1)

2. 包含选择器

  • 选择包含 <p> 标签的 <div> 标签:div:has(p)
  • 选择不包含 class="logo" 的所有 <div> 标签:div:not(.logo)

3. 文本匹配选择器

  • 选择包含文本 jsoup 的 <p> 标签:p:contains(jsoup)
  • 选择直接包含文本 jsoup 的 <p> 标签:p:containsOwn(jsoup)

4. 正则表达式匹配选择器

  • 选择文本匹配正则表达式的 <div> 标签:div:matches((?i)login)
  • 选择自身包含文本匹配正则表达式的 <div> 标签:div:matchesOwn((?i)login)

6. 实战示例

以爬取 https://ssr3.scrape.center/ 这个网站为例:

1. 获取所有电影信息。

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpHeaders;import java.io.IOException;@SpringBootTest
public class JsoupTests {@Testpublic void testJsoup() throws IOException {String url = "https://ssr3.scrape.center/";Document document = Jsoup.connect(url).header(HttpHeaders.AUTHORIZATION, "Basic YWRtaW46YWRtaW4=").get();// 解析电影信息Elements movieItems = document.select(".el-card__body");for (Element item : movieItems) {// 提取电影名称和链接Element nameLink = item.select("a.name").first();if (nameLink != null) {String movieName = nameLink.select("h2").text();String movieUrl = nameLink.attr("href");// 提取电影封面URLElement coverImage = item.select("img.cover").first();String coverImageUrl = coverImage != null ? coverImage.attr("src") : "N/A";// 提取电影类别String category = item.select(".el-button.category").text();// 提取国家和片长Elements infoElements = item.select(".info");String countryAndDuration = infoElements.get(0).text();String[] parts = countryAndDuration.split(" / ");String country = parts[0];String duration = parts[1];// 提取上映日期String releaseDate = infoElements.get(1).text();// 提取评分String score = item.select(".score").text();// 提取星级评分String starRating = item.select(".el-rate").attr("aria-valuenow");// 打印提取的信息System.out.println("电影名称: " + movieName);System.out.println("电影链接: " + movieUrl);System.out.println("电影封面URL: " + coverImageUrl);System.out.println("电影类别: " + category);System.out.println("国家: " + country);System.out.println("片长: " + duration);System.out.println("上映日期: " + releaseDate);System.out.println("评分: " + score);System.out.println("星级评分: " + starRating);System.out.println("----------------------------");}}}
}

 测试结果为:

 2. 打印所有电影的电影类别、国家和片长、上映日期、评分、星级评分、总条数及页面链接

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpHeaders;import java.io.IOException;@SpringBootTest
public class JsoupTests {public static void main(String[] args) {String url = "https://ssr3.scrape.center/";try {// 连接并获取文档Document document = Jsoup.connect(url).header("Authorization", "Basic YWRtaW46YWRtaW4=").get();// 提取电影类别Elements categoryButtons = document.select(".el-button.category");for (Element button : categoryButtons) {System.out.println("电影类别: " + button.text());}// 提取国家和片长Elements infoDivs = document.select(".info");for (Element div : infoDivs) {System.out.println("国家和片长: " + div.text());}// 提取上映日期Elements releaseDateDivs = document.select(".info:contains(上映)");for (Element div : releaseDateDivs) {System.out.println("上映日期: " + div.text());}// 提取评分Elements scoreElements = document.select(".score");for (Element score : scoreElements) {System.out.println("评分: " + score.text());}// 提取星级评分Elements rateElements = document.select(".el-rate");for (Element rate : rateElements) {int fullStars = rate.select(".el-rate__icon.el-icon-star-on").size();int halfStar = rate.select(".el-rate__decimal.el-icon-star-on").size();double rating = fullStars + (halfStar > 0 ? 0.5 : 0);System.out.println("星级评分: " + rating);}// 提取分页信息Element pagination = document.select(".el-pagination").first();if (pagination != null) {String totalItems = pagination.select(".el-pagination__total").text();System.out.println("总条数: " + totalItems);Elements pageLinks = pagination.select(".el-pager li.number a");for (Element link : pageLinks) {System.out.println("页面链接: " + link.attr("href"));}}} catch (IOException e) {e.printStackTrace();}}
}

打印结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.tpcf.cn/bicheng/61991.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯不知道叫什么题目

小蓝有一个整数&#xff0c;初始值为1&#xff0c;他可以花费一些代价对这个整数进行变换。 小蓝可以花贵1的代价将教数增加1。 小蓝可以花费3的代价将整数增加一个值,这个值是整数的数位中最大的那个(1到9) .小蓝可以花费10的代价将整数变为原来的2倍, 例如&#xff0c;如果整…

【JavaEE初阶】枫叶经霜艳,梅花透雪香-计算机是如何运行的?

本篇博客给大家带来的是与计算机相关的知识点, 包括:计算机的组成, 指令, 进程(重点). 文章专栏: JavaEE初阶 若有问题 评论区见 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 1. 计算机的组成 1.1 计算机的发展史 计算…

SuperMap Objects组件式GIS开发技术浅析

引言 随着GIS应用领域的扩展&#xff0c;GIS开发工作日显重要。一般地&#xff0c;从平台和模式上划分&#xff0c;GIS二次开发主要有三种实现方式&#xff1a;独立开发、单纯二次开发和集成二次开发。上述的GIS应用开发方式各有利弊&#xff0c;其中集成二次开发既可以充分利…

Linux网络——NAT/代理服务器

一.NAT技术 1.NAT IP转换 之前我们讨论了, IPv4 协议中, IP 地址数量不充足的问题&#xff0c;NAT 技术就是当前解决 IP 地址不够用的主要手段, 是路由器的一个重要功能。 NAT 能够将私有 IP 对外通信时转为全局 IP. 也就是一种将私有 IP 和全局IP 相互转化的技术方法: 很…

前端安全和解决方案

提到这个我可能想到的就是不要暴露太多的账号密码信息。一些页面的请求和操作要加上权限。 然后下面就详细的介绍前端可能遇到的安全问题以及解决方法。 首先比较常见的前端的安全性问题就是跨站脚本攻击&#xff08;XSS&#xff09;。跨站请求伪造&#xff08;csrf&#xff…

使用八爪鱼爬虫抓取汽车网站数据,分析舆情数据

我是做汽车行业的&#xff0c;可以用八爪鱼爬虫抓取汽车之家和微博上的汽车文章内容&#xff0c;分析各种电动汽车口碑数据。 之前&#xff0c;我写过很多Python网络爬虫的案例&#xff0c;使用requests、selenium等技术采集数据&#xff0c;这次尝试去采集小米SU7在微博、汽车…

C语言笔记(自定义类型:结构体、枚举、联合体 )

前言 本文对自定义类型的结构体创建、使用、结构体的存储方式和对齐方式&#xff0c;枚举的定义、使用方式以及联合体的定义、使用和存储方式展开叙述&#xff0c;如有错误&#xff0c;请各位指正。 目录 前言 1 结构体 1.1 结构体的声明 1.2 结构体的自引用 1.3 结构体变…

网络安全问题与大忌

“老三样&#xff0c;堵漏洞、做高墙、防外攻&#xff0c;防不胜防。” 日前&#xff0c;中国工程院沈昌祥院士这样概括中国信息安全的基本状况。 信息安全提了这么些年&#xff0c;究竟国内的网络如何脆弱&#xff0c;如何不堪一击&#xff0c;恐怕常人是难以想象的。公安部计…

3.langchain中的prompt模板 (few shot examples in chat models)

本教程将介绍如何使用LangChain库和智谱清言的 GLM-4-Plus 模型来理解和推理一个自定义的运算符&#xff08;例如使用鹦鹉表情符号&#x1f99c;&#xff09;。我们将通过一系列示例来训练模型&#xff0c;使其能够理解和推断该运算符的含义。 环境准备 首先&#xff0c;确保…

【消息序列】详解(6):深入探讨缓冲区管理与流量控制机制

目录 一、概述 1.1. 缓冲区管理的重要性 1.2. 实现方式 1.2.1. HCI_Read_Buffer_Size 命令 1.2.2. HCI_Number_Of_Completed_Packets 事件 1.2.3. HCI_Set_Controller_To_Host_Flow_Control 命令 1.2.4. HCI_Host_Buffer_Size 命令 1.2.5. HCI_Host_Number_Of_Complete…

如何使用OCR技术批量识别图片中的文字并重命名文件,OCR 技术批量识别图片中的文字可能出现的错误

字符识别错误 形近字混淆&#xff1a;例如 “已” 和 “己”、“未” 和 “末” 等&#xff0c;由于外形极为相似&#xff0c;OCR 软件在识别时可能出现误判&#xff0c;将原本正确的字识别成与之形近的另一个字。比如在识别一篇手写的文章中&#xff0c;手写体的 “已” 可能就…

Qt | 开发技能提升档次哈

点击上方"蓝字"关注我们 01、Creator常用快捷键 >>> F1 查看帮助 F2 跳转到函数定义 Shift+F2 声明和定义之间切换 F3 查找下一个 F4 头文件和源文件之间切换 Ctrl+1 欢迎模式 Ctrl+2 编辑模…

kafka消费者组和分区数之间的关系是怎样的?

消费者组和分区数之间的关系决定了Kafka中消息的消费方式和负载均衡。合理配置分区数和消费者数量对于优化Kafka的性能和资源利用率至关重要。以下是这种关系的几个关键点&#xff1a; 一个分区只能被同一组的一个消费者消费&#xff1a;这是为了保证消息的顺序性。在同一个消费…

Element Plus的快速入门

一、什么是Element Plus Element : 是饿了么团队研发的&#xff0c;基于Vue3&#xff0c;面向设计师和开发者的组件库。 组件&#xff1a;组成网页的部分&#xff0c;例如超链接&#xff0c;按钮&#xff0c;图片&#xff0c;表格&#xff0c;表单&#xff0c;分页条等等。 …

健身房小程序服务渠道开展

健身不单单是锻炼身体、保持身材&#xff0c;也是一种社交方式&#xff0c;城市里门店不少&#xff0c;每家都有一定流量和老客&#xff0c;但仅靠传统线下拉客/自然流量前往和线上朋友圈、短视频发硬广等方式还不够。 商家需要找到更多潜在目标客户&#xff0c;而消费者也对门…

MRI联合超声影像学预测乳腺癌分子水平表达

MRI联合超声影像学预测乳腺癌分子水平表达的研究是一个跨学科的方向,涉及医学影像学、分子生物学和计算机视觉等领域。目标是通过影像学手段(如MRI和超声)来预测乳腺癌的分子标志物,进一步了解肿瘤的生物学特征,并辅助诊断、预后评估以及治疗方案的选择。 一、可能的研究…

网络渗透测试工具推荐与简介

推荐一批网络渗透测试工具&#xff1a; AIEngine - 这是一个基于Python/Ruby/Java/Lua的互动/可编程的下一代数据包检测引擎&#xff0c;具有无需人工干预的学习功能&#xff0c;支持网络入侵检测系统(NIDS)、DNS域名分类、网络数据收集、网络专家分析等功能。 Denyhosts - 用…

Docker--通过Docker容器创建一个Web服务器

Web服务器 Web服务器&#xff0c;一般指网站服务器&#xff0c;是驻留于因特网上某种类型计算机的程序。 Web服务器可以向浏览器等Web客户端提供文档&#xff0c;也可以放置网站文件以供全世界浏览&#xff0c;或放置数据文件以供全世界下载。 Web服务器的主要功能是提供网上…

HTMLCSS:3D金字塔加载动画

效果演示 这段代码通过CSS3的3D变换和动画功能&#xff0c;创建了一个旋转的金字塔加载动画&#xff0c;每个侧面都有不同的颜色渐变&#xff0c;底部还有一个模糊的阴影效果&#xff0c;增加了视觉的立体感。 HTML <div class"pyramid-loader"><div cl…

C++中定义类型名的方法

什么是 C 中的类型别名和 using 声明&#xff1f; 类型别名与using都是为了提高代码的可读性。 有两种方法可以定义类型别名 一种是使用关键字typedef起别名使用别名声明来定义类型的别名&#xff0c;即使用using. typedef 关键字typedef作为声明语句中的基本数据类型的一…