新版知乎登錄之post請求


前言

上一篇文章中給大家講解了requests發送post請求的幾種方式,並分析了一些使用陷阱。

疑惑

在文章發表之后,有朋友給我留言說,知乎登錄就沒有使用提交Form表單(application/x-www-form-urlencoded)的方式,而是上傳文件(multipart/form-data),這是為什么呢?知乎登錄post請求該怎么發送呢?

本質

我想說的是一般情況下是使用提交Form表單的方式進行登錄,但是不排除其他的方式。大家要透過現象看本質,登錄驗證的本質上是客戶端發送驗證消息,服務端校驗消息,返回響應。登錄驗證可以使用提交Form表單,可以使用發送ajax,也可以上傳驗證文件,甚至我不用http請求,使用Websocket,都是可以的,這沒必要糾結。好多朋友在知乎登錄的時候,就傻眼了?這個怎么使用requests發送post請求呢?

新版知乎登錄分析

首先打開谷歌瀏覽器,同時F12,打開開發者模式,並勾選Preserve log

為了保留所有的網絡信息

接着在知乎登錄首頁,輸入賬號與密碼,開始登錄。(這次不涉及驗證碼的分析)

知乎登錄

知乎登錄請求如下圖,大家肯定注意到了content-type: multipart/form-data; boundary=----WebKitFormBoundarypxPm5bUFaA8CHOHo。不僅不是Form表單提交,而且和之前講的上傳文件還有區別,即boundary的配置。

requests模擬知乎登錄

上一篇文章里的文件上傳,post函數里使用的是files參數,通過這個參數來表明使用的是multipart/form-data編碼,這里不再是通過files參數傳文件,而是傳參數,其實本質上一樣的,文件內容不就是這參數嗎?好,為了測試方便,向 http://httpbin.org/post 發送post請求,代碼如下:

import requests
url = "http://httpbin.org/post"

fields = {
    "client_id":  "c3cef7c66a1843f8b3a9e6a1e3160e20",
    "grant_type":  "password",
    "timestamp": "1527040472416",
    "source":  "com.zhihu.web",
    "signature":"66a16483ab16e54c3bb4ef84bf683dd67cadc246",
    "username": "xxxxx@qq.com",
    "password":  "xxxxxxxx"
}


res = requests.post(url, files=fields)

print(res.request.body)
print(res.request.headers)
print(res.text)

從上面代碼中可以看到,files參數只不過變成了參數字典。在控制台的輸出效果如下:

打印的方式觀察的效果不是很好,不如使用http Analyzer
抓取發送的包更加直觀。對於http Analyzer的使用在我的書《Python爬蟲開發與項目實戰》中有講解。http Analyzer抓到的發送包請求頭截圖如下:

請求頭

payload信息如下,效果已經出來了。

post payload

從上面兩張圖中,我們發現我們寫的程序沒有問題,發送的post請求和知乎登錄的數據包差別不是很大。

boundary定制

要說和知乎登錄請求包還有什么差別,也就是boundary的配置

知乎登錄的類似boundary=----WebKitFormBoundarypxPm5bUFaA8CHOHo,而我們寫的程序為boundary=f30cf72e14254d59a9824e694e10e2c0。肯定有聰明的小伙伴,已經開動腦筋,我們在requests單獨配置headers不就可以了?很不幸的告訴大家,這樣是不行的,雖然headers改變了,但是post數據中的boundary內容並沒有改變呢。這個時候我們要引入幫手requests_toolbelt

requests_toolbelt

requests_toolbelt是對requests的補充,是一個第三方輔助插件,通過這個插件就可以定制boundary。首先安裝requests_toolbelt:

pip3 install requests_toolbelt

定制代碼如下:

import requests
from requests_toolbelt import MultipartEncoder
url = "http://httpbin.org/post"
fields = {
    "client_id":  "c3cef7c66a1843f8b3a9e6a1e3160e20",
    "grant_type":  "password",
    "timestamp": "1527040472416",
    "source":  "com.zhihu.web",
    "signature":"66a16483ab16e54c3bb4ef84bf683dd67cadc246",
    "username": "xxxxx@qq.com",
    "password":  "xxxxxxxx"
}

m = MultipartEncoder(fields, boundary='----WebKitFormBoundaryWp8R1tWtqL2vhLuG')
res = requests.post(url, headers={'Content-Type': m.content_type}, data=m.to_string())

print(res.request.body)
# # 查看請求頭
print(res.request.headers)
print(res.text)

發送效果

這次直接使用http analyzer抓包看一下效果。

請求頭

post payload

福利大放送

關注公眾號:七夜安全博客

  • 回復【1】:領取 Python數據分析 教程大禮包
  • 回復【2】:領取 Python Flask 全套教程
  • 回復【3】:領取 某學院 機器學習 教程
  • 回復【4】:領取 爬蟲 教程

知識星球已經快40人了,隨着人數的增多,價格之后會上漲,越早關注越多優惠。星球的福利有很多:

  • 比如上面的教程,已經提前在知識星球中分享
  • 可以發表一些問題,大家一塊解決
  • 我之后寫的電子書,錄制的教學視頻,對於知識星球的朋友都是優惠的(基本上免費)
  • 一些節假日會給大家發個紅包或者贈書


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM