js 爬虫抓取网页数据(AngularJSjs渲染出的页面越来越多如何判断前端渲染页面)

优采云 发布时间: 2022-03-25 05:28

  js 爬虫抓取网页数据(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应该是我们想要的帖子的id,帖子详情请求由一些固定的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人工客服


线