https://www.jianshu.com/p/0023bb7afddb
模擬multipart/form-data請求
原以為requests請求十分強大, 但遇到了模擬multipart/form-data類型的post請求, 才發現requests庫還是有一丟丟的不足。 不過也可能是我理解的不足, 還希望讀者老爺不吝指教! 在此感謝!
1. 什么是multipart/form-data請求
enctype屬性:
enctype:規定了form表單在發送到服務器時候編碼方式,它有如下的三個值。
①application/x-www-form-urlencoded:默認的編碼方式。但是在用文本的傳輸和MP3等大型文件的時候,使用這種編碼就顯得 效率低下。
②multipart/form-data:指定傳輸數據為二進制類型,比如圖片、mp3、文件。
③text/plain:純文體的傳輸。空格轉換為 “+” 加號,但不對特殊字符編碼。

2. multipart/form-data請求請求體的格式(以某網站模擬登錄為例)
multipart請求體的格式
值得注意的是:請求頭的Content-Type屬性與其他post請求的不同
3. 實現請求體的拼接
3.1 第一種:使用 requests庫
# coding: utf-8 from collections import OrderedDict import requests # 構建有序字典 params = OrderedDict([("username", (None, '130533193203240022')), ("password", (None, 'qwerqwer')), ('captchaId', (None, 'img_captcha_7d96b3cd-f873-4c36-8986-584952e38f20')), ('captchaWord', (None, 'rdh5')), ('_csrf', (None, '200ea95d-90e9-4789-9e0b-435a6dd8b57b'))]) res = requests.get('http://www.baidu.com', files=params) print res.request.body
打印的結果:
--6c7a1966e0294e1cb89b06b95cf3da84 Content-Disposition: form-data; name="username" 130533193203240022 --6c7a1966e0294e1cb89b06b95cf3da84 Content-Disposition: form-data; name="password" qwerqwer --6c7a1966e0294e1cb89b06b95cf3da84 Content-Disposition: form-data; name="captchaId" img_captcha_7d96b3cd-f873-4c36-8986-584952e38f20 --6c7a1966e0294e1cb89b06b95cf3da84 Content-Disposition: form-data; name="captchaWord" rdh5 --6c7a1966e0294e1cb89b06b95cf3da84 Content-Disposition: form-data; name="_csrf" 200ea95d-90e9-4789-9e0b-435a6dd8b57b --6c7a1966e0294e1cb89b06b95cf3da84--
需要注意的是, 可以發現分隔符是隨機生成的, 跟制定的不太一樣, 這需要我們自己手動替換
# 替換使用的re temp = re.search(r'--(.*)--', res.request.body).group(1) data = re.sub(temp, '----WebKitFormBoundaryKPjN0GYtWEjAni5F', res.request.body)
注:這種方法可以構建想要的請求體, 麻煩的是分隔符並不是制定的那樣,而是默認的 uuid4().hex 需要手動替換。 files可以接收的參數, 源碼中解釋截圖在文末。
3.2 第二種:使用 encode_multipart_formdata函數
# coding: utf-8 from collections import OrderedDict from urllib3 import encode_multipart_formdata params = OrderedDict([("username", (None, '130533193203240022', 'multipart/form-data')), ("password", (None, 'qwerqwer', 'multipart/form-data')), ('captchaId', (None, 'img_captcha_7d96b3cd-f873-4c36-8986-584952e38f20', 'multipart/form-data')), ('captchaWord', (None, 'rdh5', 'multipart/form-data')), ('_csrf', (None, '200ea95d-90e9-4789-9e0b-435a6dd8b57b','multipart/form-data'))]) m = encode_multipart_formdata(params, boundary='----WebKitFormBoundaryKPjN0GYtWEjAni5F') print m[0]
# 打印結果
------WebKitFormBoundaryKPjN0GYtWEjAni5F Content-Disposition: form-data; name="username" Content-Type: multipart/form-data 130533193203240022 ------WebKitFormBoundaryKPjN0GYtWEjAni5F Content-Disposition: form-data; name="password" Content-Type: multipart/form-data qwerqwer ------WebKitFormBoundaryKPjN0GYtWEjAni5F Content-Disposition: form-data; name="captchaId" Content-Type: multipart/form-data img_captcha_7d96b3cd-f873-4c36-8986-584952e38f20 ------WebKitFormBoundaryKPjN0GYtWEjAni5F Content-Disposition: form-data; name="captchaWord" Content-Type: multipart/form-data rdh5 ------WebKitFormBoundaryKPjN0GYtWEjAni5F Content-Disposition: form-data; name="_csrf" Content-Type: multipart/form-data 200ea95d-90e9-4789-9e0b-435a6dd8b57b ------WebKitFormBoundaryKPjN0GYtWEjAni5F--
可以看得到, 這種方法多出來一個 Content-Type(我傳遞的參數中指定了這個值, 如果沒有指定,這個Content-Type依然存在,值為:application/octet-stream), 我現在也沒有太確定多的這個值對最后的結果有沒有影響。還沒試...[手動捂臉]
4. 最終的請求
參數拼接完, 最終的請求要用post, 參數是data, 不要再用files。記得Headers的Content-Type
參數拼接完, 最終的請求要用post, 參數是data, 不要再用files。記得Headers的Content-Type
總注:上邊這兩種構建參數的方式各有不同, 用起來感覺並不是那么的靈活,所以感嘆requests有那么一丟丟丟的不足。值的注意的是,requests.post中files參數接收字典的形式和encode_multipart_formdata中params參數接收字典形式的區別!人生苦短......
本人水平有限, 如有錯誤歡迎提出指正!如有參考, 請注明出處!!禁止抄襲,遇抄必肛!!!
files接收參數的格式
boundary的取值
默認的boundary
源碼中這個函數boundary默認為None
作者:董小賤
鏈接:https://www.jianshu.com/p/0023bb7afddb
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
