爬取基於Flex技術的網站數據

參考:https://github.com/LouisYZK/ShiXi_inWuhan/tree/master/1.23python

Flex技術是網站運用flash方法與客戶端進行數據通訊,數據的格式能夠是txt,json或amf等。 
AMF是一種二進制編碼方式,其在flash傳輸效率高,以農業信息網數據爲例,爬取的方式與通常ajax分析相同。經過抓包分析請求頭和響應數據,而後構造請求、接受返回數據git

經過爬取全國農產品批發市場價格信息系統,獲取數據,可是此網站是經過flash展現數據,與如今大部分網站展現數據的方法不一樣,所以使用python下的pyamf來幫助咱們獲取數據。github

1.分析網頁

經過分析網頁,咱們獲得信息,此網站的data是在hqapp.swf中ajax

2.分析請求包json

目前Chales抓包工具可以支持將AMF編碼解析成明文形式,便於咱們分析。併發

經過chares抓包,咱們發現請求的body包含一個com.itown.kas.pfsc.report.po.HqPara對象和四個參數,結合網頁可知爲flash上的四個選擇菜單,能夠選擇省份和批發市場名稱等。app

 

class HqPara:
    def __init__(self):
        self.marketInfo = None
        self.breedInfoDl = None
        self.breedInfo = None
        self.provice = None
# 第一個是查詢參數,第二個是頁數,第三個是控制每頁顯示的數量(默認每頁只顯示15條)但爬取的時候能夠一會兒設置成所有的數量
# 構造請求數據
def getRequestData(page_num,total_num):
    # 註冊自定義的Body參數類型,這樣數據類型com.itown.kas.pfsc.report.po.HqPara就會在後面被一併發給服務端(不然服務端就可能返回參數不是預期的異常Client.Message.Deserialize.InvalidType)
    pyamf.register_class(HqPara, alias='com.itown.kas.pfsc.report.po.HqPara')
    # 構造flex.messaging.messages.RemotingMessage消息
    msg = messaging.RemotingMessage(messageId=str(uuid.uuid1()).upper(),
                                    clientId=str(uuid.uuid1()).upper(),
                                    operation='getHqSearchData',
                                    destination='reportStatService',
                                    timeToLive=0,
                                    timestamp=0)
    msg.body = [HqPara(),str(page_num), str(total_num)]
    msg.headers['DSEndpoint'] = None
    msg.headers['DSId'] = str(uuid.uuid1()).upper()
    # 按AMF協議編碼數據
    req = remoting.Request('null', body=(msg,))
    env = remoting.Envelope(amfVersion=pyamf.AMF3)
    env.bodies = [('/1', req)]
    data = bytes(remoting.encode(env).read())
    return data
# 返回一個請求的數據格式

2.分析response

能夠看到返回的response中,包含有全部記錄條數ide

def getResponse(data):
    url = 'http://jgsb.agri.cn/messagebroker/amf'
    req = Request(url, data, headers={'Content-Type': 'application/x-amf'})
    # 解析返回數據
    opener = urllib2.build_opener()
    return opener.open(req).read()

def getContent(response):
    amf_parse_info = remoting.decode(response)
    # 數據總條數
    total_num = amf_parse_info.bodies[0][1].body.body[3]
    info = amf_parse_info.bodies[0][1].body.body[0]
    return total_num, info

3.解析和存儲

def storagejson(info):
    path='info.json'
    path1='E:\spyderdata\\'
    res = []
    for record in info:
        record['reportDate'] = record['reportDate'].strftime('%Y-%m-%d %H:%M:%S')
        record['auditDate'] = record['auditDate'].strftime('%Y-%m-%d %H:%M:%S')
        record['snatchDate'] = 'null'
        res.append(record)
    fp = open(path,'w',encoding='utf-8')
    json.dump(res,fp,indent=4,ensure_ascii= False)
    fp.close()
    os.rename(path,path1+filename+path)

if __name__ == '__main__':
    filename = time.strftime("%Y-%m-%d", time.localtime())
    # 第一次請求時,獲取數據量
    reqData = getRequestData(1,2)
    rep = getResponse(reqData)
    total_num,info = getContent(rep)
    # 一次請求完成
    reqData = getRequestData(1, total_num)
    rep = getResponse(reqData)
    total_num,info = getContent(rep)
    storagejson(info)

全部代碼

from urllib import request as urllib2
from urllib.request import Request
import uuid
import pyamf
import json
import time
import os
from pyamf import remoting
from pyamf.flex import messaging

class HqPara:
    def __init__(self):
        self.marketInfo = None
        self.breedInfoDl = None
        self.breedInfo = None
        self.provice = None
# 第一個是查詢參數,第二個是頁數,第三個是控制每頁顯示的數量(默認每頁只顯示15條)但爬取的時候能夠一會兒設置成所有的數量
# 構造請求數據
def getRequestData(page_num,total_num):
    # 註冊自定義的Body參數類型,這樣數據類型com.itown.kas.pfsc.report.po.HqPara就會在後面被一併發給服務端(不然服務端就可能返回參數不是預期的異常Client.Message.Deserialize.InvalidType)
    pyamf.register_class(HqPara, alias='com.itown.kas.pfsc.report.po.HqPara')
    # 構造flex.messaging.messages.RemotingMessage消息
    msg = messaging.RemotingMessage(messageId=str(uuid.uuid1()).upper(),
                                    clientId=str(uuid.uuid1()).upper(),
                                    operation='getHqSearchData',
                                    destination='reportStatService',
                                    timeToLive=0,
                                    timestamp=0)
    msg.body = [HqPara(),str(page_num), str(total_num)]
    msg.headers['DSEndpoint'] = None
    msg.headers['DSId'] = str(uuid.uuid1()).upper()
    # 按AMF協議編碼數據
    req = remoting.Request('null', body=(msg,))
    env = remoting.Envelope(amfVersion=pyamf.AMF3)
    env.bodies = [('/1', req)]
    data = bytes(remoting.encode(env).read())
    return data
# 返回一個請求的數據格式

def getResponse(data):
    url = 'http://jgsb.agri.cn/messagebroker/amf'
    req = Request(url, data, headers={'Content-Type': 'application/x-amf'})
    # 解析返回數據
    opener = urllib2.build_opener()
    return opener.open(req).read()

def getContent(response):
    amf_parse_info = remoting.decode(response)
    # 數據總條數
    total_num = amf_parse_info.bodies[0][1].body.body[3]
    info = amf_parse_info.bodies[0][1].body.body[0]
    return total_num, info

def storagejson(info):
    path='info.json'
    path1='E:\spyderdata\\'
    res = []
    for record in info:
        record['reportDate'] = record['reportDate'].strftime('%Y-%m-%d %H:%M:%S')
        record['auditDate'] = record['auditDate'].strftime('%Y-%m-%d %H:%M:%S')
        record['snatchDate'] = 'null'
        res.append(record)
    fp = open(path,'w',encoding='utf-8')
    json.dump(res,fp,indent=4,ensure_ascii= False)
    fp.close()
    os.rename(path,path1+filename+path)

if __name__ == '__main__':
    filename = time.strftime("%Y-%m-%d", time.localtime())
    # 第一次請求時,獲取數據量
    reqData = getRequestData(1,2)
    rep = getResponse(reqData)
    total_num,info = getContent(rep)
    # 一次請求完成
    reqData = getRequestData(1, total_num)
    rep = getResponse(reqData)
    total_num,info = getContent(rep)
    storagejson(info)
View Code

 

遇到的問題:

1.pyamf工具

這次爬蟲要用到python的pyamf庫,anaconda中並無這個庫,所以得本身下載,經過查詢得知能夠經過pip安裝flex

pip install PyAMF

可是安裝過程出現錯誤,沒法安裝,因而經過下載源文件,解壓到  python安裝目錄\Lib\site-packages下,更名爲pamf,在pycharm中導入pyamf,便可使用。

網上搜索時,有人說pyamf不支持python3,須要替換爲Py3AMF,可是實測pyamf在python3能夠運行爬蟲。

相關文章
相關標籤/搜索