最近在做一个旅游类的网站,在使用爬虫时,发现某程网站上某一个景点的用户评论这部分数据是通过Ajax异步请求动态加载的,首先通过Chrome跟踪异步请求,发现有两次请求,
前一次请求方法的OPTION,后一次请求才是POST而且返回目标数据,不过两次请求的url是一样的,直接在地址栏输入url返回的是没有用户评论信息的json格式的数据,
这说明某程服务器并没有接收到可用的参数,比如页数、页大小等等,因此返回空的json数据。而且这个ur有且只有一个参数,并且不随页数的改变而改变,url始终唯一,那某程服务器如何确定返回哪一页的数据呢?
琢磨很久发现后一次请求的头部比前一次的增加了一个称为Request Payload(请求负载)的数据,里边存放了页数、页大小等数据,以json格式随着post请求发送出去,服务器才返回响应的数据。
至于什么是Request Payload?它就是一种实现Ajax异步请求中存放传输数据的方式之一,另一种是Form Data即以表单提交的方式,携带的数据通过url参数的方式传输,但是这不是安全的,这就是为什么上面提到的不管我们查询哪一页的评论,异步请求的url都没有改变,其实Request Payload存放了页数、页大小等数据的原因。概念参考此文章。
接下来,只要模拟POST请求,在头部添加Request Payload属性,应该能返回数据。如何模拟?我选择了Jsoup,当然也可以用okhttp。现在的项目是基于webmagic框架来实现,虽然它基于Jsoup但是不提供相应的接口,所有要独立于webmagic使用Jsoup爬取用户评论这部分数据。
首先,查看POST请求头的属性:content-type、cookie、referer、sec-fetch-mode、sec-fetch-site等,
为postConnection添加以上请求头,然后发起请求,实例代码:
String url = "https://sec-m.ctrip.com/restapi/soa2/12530/json/viewCommentList?_fxpcqlniredt=09031094411358401742";
int pagenum = 10;
int pagesize = 10;
String jsonBody = "{\"pageid\":10650000804,\"viewid\":2888,\"tagid\":0,\"pagenum\":" + pagenum + ",\"pagesize\":10" + pagesize + ",\"contentType\":\"json\",\"head\":{\"appid\":\"100013776\",\"cid\":\"09031176211061113479\",\"ctok\":\"\",\"cver\":\"1.0\",\"lang\":\"01\",\"sid\":\"8888\",\"syscode\":\"09\",\"auth\":\"\",\&