python利用requests庫模擬post請求時json的使用

来源:https://www.cnblogs.com/new-june/archive/2018/12/06/10079800.html
-Advertisement-
Play Games

我們都見識過requests庫在靜態網頁的爬取上展現的威力,我們日常見得最多的為get和post請求,他們最大的區別在於安全性上: 1、GET是通過URL方式請求,可以直接看到,明文傳輸。 2、POST是通過請求header請求,可以開發者工具或者抓包可以看到,同樣也是明文的。 3.GET請求會保存 ...


  我們都見識過requests庫在靜態網頁的爬取上展現的威力,我們日常見得最多的為get和post請求,他們最大的區別在於安全性上:

1、GET是通過URL方式請求,可以直接看到,明文傳輸。

2、POST是通過請求header請求,可以開發者工具或者抓包可以看到,同樣也是明文的。 3.GET請求會保存在瀏覽器歷史紀錄中,還可能會保存在Web的日誌中。

  兩者用法上也有顯著差異(援引自知乎):

1、GET用於從伺服器端獲取數據,包括靜態資源(HTML|JS|CSS|Image等等)、動態數據展示(列表數據、詳情數據等等)。

2、POST用於向伺服器提交數據,比如增刪改數據,提交一個表單新建一個用戶、或修改一個用戶等。

對於Post請求,我們可以通過瀏覽器開發者工具或者其他外部工具來進行抓包,得到請求的URL、請求頭(request headers)以及請求的表單data信息,這三樣恰恰是我們用requests模擬post請求時需要的,典型的寫法如下:

  response=requests.post(url=url,headers=headers,data=data_search)     由於post請求很多時候是配合Ajax(非同步載入)技術一起使用的,我們抓包時,可以直接選擇XHR(XmlHttpRequest)-ajax的一種對象,幫助我們濾掉其他的一些html、css、js類文件,如下圖所示(截取自Chrome):  

雙擊點開,就可以在頁面右邊的Headers頁下看到General、Response Headers、Request Headers、Form Data幾個模塊,

其中General模塊能看到請求的方法和請求的URL以及伺服器返回的狀態碼(200(成功) 伺服器已成功處理了請求。通常,這表示伺服器提供了請求的網頁。

而Response Headers部分,可以看到緩存控制、伺服器類型、返回內容格式、有效期等參數(筆者截圖所示,返回的為json文件):

Request Header模塊是非常重要的,可以有效地將我們的爬取行為模擬成瀏覽器行為,應對常規的伺服器反爬機制:

其中Content-Type、Cookie以及User-Agent欄位較為重要,需要我們構造出來(其他欄位大多數時候,不是必須)

 

由於Cookie欄位記錄了用戶的登陸信息,每次都不同,且同一個cookie存在一定有效期,當我們結合Selenium來組合爬取頁面信息時,可以通過selenium完成網頁的登陸校驗,然後利用selenium提取出cookie,再轉換為瀏覽器能識別的cookie格式,通常代碼如下所示:

cookies = driver.get_cookies() #利用selenium原生方法得到cookies
ret=''
for cookie in cookies:
    cookie_name=cookie['name']
    cookie_value=cookie['value']
    ret=ret+cookie_name+'='+cookie_value+';' #ret即為最終的cookie,各cookie以“;”相隔開

緊接著,我們需要構造headers部分(即請求頭),我們挑重點的幾個欄位進行構造:

headers={
    'Host':'**********.com',
    'Referer':'http://****************/check/index.do',
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
    'X-Requested-With':'XMLHttpRequest',
    'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
    'Cookie':ret  #需要登陸後捕獲cookie並調用
}

我們在網頁中點擊“確定”按鈕,網頁則會非同步載入,後臺發出post請求,取到json文件並渲染到網頁表單中,比如我們根據需求填寫了部分欄位(這些就是我們post請求的data信息),然後觀察後臺的form data信息:

後臺Form data 捕獲到的data參數如圖:

 

類似於字典格式,其中condition鍵對應的value較為複雜——列表中包含字典,字典中還有部分函數,其中字元串中既有單引號又有雙引號交錯。屬於關鍵信息,page決定了網頁的翻頁在第幾頁,而rows則表示每次請求的數據限定的最大行數。

本例中問題的關鍵是,如何把想要的信息(譬如來源於excel配置文件)傳遞到condition欄位對應的值內,確保Form data信息靈活可配置,大抵用法如下:

data_search={
    'page':1,
    'rows':15,
    'condition':
    """[\
        {"column":"BPM_DEF_NAME","exp":"like","value":""},\
        {"column":"DELETE_STATUS","exp":"=","value":0},\
        {"column":"TO_CHAR(TO_DATE(CREATE_DATE,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD')","exp":">=","value":"YYYY-MM-DD"},\
        {"column":"TO_CHAR(TO_DATE(CREATE_DATE,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD')","exp":"<=","value":"YYYY-MM-DD"},\
        {"column":"CHECK_TYPE","exp":"like","value":"2"},\
        {"column":"LOCKED_STATUS","exp":"=","value":0},\
        {"column":"DELETE_STATUS","orderType":"default","orderKey":"","direction":"ASC"}\
    ]""",   #考慮到該欄位已經有單引號、雙引號,所以只能用三引號來包住這部分代表字元串
    'additionalParams':'{}'
}
data_search_condition=json.loads(data_search['condition'])    #將字元串轉為列表,方便更新列表(列表中每個元素都是一個單個字典)元素
#刷新字典
data_search_condition[0]['value']=businessName
data_search_condition[2]['value']=str(startDate)
data_search_condition[3]['value']=str(endDate)
data_search['condition']=json.dumps(data_search_condition)  #將列表重新轉回字元串,作為data_search字典中鍵“condition”對應的“value”,然後更新字典

上述代碼中,data_search其實為字典對象,其鍵“condition”對應的值(三引號包住部分)為字元串,本質是json格式,我們如何對這部分動態傳參呢?

這裡需要用到python json包中常用的loads和dumps方法:

1、json.loads()是將json格式對象,轉化Python可識別的字典對象。解碼python json格式,可以用這個模塊的json.loads()函數的解析方法。

2、json.dumps()是將一個Python數據類型列表進行json格式的編碼解析,可以將一個list列表對象,進行了json格式的編碼轉換。

3、json.dump和json.dumps很不同,json.dump主要用來json文件讀寫,和json.load函數配合使用。

上面實例中,就是將data_search['condition'](json,字元串)轉換為列表,然後根據列表定位到底層的每個dict字典,最後根據dict[Key]=value的方法進行更新(傳參),更新完之後的列表,再通過json.dumps反向轉回字元串,這樣整個data_search字典中參數就可以靈活配置,通過外部引入了。

 

剩下的工作就很簡單,交給強大的Requests包完成就好,示例代碼如下:

def get_page(data_search,url): #定義頁面解析的函數,返回值為json格式
    try:
        response=requests.post(url=url,headers=headers,data=data_search)
        if response.status_code==200:
            return response.json()
    except requests.ConnectionError as e:
        print('Error',e.args)

我們還可以把json格式內容存到本地(data.json)格式文件或者txt文本,並按照特定縮進(indent=4)進行規則排版,格式化內容,此時要用到json.dump()方法,示例代碼如下:

for pageNum in range(1,1000):
    data_search['page']=str(pageNum)
    pageContent=get_page(data_search=data_search,url=url)
    with open('data.json','w',encoding="utf-8") as json_file:
        json.dump(pageContent,json_file,ensure_ascii = False,indent=4)
    if pageContent==None:
        print("無符合條件的單據!") 
        time.sleep(3)
        sys.exit(0)

格式化後的json看上去直觀不少:

 

   最後感慨一句:爬蟲是門技術活,任何一個技術理解地不夠透徹,碰到複雜的問題,可能就要花上很長時間去試錯,譬如本文示例中的字典、json包幾個功能的使用,稍微出錯,就無法請求到對的數據!

PS:特別強調一點,有的時候requests.post()方法中data欄位不填或者填寫有誤,伺服器有時也會返回200狀態碼以及相應內容。這種情況下,我們一定要與手工操作得到的json文件進行對比,看看我們的傳參(多測試幾組不同的參數,看返回json內容是否不同)是否真的起到作用,以免空歡喜一場!

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 題意 "題目鏈接" Sol 紫色的線段樹板子題??。。。 ...
  • 題目內容: 電腦內部用二進位來表達所有的值。一個十進位的數字,比如18,在一個32位的電腦內部被表達為00000000000000000000000000011000。可以看到,從左邊數過來,在第一個1之前,有27個0。我們把這些0稱作前導的零。 現在,你的任務是寫一個程式,輸入一個整數,輸出在 ...
  • 在Timer模塊中有提到,libuv控制著延遲事件的觸發,那麼必須想辦法精確控制時間。 如果是JS,獲取當前時間可以直接通過Date.now()得到一個時間戳,然後將兩段時間戳相減得到時間差。一般情況下當然沒有問題,但是這個方法並不保險,因為本地電腦時間可以修改。 libuv顯然不會用這麼愚蠢的辦 ...
  • 題目內容: 一個正整數的因數是所有可以整除它的正整數。而一個數如果恰好等於除它本身外的因數之和,這個數就稱為完數。例如6=1+2+3(6的因數是1,2,3)。 現在,你要寫一個程式,讀入兩個正整數n和m(1<=n<m<1000),輸出[n,m]範圍內所有的完數。 提示:可以寫一個函數來判斷某個數是否 ...
  • 題目內容: 每個非素數(合數)都可以寫成幾個素數(也可稱為質數)相乘的形式,這幾個素數就都叫做這個合數的質因數。比如,6可以被分解為2x3,而24可以被分解為2x2x2x3。 現在,你的程式要讀入一個[2,100000]範圍內的整數,然後輸出它的質因數分解式;當讀到的就是素數時,輸出它本身。 輸入格 ...
  • json數據格式 參見 "json數據格式說明" 。 如果沒操作過json數據,建議先看下上面的文章,有助於理解本文後面的內容。 Go json包 Marshal():Go數據對象 json數據 UnMarshal():Json數據 Go數據對象 構建json數據 Marshal()和Marshal ...
  • 在監控設備的時候,在server端的日誌中有時候會見到類似another network error, wait for 15s seconds的異常,今天我們看下這個問題的出現原因和解決方案:問題定位到poller.c,看下下麵兩份代碼:這個get_values的部分代碼: 這裡是zbx_deac ...
  • yield 關鍵字 yield 是在:PEP 255 -- Simple Generators 這個pep引入的 yield 只能在函數內部使用,包含yield語句的函數稱為生成器函數 當調用生成器函數時,並不會執行函數體中的代碼,而是返回一個生成器對象 每次調用生成器對象的next()方法時,才會 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...