java 爬取 flash 里面的数据

背景

最近公司需要抓取中国农业信息网(http://jgsb.agri.cn/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.com/download/) 了。

处理

运行抓包工具,在该页面点击 下一页,charles 中效果如图 :

java 爬取 flash 里面的数据_第1张图片

可以看到比较重要的一些请求封装,然后就是使用 java 模拟 amf 请求了。

maven 依赖

        
        
            org.apache.flex.blazeds
            flex-messaging-core
            4.7.2
        
        
        
            org.apache.flex.blazeds
            flex-messaging-common
            4.7.2
        

封装请求

封装请求就是图中框起来的 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 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 里面的数据_第2张图片

需要的具体数据大概是这样的 :

java 爬取 flash 里面的数据_第3张图片

编写代码

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.cn/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 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 里面的数据_第4张图片

你可能感兴趣的:(java)