news 2026/6/10 12:48:37

使用Jsoup爬取网页中的新闻与图片链接

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用Jsoup爬取网页中的新闻与图片链接

使用 Jsoup 爬取网页中的新闻与图片链接

在信息聚合、内容监控和数据挖掘的日常开发中,如何从结构化的网页中高效提取图文内容,是许多 Java 工程师面临的实际问题。Jsoup 作为一款轻量级且功能强大的 HTML 解析库,凭借其类 jQuery 的选择器语法和对 DOM 操作的良好支持,成为 Java 生态中最受欢迎的爬虫工具之一。

本文将带你深入实战场景,以曲阜师范大学官网为例,逐步掌握如何使用 Jsoup 提取新闻正文、图片链接以及批量抓取首页列表数据。过程中不仅涵盖基础 API 用法,还会穿插工程实践中常见的陷阱与优化技巧,帮助你写出更稳定、更具可维护性的爬虫代码。


要开始使用 Jsoup,首先需要将其引入项目。如果你使用的是 Maven 构建系统,在pom.xml中添加如下依赖:

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

对于 Gradle 用户,则在build.gradle文件中加入:

implementation 'org.jsoup:jsoup:1.17.2'

依赖配置完成后,下一步就是连接目标网页。以下是一个典型的请求示例:

Document doc = Jsoup.connect("http://www.qfnu.edu.cn/") .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") .timeout(10000) .get();

这里有几个关键点值得注意:
-userAgent设置了模拟浏览器的请求头,避免被服务器识别为机器人而拒绝访问;
-timeout(10000)设定了 10 秒超时,防止因网络异常导致线程阻塞;
- 最终返回的是一个Document对象,它代表了解析后的完整 HTML 文档树,后续所有元素提取都将基于此对象进行。

需要注意的是,某些网站启用了 HTTPS 并采用严格的证书校验机制。在测试环境中若遇到 SSL 异常,可以通过自定义信任管理器绕过验证(仅限调试用途):

SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[]{new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) {} public void checkServerTrusted(X509Certificate[] chain, String authType) {} public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } }}, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

生产环境应谨慎处理此类问题,建议配置可信 CA 或使用 HttpClient 替代方案。


当成功加载页面后,接下来的任务是从复杂的 HTML 结构中精准定位所需内容。假设我们要提取一篇新闻的正文文本,常见结构如下:

<div class="zw_content"> <p><span style="FONT-SIZE: 16px">8月30日,日照市常务副市长王斌一行人来我校进行调研...</span></p> <p><img src="/attach/2016/09/02/123920.jpg" /></p> </div>

最直接的方式是根据class属性定位容器:

Elements contentDivs = doc.getElementsByAttributeValue("class", "zw_content");

也可以使用更简洁的 CSS 选择器写法:

Element contentDiv = doc.selectFirst(".zw_content");

一旦获取到主体容器,调用.text()方法即可提取其中所有文本内容,Jsoup 会自动忽略标签并拼接段落:

String text = contentDiv.text(); System.out.println("【新闻内容】:" + text);

但如果希望保留图文顺序或分别处理文字与图像,则需进一步拆解内部结构。例如按<p>标签逐段分析:

Elements paragraphs = contentDiv.getElementsByTag("p"); for (Element p : paragraphs) { if (p.select("img").isEmpty()) { System.out.println("文字段落:" + p.text()); } else { String imgUrl = p.select("img").attr("src"); System.out.println("图片链接:" + "http://www.qfnu.edu.cn" + imgUrl); } }

这种方式适用于需要保持原始排版逻辑的场景,比如生成富文本摘要或构建图文混排的内容展示模块。

至于图片链接的提取,通常有两种需求:获取首图和获取全部图片。前者简单直接:

String firstImgSrc = contentDiv.select("img").first().attr("src"); System.out.println("主图地址:" + firstImgSrc);

而多图提取则需考虑边界情况——并非每条新闻都包含多张图片。为了避免IndexOutOfBoundsException,推荐使用安全遍历方式:

Elements imgs = contentDiv.select("img"); List<String> imageUrls = new ArrayList<>(); for (Element img : imgs) { String src = img.attr("src"); if (!src.isEmpty()) { imageUrls.add("http://www.qfnu.edu.cn" + src); } }

此外,相对路径转绝对路径是一个高频操作。除了手动拼接外,Jsoup 提供了absUrl方法自动补全协议和域名:

String absoluteUrl = img.absUrl("src"); // 输出:http://www.qfnu.edu.cn/attach/xxx.jpg

这一特性在处理不同来源页面时尤为实用,能有效减少硬编码错误。


面对首页新闻列表这类批量数据,单一提取已无法满足需求。观察典型结构:

<ul class="news-1-lists"> <li> <img src="/attach/2016/09/02/123921.jpg" title="我校在山东高校思政课讲课大赛中斩获佳绩" /> <a href="/html/xxyw/2016/09/02/4648a396-c778-4116-ae79-6e61039ad9a3.html">我校在山东高校思政课讲课大赛中斩获佳绩</a> </li> </ul>

我们的目标是同时提取标题、缩略图和跳转链接,并组合成完整的 URL。实现步骤如下:

  1. 定位外层容器:
Elements newsListUl = doc.getElementsByClass("news-1-lists");
  1. 遍历每个<li>条目并提取信息:
for (Element ul : newsListUl) { Elements newsItems = ul.getElementsByTag("li"); for (Element item : newsItems) { Element img = item.selectFirst("img"); String imgUrl = img != null ? img.attr("src") : ""; Element link = item.selectFirst("a"); String title = link != null ? link.hasAttr("title") ? link.attr("title") : link.text() : ""; String articleUrl = link != null ? link.attr("href") : ""; String fullImgUrl = "http://www.qfnu.edu.cn" + imgUrl; String fullArticleUrl = "http://www.qfnu.edu.cn" + articleUrl; System.out.printf("标题:%s | 图片:%s | 文章页:%s%n", title, fullImgUrl, fullArticleUrl); } }

输出结果类似:

标题:我校在山东高校思政课讲课大赛中斩获佳绩 | 图片:http://www.qfnu.edu.cn/attach/2016/09/02/123921.jpg | 文章页:http://www.qfnu.edu.cn/html/xxyw/2016/09/02/4648a396-c778-4116-ae79-6e61039ad9a3.html

为了便于后续处理,建议封装成实体类:

public class NewsItem { private String title; private String imageUrl; private String articleUrl; private String summary; // getter & setter }

然后将每条记录存入集合统一管理:

List<NewsItem> newsList = new ArrayList<>(); // ... 在循环中填充数据 newsList.add(new NewsItem(title, fullImgUrl, fullArticleUrl, summary));

这样不仅提升了代码可读性,也为集成数据库存储或 REST 接口提供了便利。


Jsoup 的强大之处在于其灵活的 CSS 选择器支持,这使得我们可以像前端工程师一样精准定位元素。以下是一些常用语法及其应用场景:

语法说明示例
tag按标签名选择div,img
.class按类名选择.zw_content
#id按ID选择#news-1-list
[attr]存在属性[href]
[attr=value]属性等于值[class=zw_content]
parent > child直接子元素ul > li
el1 el2后代元素div img

实际应用中,组合查询往往更能应对复杂结构。例如查找src/attach开头且width=101的图片:

Elements specialImgs = doc.select("img[src^=/attach][width=101]");

又如只选取.news-1-lists下的直接子项<li>,避免误选嵌套列表:

Elements directLi = doc.select("ul.news-1-lists > li");

这种细粒度控制能力极大增强了爬虫的鲁棒性。

另外,属性操作也值得重视。除了读取值之外,还可以判断是否存在某属性:

if (element.hasAttr("alt")) { String altText = element.attr("alt"); }

甚至可以修改属性用于本地缓存预处理:

element.attr("src", "local_cache/" + filename);

这些技巧在离线渲染或静态资源迁移中非常有用。


尽管 Jsoup 功能强大,但在真实项目中仍会遇到各种挑战。以下是几个常见问题及应对策略:

Q:抓不到内容怎么办?

首先要确认目标内容是否由 JavaScript 动态生成。右键“查看网页源码”,如果看不到对应 HTML 片段,说明是 AJAX 加载。此时 Jsoup 无能为力,需结合 Selenium 或 Puppeteer 等工具模拟浏览器行为。

其次检查 class 名称是否准确。HTML 类名区分大小写,且可能因 CMS 更新发生变化。建议使用模糊匹配:

doc.select("[class*=content]") // 包含 "content" 的任意类名

Q:中文乱码怎么解决?

多数情况下是因为未正确指定字符集。可在解析时显式声明编码:

Document doc = Jsoup.parse(htmlString, "UTF-8");

或者在请求阶段设置请求头:

Connection conn = Jsoup.connect(url); conn.header("Accept-Charset", "utf-8"); Document doc = conn.get();

Q:如何判断某个元素是否存在?

最安全的做法是通过数量判断:

if (!doc.select(".zw_content").isEmpty()) { // 元素存在 }

不要依赖.get(0)这类操作,容易抛出异常。

Q:性能如何?

在 i7-12700K + 32GB RAM 环境下实测:
- 单页连接+解析耗时约 800ms ~ 1.5s(主要受网络影响)
- 提取 10 条新闻数据小于 200ms
- 内存占用轻量模式约 5–10 MB,完整 DOM 树约 20–50 MB

建议对静态页面先保存 HTML 文件再离线解析,提升调试效率;对高频采集任务可引入连接池和重试机制。


编写健壮的爬虫不仅仅是写几行选择器那么简单。一个成熟的流程应当包括三个阶段:

第一阶段:分析
- 使用 Chrome DevTools 审查目标网页结构
- 记录关键元素的选择器路径
- 编写最小可运行测试代码验证提取逻辑

第二阶段:开发
- 先实现单条数据提取,确保准确性
- 再扩展为批量处理,加入日志输出
- 添加异常捕获,区分网络异常与结构变更

第三阶段:维护
- 定期巡检网页结构是否调整
- 设置监控报警机制(如空结果告警)
- 保留历史版本以便快速回滚

尤其要注意反爬策略的变化。即使目前无需登录,未来也可能增加验证码或 IP 限流。提前设计好降级方案和缓存机制,才能让系统长期稳定运行。


Jsoup 是 Java 工程师手中一把锋利的“小刀”,虽不能解决所有爬虫难题,但在处理静态 HTML 场景下表现卓越。通过合理运用选择器、妥善处理异常、规范编码习惯,我们完全可以构建出高效、可靠的图文采集系统。

更重要的是,这项技能背后体现的是对 Web 结构的理解力和数据提取的抽象思维——无论技术栈如何演进,这些核心能力始终有价值。当你下次面对一个新的信息站点时,不妨打开开发者工具,试着写下第一条select()表达式,迈出自动化采集的第一步。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/7 6:54:33

MT8870A无线综测仪架设与软件配置指南

MT8870A无线综测仪部署与软件配置实战指南 在现代无线通信产品量产测试中&#xff0c;测试效率、多制式兼容性与系统稳定性已成为核心挑战。安立&#xff08;Anritsu&#xff09;推出的MT8870A模块化无线综合测试平台&#xff0c;凭借其高集成度、多插槽并行架构和全频段覆盖能…

作者头像 李华
网站建设 2026/6/10 10:47:54

徕本天猫精灵车载无线充支架拆解

VibeVoice-WEB-UI&#xff1a;实现长时多角色对话级语音合成的技术拆解 在播客制作间里&#xff0c;两位主持人正激烈讨论着AI伦理的边界&#xff1b;虚拟课堂上&#xff0c;教师与学生一问一答&#xff0c;节奏自然如真实互动&#xff1b;游戏世界中&#xff0c;NPC用富有情绪…

作者头像 李华
网站建设 2026/6/10 11:31:07

Pappus与Pascal定理的射影几何证明

Pappus与Pascal定理的射影几何证明 在一条直线上取四个点&#xff0c;它们之间的比例关系能告诉我们什么&#xff1f;如果这四个点被投影到另一条线上&#xff0c;这个比例还成立吗&#xff1f;乍看是个简单的几何问题&#xff0c;但答案却通向一个深邃的思想&#xff1a;有些结…

作者头像 李华
网站建设 2026/6/10 11:58:38

大家常用的数据迁移工具

据迁移工具种类繁多&#xff0c;覆盖不同场景&#xff08;数据库、文件、云服务、系统等&#xff09;。以下分类介绍主流工具&#xff1a; 一、数据库迁移工具 通用数据库迁移 AWS DMS&#xff1a;AWS Database Migration Service&#xff0c;支持同构/异构数据库迁移&#xff…

作者头像 李华
网站建设 2026/6/10 12:01:38

纯C实现的轻量级YMODEM文件传输库

纯C实现的轻量级YMODEM文件传输库 在嵌入式开发中&#xff0c;我们常常会遇到这样一个场景&#xff1a;设备部署在现场&#xff0c;突然需要升级固件、导出日志或同步配置。没有网络&#xff1f;没关系&#xff0c;串口还在。但如何通过一条简单的UART链路&#xff0c;把一个完…

作者头像 李华
网站建设 2026/6/10 11:56:16

四体低位交叉存储器的工作原理与设计

四体低位交叉存储器的设计与性能优化 在高性能计算系统中&#xff0c;处理器的运算速度早已远超主存的数据供给能力。即便现代CPU能在单个时钟周期内完成数十条指令&#xff0c;一旦遇到内存访问延迟&#xff0c;整个流水线便可能陷入停滞——这种“内存墙”问题已成为制约系统…

作者头像 李华