爬虫使用Jsoup和htmlunit解析公众号文章的不同

B站影视 欧美电影 2025-04-04 18:41 1

摘要:对于公众号文章,当项目中有需求需要解析公众号文章,入库到自己的系统中,此时就会用到爬虫技术,今天就来输入公众号链接,来输出解析内容来看下,Jsoup和htmlunit的不同。

对于公众号文章,当项目中有需求需要解析公众号文章,入库到自己的系统中,此时就会用到爬虫技术,今天就来输入公众号链接,来输出解析内容来看下,Jsoup和htmlunit的不同。

在解析之前,首先来谈下爬虫框架Jsoup 和 HtmlUnit 的技术介绍,分点说明它们的特性、用途和区别:

Jsoup 是一个用于解析、操作和清理 HTML 文档的 Java 库。它专注于 HTML 的解析和数据提取,适合处理静态 HTML 内容。

核心特点:

DOM 解析:将 HTML 转换为类似浏览器 DOM 的结构,支持 CSS 选择器语法(如 div#id 或 a[href])。数据提取:通过选择器或遍历 API 提取特定元素(如标题、链接、表格等)。HTML 清理:过滤不安全标签(防止 XSS 攻击),生成安全的 HTML。简单轻量:无需浏览器环境,适合快速处理静态页面。不支持 JavaScript:无法执行动态生成的页面内容。爬虫中解析静态 HTML 页面。数据抓取(如新闻标题、商品价格)。清理用户输入的 HTML 内容(如富文本编辑器)。

HtmlUnit 是一个基于 Java 的无头浏览器(Headless Browser),模拟浏览器行为(如执行 JavaScript),适合处理动态网页。

核心特点:

支持 JavaScript:能执行页面中的 JS 代码(如 AJAX 请求、动态渲染)。浏览器模拟:支持 Cookies、表单提交、页面跳转等交互操作。复杂场景支持:处理 iframe、弹出窗口、文件上传等。资源消耗较高:相比 Jsoup 更重量级,适合复杂任务。特性JsoupHtmlUnitHTML 解析✔️ 高效,支持 CSS 选择器✔️ 支持,但更侧重浏览器模拟JavaScript 支持❌ 不支持✔️ 完整支持(如 AJAX、动态渲染)性能✔️ 轻量,适合快速解析静态内容❌ 较重,资源消耗较大交互能力❌ 仅支持静态操作✔️ 支持表单提交、Cookies 等适用场景静态页面数据提取、HTML 清理动态页面抓取、自动化测试

Jsoup实现代码如下:

public static Map getJsoupPublicContent(String url){Map map = Maps.newHashMap;Connection connect = Jsoup.connect(url);Document document = null;try {document = connect.get;Elements author = document.getElementsByAttributeValue("name", "author");Element html = document.getElementById("js_content");Element title = document.getElementById("activity-name");Element officalName = document.getElementById("js_name");Elements elementsByAttributeValue = document.getElementsByAttributeValue("name", "description");Elements shortContent = elementsByAttributeValue.select("meta");Elements property = document.getElementsByAttributeValue("property", "og:image");Elements img = property.select("meta");if (ObjectUtil.isEmpty(html)) {return map;}if(ObjectUtil.isNotEmpty(html)){map.put("html", html.outerHtml);}if(ObjectUtil.isNotEmpty(title)){map.put("title", title.text);}if(ObjectUtil.isNotEmpty(author)){map.put("author", author.get(0).attr("content"));}if(ObjectUtil.isNotEmpty(officalName)){map.put("officalName", officalName.text);}if(ObjectUtil.isNotEmpty(shortContent)){map.put("shortContent",shortContent.get(0).attr("content"));}if(ObjectUtil.isNotEmpty(img)){map.put("img",img.get(0).attr("content"));}Element publishTime = document.getElementById("publish_time");if(publishTime != null && StringUtils.isNotEmpty(publishTime.text)){logger.info("解析文章的发布时间:{}",publishTime.text);try{DateTime dateTime = DateUtil.parse(publishTime.text, "yyyy年MM月dd日 HH:mm");String format = DateUtil.format(dateTime, "yyyy-MM-dd HH:mm:ss");map.put("releasetime", format);}catch (Exception e){logger.error("日期格式转换失败{}",publishTime.text,e);}}return map;} catch (IOException e) {logger.error("发生异常,信息为:{}", e.getMessage);return null;}}

通过传入url测试一下:

public static void main(String args) {Map publicContent = getJsoupPublicContent("https://mp.weixin.qq.com/s/im_v_ABNUyZzrEGTmhBxkw");System.out.println(publicContent);}

运行一下结果如下:

通过返回的内容可以看出,有个解析发布时间没有拿到,那么我们就来看下页面中这个发布时间是怎么形成的:

发布时间是有的,id也是正确的,那怎么能拿不到的,我们从js中搜索一下这个publish_time,是不是动态生成的:

我们发现,这个发布时间是js加载生成的,那就不能按照静态文件来获取了,Jsoup和HtmlUnit其中有一个区别,就是对JavaScript 支持,Jsoup是不支持的,htmlunit完整支持(如 AJAX、动态渲染),那下面就用htmlunit来获取一下,代码如下:

static BrowserVersion browser =new BrowserVersion.BrowserVersionBuilder(BrowserVersion.CHROME).setUserAgent(userAgent[new Random.nextInt(userAgent.length)]).build;private static final WebClient webClient = new WebClient(browser);public static Map getHtmlUnitPublicContent(String url) {webClient.getOptions.setThrowExceptionOnScriptError(false);webClient.getOptions.setThrowExceptionOnFailingStatusCode(false);webClient.getOptions.setJavaScriptEnabled(false);webClient.getOptions.setCssEnabled(false);webClient.getOptions.setJavaScriptEnabled(true);webClient.setAjaxController(new NicelyResynchronizingAjaxController);HtmlPage page = null;try{page = webClient.getPage(url);}catch (Exception e){logger.error("解析公众号失败,信息为{}", e.getMessage);}finally {webClient.close;}if(page == null){return null;}webClient.waitForBackgroundJavaScript(30000);Document document = Jsoup.parse(page.asXml);Map map = Maps.newHashMap;Elements author = document.getElementsByAttributeValue("name", "author");Element html = document.getElementById("js_content");Element title = document.getElementById("activity-name");Element officalName = document.getElementById("js_name");Elements elementsByAttributeValue = document.getElementsByAttributeValue("name", "description");Elements shortContent = elementsByAttributeValue.select("meta");Elements property = document.getElementsByAttributeValue("property", "og:image");Elements img = property.select("meta");if (ObjectUtil.isEmpty(html)) {return map;}if(ObjectUtil.isNotEmpty(html)){map.put("html", html.outerHtml);}if(ObjectUtil.isNotEmpty(title)){map.put("title", title.text);}if(ObjectUtil.isNotEmpty(author)){map.put("author", author.get(0).attr("content"));}if(ObjectUtil.isNotEmpty(officalName)){map.put("officalName", officalName.text);}if(ObjectUtil.isNotEmpty(shortContent)){map.put("shortContent",shortContent.get(0).attr("content"));}if(ObjectUtil.isNotEmpty(img)){map.put("img",img.get(0).attr("content"));}Element publishTime = document.getElementById("publish_time");if(publishTime != null && StringUtils.isNotEmpty(publishTime.text)){logger.info("解析文章的发布时间:{}",publishTime.text);try{DateTime dateTime = DateUtil.parse(publishTime.text, "yyyy年MM月dd日 HH:mm");String format = DateUtil.format(dateTime, "yyyy-MM-dd HH:mm:ss");map.put("releasetime", format);}catch (Exception e){logger.error("日期格式转换失败{}",publishTime.text,e);}}return map;}

传入url地址,运行一下,结果如下:

这次可以拿到这个js加载的发布时间,不过运行时间比Jsoup慢了不少!

来源:AI进阶之路

相关推荐