背景说明
按项目经理的要求,需要导出阿里云物联网平台上所有设备的物模型数据到Excel上,方便后台导入、给客户演示和备份。但是,阿里云物联网平台没有这个功能,手动一个个处理不现实,因此只能写一个爬虫爬取所有数据,然后再导出excel。
步骤
1、分析请求URL
获取该功能的所有XHR请求,挨个寻找到返回物模型数据的请求。
找到对应的URL后,分析其参数,主要是确定遍历条件和鉴权参数等,判断是否能够做爬虫爬取数据。
2、postman测试一下
URL的参数分析完成后,如果确定能够做爬虫爬取数据,则可以继续往下写爬虫程序。此时,先不急着写开发程序,先用postman看下该URL是否做了其他拦截处理。
postman上填好参数,特别要注意token和cookie之类的鉴权参数,测试是否能拿到数据,同时验证上面关于参数的猜想是否成立。如果遇到问题,则需要根据其返回值做响应的处理。
只有postman能拿到数据,才能用程序爬取数据。如果一切顺利,处理完成之后,就可以编写爬取程序了。
3、编写一个简单的Java爬虫
Controller 层
/**
* 导出阿里云物联网平台所有设备的物模型数据
**/
@GetMapping("aliyun/insertExcelOut")
public String insertExcelOut(ModelMap modelMap, Map para) {
List<ExcelExportEntity> entityList = new ArrayList<>();
ExcelExportEntity xh = new ExcelExportEntity("序号", "nu", 10);
xh.setFormat("isAddIndex");
entityList.add(xh);
entityList.add(new ExcelExportEntity("设备名称", "deviceCode", 20));
entityList.add(new ExcelExportEntity("信号强度", "CSQ", 20));
entityList.add(new ExcelExportEntity("设备硬件版本", "HW", 20));
entityList.add(new ExcelExportEntity("设备标识符", "IMEI", 20));
entityList.add(new ExcelExportEntity("设备SIM卡号", "SIM", 20));
entityList.add(new ExcelExportEntity("设备软件版本", "SW", 20));
entityList.add(new ExcelExportEntity("最大距离", "DisMax", 20));
entityList.add(new ExcelExportEntity("采样频率", "SampRate", 20));
entityList.add(new ExcelExportEntity("最小距离", "DisMin", 20));
entityList.add(new ExcelExportEntity("进出方向", "DirConf", 20));
entityList.add(new ExcelExportEntity("环境湿度", "humi", 20));
entityList.add(new ExcelExportEntity("环境湿度F", "humi_f", 20));
entityList.add(new ExcelExportEntity("环境温度", "temp", 20));
entityList.add(new ExcelExportEntity("环境温度F", "temp_f", 20));
entityList.add(new ExcelExportEntity("反向人数_出", "neg", 20));
entityList.add(new ExcelExportEntity("正向人数_进", "pos", 20));
entityList.add(new ExcelExportEntity("地理位置", "GeoLocation", 20));
List dataResult = aliyunService.insertExcelOut();
modelMap.put(MapExcelConstants.ENTITY_LIST, entityList);
modelMap.put(MapExcelConstants.MAP_LIST, dataResult);
modelMap.put(MapExcelConstants.FILE_NAME, "阿里云设备物理模型");
modelMap.put(NormalExcelConstants.PARAMS, new ExportParams("阿里云设备物理模型", "阿里云设备物理模型"));
return MapExcelConstants.EASYPOI_MAP_EXCEL_VIEW;
}
Service 层
/**
* 爬取阿里云物联网平台设备的物模型数据,业务逻辑主要在这里
**/
@Override
public List<Map> insertExcelOut() {
// 请求URL
String URL = "https://iot.console.aliyun.com/data/api.json";
// 返回的list
List dataList = new ArrayList();
// header参数
Map header = new HashMap();
header.put("cookie", "cna=5555555555555555");
// 请求参数
Map params = new HashMap();
params.put("action", "QueryDevicePropertyStatus");
params.put("product", "iot");
params.put("region", "cn-shanghai");
params.put("sec_token", "777777777777777777");
params.put("umid", "888888888888888888");
params.put("collina", "9999999999999==");
for(int i=0; i<501; i++){
// 拼接设备的唯一标识
String deviceCode = "IR" + String.format("%3d", i).replace(" ", "0");
// 传入参数中
params.put("params", "{\"RegionId\":\"cn-shanghai\",\"ProductKey\":\"3333333333\",\"DeviceName\":\""+deviceCode+"\"}");
try {
// 拿到设备的物模型数据,并转成json
String data = HttpUtils.doPost(URL, params, header);
System.out.println("============== "+deviceCode);
JSONObject json = JSON.parseObject(data);
System.out.println(json.toJSONString());
// 单个设备的物模型数据转换成map
Map dataMap = new HashMap();
// 保存设备名称
dataMap.put("deviceCode", deviceCode);
// 根据其返回的数据,做具体的业务逻辑,需要梳理清楚我们要的数据和其返回结果的的层级关系,并解析
JSONArray jsonArray = json.getJSONObject("data").getJSONObject("Data").getJSONObject("List").getJSONArray("PropertyStatusInfo");
for(int index = 0; index < jsonArray.size(); index++) {
JSONObject aJson = jsonArray.getJSONObject(index);
String key = aJson.getString("Identifier"); // 拿到参数key
String value = aJson.getString("Value"); // 参数值
String unit = aJson.containsKey("Unit") ? " "+aJson.getString("Unit") : ""; // 参数单位,判断是否有
dataMap.put(key, value+unit);
}
// 添加到list中
dataList.add(dataMap);
} catch (Exception e) {
System.out.println("========= 程序错误,拉取阿里云数据失败");
e.printStackTrace();
continue;
}
}
return dataList;
}
注意:有些URL有反爬虫的拦截过滤机制,对于不会影响结果的参数,可以选择拼接随机字符串,以避免拦截,不过,还是应具体问题具体分析。
阿里云的部分URL还存在请求时间拦截机制,即如果两个url相同参数不同的请求,时间间隔过短,会被拦截过滤,因此,必要情况下还应当设置线程休眠时间(sleep),适当延长爬取间隔。
4、测试
启动项目,访问 localhost:8080/aliyunTest/aliyun/insertExcelOut,即可得到导出的excel。