现在js渲染出的页面越来越多。对于爬虫来说,这种页面是比较讨厌的:仅仅提取HTML内容,往往无法拿到有效的信息。

两种做法:

  1. 在抓取阶段,在爬虫中内置一个浏览器内核,执行js渲染页面后,再抓取。这方面对应的工具有SeleniumHtmlUnit或者PhantomJs。但是这些工具都存在一定的效率问题,同时也不是那么稳定。好处是编写规则同静态页面一样。
  2. 因为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());