现在js渲染出的页面越来越多。对于爬虫来说,这种页面是比较讨厌的:仅仅提取HTML内容,往往无法拿到有效的信息。
两种做法:
- 在抓取阶段,在爬虫中内置一个浏览器内核,执行js渲染页面后,再抓取。这方面对应的工具有
Selenium
、HtmlUnit
或者PhantomJs
。但是这些工具都存在一定的效率问题,同时也不是那么稳定。好处是编写规则同静态页面一样。 - 因为js渲染页面的数据也是从后端拿到,而且基本上都是AJAX获取,所以分析AJAX请求,找到对应数据的请求,也是比较可行的做法。而且相对于页面样式,这种接口变化可能性更小。缺点就是找到这个请求,并进行模拟,是一个相对困难的过程,也需要相对多的分析经验。
一、使用Google浏览器,获取ajax请求格式与路径
1、F12打开调试工具,然后重新刷新页面;
2、查找ajax请求学习-----选中“Network”,所有的交互记录都在“ALL”中,快速定位可以在“XHR”和“JS”中查找;
3、根据数据大小来判断一下,一般结果体积较大的更有可能是返回数据的接口。剩下的,基本靠经验了。
二、获取ajax请求结果,并处理
1、ajax请求地址
String list_url="http://api.slide.news.sina.com.cn/interface/api_album_choice.php.*";
2、匹配地址,获取返回结果 getRawText
if (page.getUrl().regex(list_url).match()) {
//获取返回的Json
String json = page.getRawText();
//这里我们使用JSONPATH这种选择语言来选择数据
List<String> ids = new JsonPathSelector("$.data[*]._id").selectList(page.getRawText());
if (CollectionUtils.isNotEmpty(ids)) {
for (String id : ids) {
page.addTargetRequest("http://angularjs.cn/api/article/"+id);
}
}
}
3、解析数据:JsonPathSelector
page.getRawText()的结果必须满足 json 格式,不满足手动拼接或删除
$:json解析的起始,按照层级结果,通过“.”逐级获取
如果是JSONArray结构JsonPathSelector."$[i].title".select(json);
如果是JsonObject结果JsonPathSelector."$.data[i].title".select(json);
//不满足格式,手动处理
String str=text.substring(json.indexOf("{"),json.lastIndexOf("}")+1);//截取json格式数据
//JSONArray
String talstid=new JsonPathSelector("$["+i+"].tlastid").select(page.getRawText());
//JSONObject
List<String> ids=new JsonPathSelector("$.data[*].id").selectList(str);
//获取List
List<String> ids=new JsonPathSelector("$.data[*].id").selectList(str);
//获取String
String url=new JsonPathSelector("$.data["+i+"].url").select(str);
//批量获取二级下面的List,用[*]
List<String> keyword=new JsonPathSelector("$["+i+"].keywords[*].keyname").selectList(page.getRawText());