背景
最近公司需要抓取中国农业信息网(http://jgsb.agri/controller?SERVICE_ID=REGISTRY_JCSJ_MRHQ_SHOW_SERVICE&recordperpage=15&newsearch=true&login_result_sign=nologin) 的数据。在 google 浏览器使用 F12 查看可以发现价格行情数据是嵌套在一个 flash 中的,点击下一页请求服务器,可以看到返回的数据格式是 application/x-amf ,浏览器无法正常解析该数据,接下来就需要用的抓包工具 charles(下载地址 : https://www.charlesproxy/download/) 了。
处理
运行抓包工具,在该页面点击 下一页,charles 中效果如图 :
可以看到比较重要的一些请求封装,然后就是使用 java 模拟 amf 请求了。
maven 依赖
<!-- https://mvnrepository/artifact/org.apache.flex.blazeds/flex-messaging-core -->
<dependency>
<groupId>org.apache.flex.blazeds</groupId>
<artifactId>flex-messaging-core</artifactId>
<version>4.7.2</version>
</dependency>
<!-- https://mvnrepository/artifact/org.apache.flex.blazeds/flex-messaging-common -->
<dependency>
<groupId>org.apache.flex.blazeds</groupId>
<artifactId>flex-messaging-common</artifactId>
<version>4.7.2</version>
</dependency>
封装请求
封装请求就是图中框起来的 content 部分。特别注意图中标红得两个包名,这里请求里面封装的包名必须对应起来。
com.itown.kas.pfsc.report.po.HqPara 对象 :
注意这里的包名必须和抓包里面的包名对应起来。
package com.itown.kas.pfsc.report.po;
import lombok.Data;
/**
* HqPara
*
* @author xh
* @date 2020/5/19
*/
@Data
public class HqPara {
private String breedInfoDl;
private String provice;
private String breedInfo;
private String marketInfo;
}
封装 content 数据 :
public static RemotingMessage getRemotingMessage() {
// content 数组中的第一个对象
RemotingMessage remotingMessage = new RemotingMessage();
// 对应对象里面的各个参数
remotingMessage.setSource(null);
remotingMessage.setOperation("getHqSearchData");
remotingMessage.setTimeToLive(0);
remotingMessage.setTimestamp(0);
Map<String, Object> headers = new HashMap<>();
headers.put("DSId", UUID.randomUUID().toString());
headers.put("DSEndpoint", null);
remotingMessage.setHeaders(headers);
// 对应对象里面的 body 对象
// 数组中的第一个元素 new HqPara() ==> 对应该网页的搜索数据
// 注意 HqPara 的包名必须对应起来,如果要搜索数据的话,在这个对象中 set 对应的值即可
// 数组的第二个参数表示当前页
// 数组的第三个参数表示每页大小
// 注意合理有个坑!!!
// 分页数据在请求中是字符串类型,这里也一定要用字符串类型,如果用 int 类型的话,结果是没有值的!!!!
Object[] body = new Object[]{new HqPara(), "1", "15"};
remotingMessage.setBody(body);
remotingMessage.setClientId(UUID.randomUUID().toString());
remotingMessage.setDestination("reportStatService");
remotingMessage.setMessageId(UUID.randomUUID().toString());
return remotingMessage;
}
返回数据
抓包返回数据大概如下:
需要的具体数据大概是这样的 :
编写代码
import com.itown.kas.pfsc.report.po.HqPara;
import flex.messaging.io.ArrayCollection;
import flex.messaging.io.amf.ASObject;
import flex.messaging.io.amf.client.AMFConnection;
import flex.messaging.messages.RemotingMessage;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* SwfApp3
*
* @author xh
* @date 2020/5/19
*/
public class SwfApp {
public static void main(String[] args) throws Exception {
String url = "http://jgsb.agri/messagebroker/amf";
RemotingMessage remotingMessage = getRemotingMessage();
AMFConnection connection = new AMFConnection();
connection.addHttpRequestHeader("Content-Type", "application/x-amf");
connection.connect(url);
connection.addAmfHeader("DSId", UUID.randomUUID().toString().replaceAll("-", ""));
// 这里必须和返回值的包名对应起来
// 这个包可以不用创建
AMFConnection.registerAlias("DSK", "com.itown.kas.pfsc.report.po.PAuditMarketPrice");
// call 方法的 command 对应请求中的 Target
Object call = connection.call(null, remotingMessage);
// 解析返回值
// flex.messaging.messages.AcknowledgeMessage
flex.messaging.messages.AcknowledgeMessage message = (flex.messaging.messages.AcknowledgeMessage) call;
ArrayCollection body = (ArrayCollection) message.getBody();
ArrayCollection data = (ArrayCollection) body.get(0);
for (Object column : data) {
ASObject asObject = (ASObject) column;
System.out.println(asObject);
}
Object curPage = body.get(1);
Object totalPage = body.get(2);
Object totalCount = body.get(3);
System.out.println(curPage + " == " + totalPage + " == " + totalCount);
}
public static RemotingMessage getRemotingMessage() {
// content 数组中的第一个对象
RemotingMessage remotingMessage = new RemotingMessage();
// 对应对象里面的各个参数
remotingMessage.setSource(null);
remotingMessage.setOperation("getHqSearchData");
remotingMessage.setTimeToLive(0);
remotingMessage.setTimestamp(0);
Map<String, Object> headers = new HashMap<>();
headers.put("DSId", UUID.randomUUID().toString());
headers.put("DSEndpoint", null);
remotingMessage.setHeaders(headers);
// 对应对象里面的 body 对象
// 数组中的第一个元素 new HqPara() ==> 对应该网页的搜索数据
// 注意 HqPara 的包名必须对应起来,如果要搜索数据的话,在这个对象中 set 对应的值即可
// 数组的第二个参数表示当前页
// 数组的第三个参数表示每页大小
// 注意合理有个坑!!!
// 分页数据在请求中是字符串类型,这里也一定要用字符串类型,如果用 int 类型的话,结果是没有值的!!!!
Object[] body = new Object[]{new HqPara(), "1", "15"};
remotingMessage.setBody(body);
remotingMessage.setClientId(UUID.randomUUID().toString());
remotingMessage.setDestination("reportStatService");
remotingMessage.setMessageId(UUID.randomUUID().toString());
return remotingMessage;
}
}
运行效果
更多推荐
java 爬取 flash 里面的数据
发布评论