python爬取flash頁面的返回數據(flex技術、amf格式、charles抓包)

flash頁面的返回數據,無法從網頁源代碼中查看到數據,這種頁面的爬取需要藉助一個工具——charles,通過它來查看amf。
這裏用到一個第三方庫pyamf,安裝方式:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple py3amf

本文以浙江省地表水水質自動監測數據爲例,爬取浙江省所有監測點的五項水質實時信息,講述這種傳統flash頁面數據的爬取過程和注意事項。

一、分析網頁

瀏覽器查看

下面是這個網站的頁面和源代碼(注意圈出來的部分):
在這裏插入圖片描述
瀏覽器無法查看到我們需要的數據,接下來我們需要藉助charles。

charles查看

打開charles(具體使用方法請自行百度),找到amf(注意第三個):在這裏插入圖片描述

查看amfWms(GISCommonDataUtilForWms.getAllValleyVo,GISCommonDataUtilForWms.getAllShowHourData,GISCommonDataUtilForWms.getAllSiteHistoryVo):

request(有3個,數據在body[1],仔細查看,我們需要模擬請求):在這裏插入圖片描述
response(仔細查看,可以把這裏看作我們定製返回參數的模板,返回哪個參數就複製其‘鍵名‘):

在這裏插入圖片描述

二、代碼

# coding: utf-8
# http://wms.zjemc.org.cn/wms/wmsflex/index.html
import datetime
import pandas as pd
import urllib
import urllib.request as urllib2
from urllib.request import Request
import requests
import uuid
import pyamf
import json,datetime
from pyamf import remoting
from pyamf.flex import messaging
import re
import time
import csv

# 構造請求數據
def getRequestData():
    msg.body = []
    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://wms.zjemc.org.cn/wms/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)
    info = amf_parse_info.bodies[0][1].body.body 
    res=[]
    for record in info:
    	red = [record['mtName'],\
    	record['monitorTime'],\
    	record['boundaryArea'],\
    	record['factorValues'],\
    	record['factorLevel'],\
    	]
    	res.append(red)  		            
    return res

def printWaterList(ilt):
    tplt = "{0:20}\t{1:20}\t{2:20}\t{3:20}\t{4:20}"
    print(tplt.format("監測點","監測時間","監測點所屬地區","PH值、DO濃度(mg/l)、CODmn濃度(mg/l)、TP濃度(mg/l)、NH3-N濃度(mg/l)","PH值(級別)、DO濃度(級別)、CODmn濃度(級別)、TP濃度(級別)、NH3-N濃度(級別)"))
    output_list=["監測點","監測時間","監測點所屬地區","PH值、DO濃度(mg/l)、CODmn濃度(mg/l)、TP濃度(mg/l)、NH3-N濃度(mg/l)","PH值(級別)、DO濃度(級別)、CODmn濃度(級別)、TP濃度(級別)、NH3-N濃度(級別)"]
    #存儲路徑需根據需要更改
    data_str = datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S')
    with open("E:/python/浙江省地表水水質自動監測/%s_國家地表水水質自動監測系統檢測數據.csv" % (data_str),"a+",encoding='GB18030',newline='') as csvfile:
        	w=csv.writer(csvfile)
        	w.writerow(output_list)
        	csvfile.close()
    time.sleep(3)
    for g in ilt:   
        out_putlist=[g[0],g[1],g[2],g[3],g[4]]
        print(out_putlist)
        time.sleep(1)#可省略,每打印一條,停一秒,再打印下一個
         #存儲路徑需根據需要更改
        with open("E:/python/浙江省地表水水質自動監測/%s_國家地表水水質自動監測系統檢測數據.csv" % (data_str),"a+",encoding='GB18030',newline='') as csvfile:
        	w=csv.writer(csvfile)
        	w.writerow(out_putlist)
        	csvfile.close()

class WmsHourDataVo:
    def __init__(self):
        None
        
pyamf.register_class(WmsHourDataVo, alias='com.fpi.prj.zjemc.airenv.wms.entity.vo')
msg = messaging.RemotingMessage(messageId=str(uuid.uuid1()).upper(),
                                    clientId=str(uuid.uuid1()).upper(),
                                  operation='getAllShowHourData',#getAllValleyVo\getAllSiteHistoryVo
                                    destination ='GISCommonDataUtilForWms',
                                    timeToLive=0,
                                    timestamp=0,)

reqData = getRequestData()
rep = getResponse(reqData)
info = getContent(rep)
# 一次請求完成
reqData = getRequestData()
rep = getResponse(reqData)
res = getContent(rep)
printWaterList(res)

三、運行代碼

運行:在這裏插入圖片描述

保存數據(178條數據,其中80條爲國家監測點,爲空):
在這裏插入圖片描述

四、後記

1、使用charles抓包工具時,要仔細查看request和response兩個標籤;
2、這個網站的amfwms有三個,篩選後,發現數據在第三個,第三個amfwms的body也有三個(body[0]、body[1]、body[2]),篩選後發現數據在body[1],只用模擬請求它即可;
3、關鍵在於這兩個值:

operation='getAllShowHourData',#getAllValleyVo\getAllSiteHistoryVo
destination ='GISCommonDataUtilForWms',
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章