本次抓取地址:http://www.iconfont.cn/ 项目源码:https://github.com/geekfly2016/Spider 代码目录:Spider/src/xyz/geekfly/get_list/IconFont.Java
本篇继上述博客,介绍Ajax无刷新加载数据的方式,抓取阿里巴巴矢量图库。 技术重点:
(由于此处需要模拟Post请求,并且包含请求头信息和参数,Jsoup已经无法满足需求,其主要适用于数据解析,故此代码使用HttpClient模拟请求) 上述技术请自行学习,此处指包括使用。 本代码以来多个Jar包,已更新在Lib中。
打开目标网页,输入Java关键字,打开Chrome的开发者工具,点击页码,看到如下请求:
General中数据如下:
Request URL:http://www.iconfont.cn/api/icon/search.json
Request Method:POST
Status Code:200 OK
Remote Address:140.205.34.99:80
Referrer Policy:no-referrer-when-downgrade
分析: 加载数据的Url为:http://www.iconfont.cn/api/icon/search.json 请求方式:Post
请求头(Request Header)中数据如下(Cookie数据过长,有删减):
Accept:application/json, text/javascript, */*; q=0.01
Accept-Encoding:gzip, deflate
Accept-Language:zh-CN,en-US;q=0.8,en;q=0.6,zh;q=0.4
Connection:keep-alive
Content-Length:98
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
Cookie:UM_distinctoDITj
Host:www.iconfont.cn
Origin:http://www.iconfont.cn
Referer:http://www.iconfont.cn/search/index?q=java&page=1
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36
X-Requested-With:XMLHttpRequest
在模拟请求中,一般使用到的参数有: Cookie,Host,Referer。 User-Agent就不用说了,这个是必须的。 所以下文代码中使用的参数,就是在浏览器里面直接拷贝的上述值。
和网站的安全机制有关,若发现请求获取不到数据,或返回错误的数据时,需考虑参数问题,先尝试把必须添加的参数加上,如果不行再继续添加其他参数,不断尝试可以获取正常的数据为止。 (个人比较懒,最开始不加参数,不能获取数据在添加,或者你也可以每个网站都加上所有的参数)
请求参数:
q:java
sortType:updated_at
page:1
pageSize:54
t:1502713725794
ctoken:bL67K02mQl16IlJizxgeicon-font
请求参数一般需要全部添加
HttpClient httpClient = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
设置Request header
```
//以下参数因不同网站安全监测机制不同,所要求带的参数也不尽相同
post.setHeader("Content-Type", "application/json;charset=UTF-8");
post.setHeader("Host", "www.iconfont.cn");
post.setHeader("Cookie", "UM_distinctid=15d5d87f8534ugkekhk9Vw");
post.setHeader("Referer","http://www.iconfont.cn/search/index?q=java&page=2");
post.setHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
```
设置Data
```
List<NameValuePair> params = new ArrayList<NameValuePair>();
//变化参数
params.add(new BasicNameValuePair("page", String.valueOf(page_number))); //传入页码
params.add(new BasicNameValuePair("q", "java")); //检索关键字
//固定参数
params.add(new BasicNameValuePair("cityEname", "henan"));
params.add(new BasicNameValuePair("sortType", "updated_at"));
params.add(new BasicNameValuePair("pageSize", "54")); //每页条数 54
params.add(new BasicNameValuePair("t", String.valueOf(new Date().getTime()))); //当前时间戳 1502713082550
params.add(new BasicNameValuePair("ctoken", "bL67K02mQl16IlJizxgeicon-font"));
post.setEntity(new UrlEncodedFormEntity(params,Consts.UTF_8));
```
获取Entity
HttpResponse response = httpClient.execute(post);
int statusCode = response.getStatusLine().getStatusCode();
if(statusCode != 200){
System.out.print(statusCode);
return null;
}
HttpEntity entity = response.getEntity();
String result = null;
if (entity != null) {
result = EntityUtils.toString(entity, "utf-8");
}
EntityUtils.consume(entity);
return result;
初始化参数和构造循环体
String url = "http://www.iconfont.cn/api/icon/search.json";
String keyword = "java"; //查询条件
Integer page_number = 1; //起始页数
while(true){
String json = Post(url, page_number);
Map<String, Object> data = JsonUtil.JsonToMap(json);
//解析数据
}
解析返回数据
查看是否出错
if(data.isEmpty() || Integer.parseInt(data.get("code").toString()) != 200){
System.out.println("获取第" + page_number + "页数据出错!!");
break;
}
获取键值对
//上述结构的一个data键所对应的值
Map<String, Object> data_key = (Map<String, Object>) data.get("data");
//data中的icons键所对应的值
List<Map<String, Object>> icons = (List<Map<String, Object>>) data_key.get("icons");
处理数据
//{data={"count":103,"icons":[]}, code=200}
if(icons.isEmpty()){
System.out.println("结束,共计:" + data_key.get("count"));
break;
}else{
for(Map<String, Object> icon: icons){
//可以在此处进行数据解析
System.out.println(icon);
//可根据icon.get("")方式获取各个值
}
System.out.println("第" + page_number + "页,数据:" + icons.size() + "条数据");
page_number++; //继续下一页
}
输出
第1页,数据:54条数据
第2页,数据:49条数据
结束,共计:103
翻页系列到此结束,接下来更新模拟登录。