利用python模擬實(shí)現(xiàn)POST請(qǐng)求提交圖片的方法
本文主要給大家介紹的是關(guān)于利用python模擬實(shí)現(xiàn)POST請(qǐng)求提交圖片的方法,分享出來(lái)供大家參考學(xué)習(xí),下面來(lái)一看看詳細(xì)的介紹:
使用requests來(lái)模擬HTTP請(qǐng)求本來(lái)是一件非常輕松的事情,比如上傳圖片來(lái)說(shuō),簡(jiǎn)單的幾行代碼即可:
import requests
files = {'attachment_file': ('1.png', open('1.png', 'rb'), 'image/png', {})}
values = {'next':"http://www.xxxx.com/xxxx"}
r = requests.post('http://www.xxxx.com/upload', files=files, data=values) # 成功
r = requests.post('http://www.xxxx.com/upload', files=files, data=values) # 失敗
r = requests.post('http://www.xxxx.com/upload', files=files, data=values) # 失敗
r = requests.post('http://www.xxxx.com/upload', files=files, data=values) # 失敗
r = requests.post('http://www.xxxx.com/upload', files=files, data=values) # 失敗
...
不過(guò)我今天在調(diào)試一個(gè)django程序的時(shí)候卻遇到了大坑————為了偷懶,我直接在ipython中執(zhí)行了上述代碼,第一次提交的時(shí)候一切正常,但第二次之后提交就怎么也通過(guò)不了django的form驗(yàn)證。
驗(yàn)證部分的代碼很簡(jiǎn)單:
......
form = AttachmentForm(request.POST, request.FILES)
if form.is_valid():
form.save(request, obj)
messages.success(request,_('Your attachment was uploaded.'))
return HttpResponseRedirect(next)
......
什么鬼???怎么只有第一次成功提交???后面全失敗??只好一步一步的跟進(jìn)到django源碼中,發(fā)現(xiàn)問(wèn)題出在django/forms/fields.py文件中:
def to_python(self, data):
if data in validators.EMPTY_VALUES:
return None
# UploadedFile objects should have name and size attributes.
try:
file_name = data.name
file_size = data.size
except AttributeError:
raise ValidationError(self.error_messages['invalid'])
if self.max_length is not None and len(file_name) > self.max_length:
error_values = {'max': self.max_length, 'length': len(file_name)}
raise ValidationError(self.error_messages['max_length'] % error_values)
if not file_name:
raise ValidationError(self.error_messages['invalid'])
if not self.allow_empty_file and not file_size:
raise ValidationError(self.error_messages['empty'])
return data
在第一次執(zhí)行的時(shí)候,一切正常,這個(gè)data即InMemoryUploadFile文件類型,name、size就是我們上傳的圖片名、大小,而第二次執(zhí)行post請(qǐng)求時(shí)候,發(fā)現(xiàn)data.size居然變成了0?!怪不得直接引發(fā)了if not self.allow_empty_file and not file_size這個(gè)判斷的異常呢!
由此可知,問(wèn)題的核心并不出現(xiàn)在django對(duì)于表單驗(yàn)證的部分,而是出自發(fā)送請(qǐng)求的部分。不過(guò)發(fā)請(qǐng)求的部分代碼很簡(jiǎn)單???分別輸出了正常情況和錯(cuò)誤情況requests發(fā)出的請(qǐng)求包,發(fā)現(xiàn)區(qū)別了:
#正常情況
In [28]: r = requests.post('http://www.xxxx.com/upload', files=files, data=values)
In [29]: r.request.body
#錯(cuò)誤情況
In [33]: r = requests.post('http://www.xxxx.com/upload', files=files, data=values)
In [34]: r.request.body
Out[34]: '--155322d3e780432bb06e58135e041c8f\r\nContent-Disposition: form-data; name="next"\r\n\r\nhttp://www.xxxx.com/upload\r\n--155322d3e780432bb06e58135e041c8f\r\nContent-Disposition: form-data; name="attachment_file"; filename="1.png"\r\nContent-Type: image/png\r\n\r\n\r\n--155322d3e780432bb06e58135e041c8f--\r\n'
正常情況沒(méi)輸出,錯(cuò)誤情況反而看著像正常情況下的輸出?這不科學(xué)?。?br />
結(jié)合以上2點(diǎn),我隱約感覺(jué)問(wèn)題出在數(shù)據(jù)的構(gòu)造上,關(guān)鍵在于files = {'attachment_file': ('1.png', open('1.png', 'rb') , 'image/png', {})}這里,首先關(guān)于字典、列表這種可變類型作為函數(shù)的參數(shù)傳遞時(shí)候就需要特別注意,其次open函數(shù)打開(kāi)了一個(gè)文件,那么哪里關(guān)閉文件了呢?
帶著這個(gè)懷疑,我把代碼改寫(xiě)成:
fl = open('1.png','rb')
files = {'attachment_file': ('1.png', fl, 'image/png', {})}
r1 = requests.post('http://www.xxxx.com/upload', files=files, data=values)
fl.close()
fl = open('1.png','rb')
files = {'attachment_file': ('1.png', fl, 'image/png', {})}
r2 = requests.post('http://www.xxxx.com/upload', files=files, data=values)
然后再執(zhí)行,果然成功上傳了2張圖片。其實(shí)按照正常情況不會(huì)出現(xiàn)測(cè)試時(shí)候這種打開(kāi)一張圖片不停上傳的情形,不過(guò)也正因?yàn)檫@樣才會(huì)遇到如此有意思的問(wèn)題。關(guān)于requests中files對(duì)象的處理代碼在models.py文件中,有興趣的讀者可以自行調(diào)試。
另外,requests調(diào)用時(shí)上傳文件名中不能包含中文,否則也不能通過(guò)django表單驗(yàn)證,這里也不深究原因了。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
- Python基于PycURL實(shí)現(xiàn)POST的方法
- Python中的CURL PycURL使用例子
- python中pycurl庫(kù)的用法實(shí)例
- 簡(jiǎn)單談?wù)凱ython的pycurl模塊
- python pycurl驗(yàn)證basic和digest認(rèn)證的方法
- Python安裝pycurl失敗的解決方法
- 解決python3 安裝完P(guān)ycurl在import pycurl時(shí)報(bào)錯(cuò)的問(wèn)題
- python通過(guò)get,post方式發(fā)送http請(qǐng)求和接收http響應(yīng)的方法
- Python模仿POST提交HTTP數(shù)據(jù)及使用Cookie值的方法
- python通過(guò)post提交數(shù)據(jù)的方法
- Python3模擬curl發(fā)送post請(qǐng)求操作示例
相關(guān)文章
詳解Python之Scrapy爬蟲(chóng)教程N(yùn)BA球員數(shù)據(jù)存放到Mysql數(shù)據(jù)庫(kù)
這篇文章主要介紹了詳解Python之Scrapy爬蟲(chóng)教程N(yùn)BA球員數(shù)據(jù)存放到Mysql數(shù)據(jù)庫(kù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
Python中的測(cè)試模塊unittest和doctest的使用教程
這篇文章主要介紹了Python中的測(cè)試模塊unittest和doctest的使用教程,本文來(lái)自于IBM官方網(wǎng)站技術(shù)文檔,需要的朋友可以參考下2015-04-04
sublime3之內(nèi)網(wǎng)安裝python插件Anaconda的流程
這篇文章主要介紹了sublime3之內(nèi)網(wǎng)安裝python插件Anaconda的流程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11
使用Django簡(jiǎn)單編寫(xiě)一個(gè)XSS平臺(tái)的方法步驟
這篇文章主要介紹了使用Django簡(jiǎn)單編寫(xiě)一個(gè)XSS平臺(tái)的方法步驟,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-03-03
使用django-guardian實(shí)現(xiàn)django-admin的行級(jí)權(quán)限控制的方法
這篇文章主要介紹了使用django-guardian實(shí)現(xiàn)django-admin的行級(jí)權(quán)限控制的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-10-10
opencv python 圖像輪廓/檢測(cè)輪廓/繪制輪廓的方法
這篇文章主要介紹了opencv python 圖像輪廓/檢測(cè)輪廓/繪制輪廓的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
通過(guò)實(shí)例簡(jiǎn)單了解Python中yield的作用
這篇文章主要介紹了通過(guò)實(shí)例簡(jiǎn)單了解Python中yield的作用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
Python爬蟲(chóng)實(shí)現(xiàn)抓取京東店鋪信息及下載圖片功能示例
這篇文章主要介紹了Python爬蟲(chóng)實(shí)現(xiàn)抓取京東店鋪信息及下載圖片功能,涉及Python頁(yè)面請(qǐng)求、響應(yīng)、解析等相關(guān)操作技巧,需要的朋友可以參考下2018-08-08

