利用 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.mzph.cn/bicheng/61991.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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 相互转化的技术方法: 很…

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

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

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

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

【消息序列】详解(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…

Element Plus的快速入门

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

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

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

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…

selinux及防火墙

selinux说明 SELinux 是 Security-Enhanced Linux 的缩写&#xff0c;意思是安全强化的 linux 。 SELinux 主要由美国国家安全局&#xff08; NSA &#xff09;开发&#xff0c;当初开发的目的是为了避免资源的误用。 httpd进程标签&#xff08;/usr/share/nginx/html &#…

vue 富文本图片如何拖拽

在Vue项目中实现富文本编辑器&#xff08;如vue-quill-editor&#xff09;的图片拖拽功能&#xff0c;需要结合Quill.js及其相关插件进行配置 安装必要的依赖包&#xff1a; 你需要安装vue-quill-editor作为富文本编辑器的基础组件。为了支持图片拖拽功能&#xff0c;你还需要…

秋招面试基础总结,Java八股文基础(串联知识),四万字大全

目录 值传递和引用传递 静态变量和静态代码块的执行顺序 Java​​​​​​​集合的框架&#xff0c;Set,HashSet,LinkedHashSet这三个底层是什么 多线程篇 Java实现多线程的方式 假设一个线程池&#xff0c;核心线程数是2&#xff0c;最大线程数是3&#xff0c;阻塞队列是4…

MySQL原理简介—12.MySQL主从同步

大纲 1.异步复制为MySQL搭建一套主从复制架构 2.半同步复制为MySQL搭建一套主从复制架构 3.GTID为MySQL搭建一套主从复制架构 4.并行复制降低主从同步延迟或强制读主库 1.异步复制为MySQL搭建一套主从复制架构 (1)MySQL主从复制的原理 (2)搭建主从复制架构的配置 (1)MySQ…

一文了解Spring提供的几种扩展能力

基于 spring bean 的扩展 1. BeanPostProcessor spring 提供的针对 bean 的初始化过程时提供的扩展能力&#xff0c;从方法名也很容易看出&#xff0c;提供的两个方法分别是为 bean 对象提供了初始化之前以及初始化之后的扩展能力。 package com.wyl.conf;import org.spring…

【隐私计算大模型】联邦深度学习之拆分学习Split learning原理及安全风险、应对措施以及在大模型联合训练中的应用案例

Tips&#xff1a;在两方场景下&#xff0c;设计的安全算法&#xff0c;如果存在信息不对等性&#xff0c;那么信息获得更多的一方可以有概率对另一方实施安全性攻击。 1. 拆分学习原理 本文介绍了一种适用于隐私计算场景的深度学习实现方案——拆分学习&#xff0c;又称分割…

Linux 下进程基本概念与状态

文章目录 一、进程的定义二、 描述进程-PCBtask_ struct内容分类 三、 进程状态 一、进程的定义 狭义定义&#xff1a;进程是正在运行的程序的实例&#xff08;an instance of a computer program that is being executed&#xff09;。广义定义&#xff1a;进程是一个具有一定…

k8s1.31版本最新版本集群使用容器镜像仓库Harbor

虚拟机 rocky9.4 linux master node01 node02 已部署k8s集群版本 1.31 方法 一 使用容器部署harbor (1) wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo yum -y install docker-ce systemctl enable docker…

数据库MYSQL——表的设计

文章目录 前言三大范式&#xff1a;几种实体间的关系&#xff1a;一对一关系&#xff1a;一对多关系&#xff1a;多对多关系&#xff1a; 前言 之前的博客中我们讲解的是关于数据库的增删改查与约束的基本操作&#xff0c; 是在已经创建数据库&#xff0c;表之上的操作。 在实…