htmlunit抓取动态网页(AngularJSjs渲染出的页面越来越多如何判断前端渲染页面)

优采云 发布时间: 2021-12-21 00:19

  htmlunit抓取动态网页(AngularJSjs渲染出的页面越来越多如何判断前端渲染页面)

  随着AJAX技术的不断普及和AngularJS等单页应用框架的出现,越来越多的页面由js渲染。对于爬虫来说,这种页面比较烦人:只提取HTML内容往往得不到有效信息。那么如何处理这种页面呢?一般来说,有两种方法:

  在爬取阶段,爬虫内置浏览器内核,执行js渲染页面后,进行爬取。这方面对应的工具有Selenium、HtmlUnit或PhantomJs。但是,这些工具存在一定的效率问题,同时也不太稳定。优点是写入规则与静态页面相同。因为js渲染页面的数据也是从后端获取的,而且基本都是通过AJAX获取的,所以分析AJAX请求,找到对应数据的请求也是一种可行的方式。并且与页面样式相比,这个界面不太可能发生变化。缺点是找到这个请求并模拟它是一个比较困难的过程,需要比较多的分析经验。

  比较两种方法,我的观点是,对于一次性或小规模的需求,第一种方法省时省力。但对于长期、*敏*感*词*的需求,第二种更可靠。对于某些站点,甚至还有一些 js 混淆技术。这时候第一种方法基本上是万能的,第二种方法会很复杂。

  对于第一种方法,webmagic-selenium 就是这样的一种尝试。它定义了一个Downloader,它在下载页面时使用浏览器内核进行渲染。selenium的配置比较复杂,跟平台和版本有关,没有稳定的解决方案。有兴趣可以看我的博客:使用Selenium爬取动态加载的页面

  这里我主要介绍第二种方法。希望最后你会发现:前端渲染页面的原创解析并没有那么复杂。这里我们以AngularJS中文社区为例。

  1 如何判断前端渲染

  判断页面是否被js渲染的方法比较简单。可以直接在浏览器中查看源码(Windows下Ctrl+U,Mac下command+alt+u)。如果找不到有效信息,基本可以确定为js渲染。

  

  

  在这个例子中,如果源代码中找不到页面上的标题“友府计算机网络-前端攻城引擎”,可以断定是js渲染,而这个数据是通过AJAX获取的。

  2 分析请求

  接下来我们进入最难的部分:找到这个数据请求。这一步可以帮助我们的工具,主要是在浏览器中查看网络请求的开发者工具。

  以Chome为例,我们打开“开发者工具”(Windows下F12,Mac下command+alt+i),然后刷新页面(也可能是下拉页面,总之你所有的操作认为可能会触发新的数据),然后记得保持场景并一一分析请求!

  这一步需要一点耐心,但也不是不守规矩。首先可以帮助我们的是上面的分类过滤器(All、Document 等选项)。如果是普通的AJAX,会显示在XHR标签下,JSONP请求会在Scripts标签下。这是两种常见的数据类型。

  然后就可以根据数据的大小来判断了。一般来说,较大的结果更有可能是返回数据的接口。剩下的基本就是凭经验了。比如这里的“latest?p=1&s=20”一看就可疑……

  

  对于可疑地址,此时可以查看响应正文的内容。此处的开发人员工具中不清楚。我们把URL复制到地址栏,再次请求(如果Chrome建议安装一个jsonviewer,查看AJAX结果非常方便)。看结果,似乎找到了我们想要的。

  

  同样的,我们到了帖子详情页,找到了具体内容的请求:。

  3 编写程序

  回顾之前的列表+目标页面的例子,我们会发现我们这次的需求和之前的差不多,只不过是换成了AJAX-AJAX风格的列表,AJAX风格的数据,返回的数据变成了JSON。那么,我们还是可以用最后一种方法,分成两页来写:

  数据表

  在这个列表页面上,我们需要找到有效的信息来帮助我们构建目标 AJAX URL。这里我们看到这个_id应该是我们想要的post的id,post details请求是由一些固定的URL加上这个id组成的。所以在这一步,我们自己手动构造了URL,加入到要爬取的队列中。这里我们使用JsonPath,一种选择数据的语言(webmagic-extension包提供了JsonPathSelector来支持)。

   if (page.getUrl().regex(LIST_URL).match()) {

//这里我们使用JSONPATH这种选择语言来选择数据

List ids = new JsonPathSelector("$.data[*]._id").selectList(page.getRawText());

if (CollectionUtils.isNotEmpty(ids)) {

for (String id : ids) {

page.addTargetRequest("http://angularjs.cn/api/article/"+id);

}

}

}

  目标数据

  有了URL,解析目标数据其实很简单。因为JSON数据是完全结构化的,省去了我们分析页面和编写XPath的过程。这里我们仍然使用 JsonPath 来获取标题和内容。

   page.putField("title", new JsonPathSelector("$.data.title").select(page.getRawText()));

page.putField("content", new JsonPathSelector("$.data.content").select(page.getRawText()));

  本示例的完整代码请参见AngularJSProcessor.java

  4 总结

  在这个例子中,我们分析了一个比较经典的动态页面的爬取过程。其实动态页面爬取最大的区别就是增加了链接发现的难度。让我们比较一下两种开发模式:

  后台渲染页面

  下载辅助页面 => 发现链接 => 下载并分析目标 HTML

  前端渲染页面

  发现辅助数据 => 构建链接 => 下载并分析目标 AJAX

  对于不同的站点,这个辅助数据可能会提前在页面的HTML中输出,也可能是通过AJAX请求,甚至是多个数据请求的过程,但这种模式基本是固定的。

  但是这些数据请求的分析还是比页面分析复杂的多,所以这其实就是动态页面爬取的难点。

  本节的例子希望实现的是提供一个可以遵循的模式,供此类爬虫在分析请求后的编写,即发现辅助数据=>构建链接=>下载并分析目标AJAX模型。

  PS:

  WebMagic 0.5.0 将在链 API 中添加 Json 支持,您可以使用:

  page.getJson().jsonPath("$.name").get();

  这种方式来解析AJAX请求。

  还支持

  page.getJson().removePadding("callback").jsonPath("$.name").get();

  这种方式来解析 JSONP 请求。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线