当前位置: 首页 > news >正文

使用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()表达式,迈出自动化采集的第一步。

http://www.zskr.cn/news/158609.html

相关文章:

  • Open-AutoGLM 适配苹果设备进展曝光(2024年唯一官方技术路线图)
  • C++中如何正确调用C语言接口?
  • Social Development Bank在DeveGo 2025论坛上重点推介战略合作与全球倡议
  • PHP木马代码分析与安全风险揭示
  • 错过Open-AutoGLM可能意味着落后三年?:解读智谱AI云终端战略布局
  • 【国产AI编程新纪元】:Open-AutoGLM与豆包如何重塑开发者工作流?
  • 四体低位交叉存储器的工作原理与设计
  • LeetCode136/169/75/31/287 算法技巧题核心笔记
  • iOS中将十六进制字符串转换为UIImage
  • 【Open-AutoGLM实战指南】:5个关键模块拆解助你快速上手
  • Ionic Vue 更新发布:5.4.0-rc 版本亮点
  • 目标检测数据集 第084期-基于yolo标注格式的小型陨石坑识别检测数据集(含免费分享)
  • 5G核心网架构及会话管理关键技术解析
  • 坐标转换与投影:解决 WebGIS 的坐标混乱问题
  • 帕普斯与帕斯卡定理的射影几何证明
  • C4D材质基础:从金属到玻璃的质感模拟
  • 3Dmax模型与Vray材质如何高效转C4D用Octane渲染
  • 智谱AutoGLM开源了?手把手教你获取Open-AutoGLM源码并快速上手,错过等一年!
  • 如何通过企业微信服务中心电话,实现高效协同、客户服务? - 品牌2026
  • 《节能与新能源汽车技术路线图2.0》发布
  • 纯C实现的轻量级YMODEM文件传输库
  • C语言结构体与typedef详解
  • 2025年企业展厅建设公司TOP5推荐:盛世笔特集团品牌知名度高吗? - 工业推荐榜
  • Windows Server 2012 R2 AD域中DHCP配置指南
  • 苹果AirPods Max拆解:低功耗与主动降噪技术解析
  • RTK基站设置与GNSS测量操作全解析
  • 阿里云渠道商:GPU 服务器 5 大高频故障排查指南
  • Ionic Framework更新:Vue支持与多项Bug修复
  • 【大模型开发者必看】:Open-AutoGLM开源代码获取全攻略,错过等于掉队
  • 【Java毕设全套源码+文档】基于springboot的本科实践教学管理系统设计与实现(丰富项目+远程调试+讲解+定制)