Java 爬虫遇上数据异步加载,试试这两种办法!

2024-09-04 03:18

本文主要是介绍Java 爬虫遇上数据异步加载,试试这两种办法!,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

爬虫工具根据Xpath路径解析网页时,如果页面是异步加载,则无法获取到js渲染后的界面。这样我们通过XPath路径则定位到具体对象。对此类问题的解决方案有两种。

第一:内置浏览器内核

内置浏览器就是在抓取的程序中,启动一个浏览器内核,使我们获取到 js 渲染后的页面,这样我们就跟采集静态页面一样了。这种工具常用的有以下三种:

  • Selenium
  • HtmlUnit
  • PhantomJs

这些工具都能帮助我们解决数据异步加载的问题,但是他们都存在缺陷,那就是效率不高而且不稳定。

第二:反向解析法

什么是反向解析法呢?我们 js 渲染页面的数据是通过 Ajax 的方式从后端获取的,我们只需要找到对应的 Ajax 请求连接就 OK,这样我们就获取到了我们需要的数据,反向解析法的好处就是这种方式获取的数据都是 json 格式的数据,解析起来也比较方便,另一个好处就是相对页面来说,接口的变化概率更小。同样它有两个不足之处,一个是在 Ajax 时你需要有耐心有技巧,因为你需要在一大推请求中找到你想要的,另一个不足的地方就是对 JavaScript 渲染的页面束手无策。

上面就是异步数据加载的两种解决办法,为了加深大家的理解和在项目中如何使用,我以采集网易要闻为例,网易新闻地址:https://news.163.com/ 。利用上诉的两种方式来获取网易要闻的新闻列表。网易要闻如下:

 

内置浏览器 Selenium 方式

Selenium 是一个模拟浏览器,进行自动化测试的工具,它提供一组 API 可以与真实的浏览器内核交互。在自动化测试上使用的比较多,爬虫时解决异步加载也经常使用它,我们要在项目中使用 Selenium ,需要做两件事:

  • 1、引入 Selenium 的依赖包,在 pom.xml 中添加
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>3.141.59</version>
</dependency>
  • 2、下载对应的 driver,例如我下载的 chromedriver,下载地址为:https://npm.taobao.org/mirrors/chromedriver/,下载后,需要将 driver 的位置写到 Java 的环境变量里,例如我直接放在项目下,所以我的代码为:
    System.getProperties().setProperty("webdriver.chrome.driver", "chromedriver.exe");

完成上面两步之后,我们就可以来编写使用 Selenium 采集网易要闻啦。具体代码如下:

/*** selenium 解决数据异步加载问题* https://npm.taobao.org/mirrors/chromedriver/** @param url*/
public void selenium(String url) {// 设置 chromedirver 的存放位置System.getProperties().setProperty("webdriver.chrome.driver", "chromedriver.exe");// 设置无头浏览器,这样就不会弹出浏览器窗口ChromeOptions chromeOptions = new ChromeOptions();chromeOptions.addArguments("--headless");WebDriver webDriver = new ChromeDriver(chromeOptions);webDriver.get(url);// 获取到要闻新闻列表List<WebElement> webElements = webDriver.findElements(By.xpath("//div[@class='news_title']/h3/a"));for (WebElement webElement : webElements) {// 提取新闻连接String article_url = webElement.getAttribute("href");// 提取新闻标题String title = webElement.getText();if (article_url.contains("https://news.163.com/")) {System.out.println("文章标题:" + title + " ,文章链接:" + article_url);}}webDriver.close();
}

运行该方法,得到结果如下:

我们使用 Selenium 已经正确的提取到了网易要闻的列表新闻。

反向解析法

反向解析法就是获取到 Ajax 异步获取数据的链接,直接获取到新闻数据。如果没有技巧的话,查找 Ajax 的过程将非常痛苦,因为一个页面加载的链接太多了,看看网易要闻的 network:

有几百条的请求,该如何查找到是哪条请求获取的要闻数据呢?你不嫌麻烦的话,可以一个一个的去点,肯定能够查找到的,另一种快捷的办法是利用 network 的搜索功能,如果你不知道搜索按钮,我在上图已经圈出来啦,我们在要闻中随便复制一个新闻标题,然后检索一下,就可以获取到结果,如下图所示:

这样我们就快速的获取到了要闻数据的请求链接,链接为:https://temp.163.com/special/00804KVA/cm_yaowen.js?callback=data_callback,访问该链接,查看该链接返回的数据,如下图所示:

从数据我们可以看出,我们需要的数据都在这里啦,所以我们只需要解析这段数据接可以啦,要从这段数据中解析出新闻标题和新闻链接,有两种方式,一种是正则表达式,另一种是将该数据转成 json 或者 list。这里我选择第二种方式,利用 fastjson 将返回的数据转换成 JSONArray 。所以我们是要引入 fastjson ,在 pom.xml 中引入 fastjson 依赖:

<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.59</version>
</dependency>

除了引入 fastjson 依赖外,我们在转换前还需要对数据进行简单的处理,因为现在的数据并不符合 list 的格式,我们需要去掉 data_callback( 和最后面的 )。具体反向解析获取网易要闻的代码如下:

/*** 使用反向解析法 解决数据异步加载的问题** @param url*/
public void httpclientMethod(String url) throws IOException {CloseableHttpClient httpclient = HttpClients.createDefault();HttpGet httpGet = new HttpGet(url);CloseableHttpResponse response = httpclient.execute(httpGet);if (response.getStatusLine().getStatusCode() == 200) {HttpEntity entity = response.getEntity();String body = EntityUtils.toString(entity, "GBK");// 先替换掉最前面的 data_callback(body = body.replace("data_callback(", "");// 过滤掉最后面一个 )右括号body = body.substring(0, body.lastIndexOf(")"));// 将 body 转换成 JSONArrayJSONArray jsonArray = JSON.parseArray(body);for (int i = 0; i < jsonArray.size(); i++) {JSONObject data = jsonArray.getJSONObject(i);System.out.println("文章标题:" + data.getString("title") + " ,文章链接:" + data.getString("docurl"));}} else {System.out.println("处理失败!!!返回状态码:" + response.getStatusLine().getStatusCode());}}

编写 main 方法,执行上面的方法,需要注意的地方是:这时候传入的链接为https://temp.163.com/special/00804KVA/cm_yaowen.js?callback=data_callback 而不是 https://news.163.com/。得到如下结果:

两种方法都成功的获取到了网易要闻异步加载的新闻列表,对于这两种方法的选取,我个人的倾向是使用反向解析法,因为它的性能和稳定是都要比内置浏览器内核靠谱,但是对于一些使用 JavaScript 片段渲染的页面,内置浏览器又更加靠谱。所以根据具体情况选择吧。

希望这篇文章对你有所帮助,下一篇是关于 爬虫IP 被封的问题。如果你对爬虫感兴趣,不妨关注一波,相互学习,相互进步

 

 

这篇关于Java 爬虫遇上数据异步加载,试试这两种办法!的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1134844

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定