利用python模拟实现POST请求提交图片的方法


Posted in Python onJuly 25, 2017

本文主要给大家介绍的是关于利用python模拟实现POST请求提交图片的方法,分享出来供大家参考学习,下面来一看看详细的介绍:

使用requests来模拟HTTP请求本来是一件非常轻松的事情,比如上传图片来说,简单的几行代码即可:

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) # 失败
...

不过我今天在调试一个django程序的时候却遇到了大坑————为了偷懒,我直接在ipython中执行了上述代码,第一次提交的时候一切正常,但第二次之后提交就怎么也通过不了django的form验证。

验证部分的代码很简单:

......
form = AttachmentForm(request.POST, request.FILES)
if form.is_valid():
 form.save(request, obj)
 messages.success(request,_('Your attachment was uploaded.'))
 return HttpResponseRedirect(next)
......

什么鬼!?怎么只有第一次成功提交???后面全失败??只好一步一步的跟进到django源码中,发现问题出在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

在第一次执行的时候,一切正常,这个data即InMemoryUploadFile文件类型,name、size就是我们上传的图片名、大小,而第二次执行post请求时候,发现data.size居然变成了0?!怪不得直接引发了if not self.allow_empty_file and not file_size这个判断的异常呢!

由此可知,问题的核心并不出现在django对于表单验证的部分,而是出自发送请求的部分。不过发请求的部分代码很简单啊?分别输出了正常情况和错误情况requests发出的请求包,发现区别了:

#正常情况
In [28]: r = requests.post('http://www.xxxx.com/upload', files=files, data=values)
In [29]: r.request.body
#错误情况
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'

正常情况没输出,错误情况反而看着像正常情况下的输出?这不科学啊?

结合以上2点,我隐约感觉问题出在数据的构造上,关键在于files = {'attachment_file': ('1.png', open('1.png', 'rb') , 'image/png', {})}这里,首先关于字典、列表这种可变类型作为函数的参数传递时候就需要特别注意,其次open函数打开了一个文件,那么哪里关闭文件了呢?

带着这个怀疑,我把代码改写成:

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)

然后再执行,果然成功上传了2张图片。其实按照正常情况不会出现测试时候这种打开一张图片不停上传的情形,不过也正因为这样才会遇到如此有意思的问题。关于requests中files对象的处理代码在models.py文件中,有兴趣的读者可以自行调试。

另外,requests调用时上传文件名中不能包含中文,否则也不能通过django表单验证,这里也不深究原因了。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
kNN算法python实现和简单数字识别的方法
Nov 18 Python
Python标准库defaultdict模块使用示例
Apr 28 Python
python批量添加zabbix Screens的两个脚本分享
Jan 16 Python
Python实现可自定义大小的截屏功能
Jan 20 Python
python+selenium打印当前页面的titl和url方法
Jun 22 Python
pyqt5的QComboBox 使用模板的具体方法
Sep 06 Python
对python函数签名的方法详解
Jan 22 Python
python实现飞船游戏的纵向移动
Apr 24 Python
python基于socket函数实现端口扫描
May 28 Python
基于python代码批量处理图片resize
Jun 04 Python
python 模块导入问题汇总
Feb 01 Python
python的变量和简单数字类型详解
Sep 15 Python
利用django如何解析用户上传的excel文件
Jul 24 #Python
Python编程之变量赋值操作实例分析
Jul 24 #Python
Python模块结构与布局操作方法实例分析
Jul 24 #Python
Python列表list操作符实例分析【标准类型操作符、切片、连接字符、列表解析、重复操作等】
Jul 24 #Python
Python列表list内建函数用法实例分析【insert、remove、index、pop等】
Jul 24 #Python
python引入导入自定义模块和外部文件的实例
Jul 24 #Python
Python3.X 线程中信号量的使用方法示例
Jul 24 #Python
You might like
需要发散思维学习PHP
2009/06/29 PHP
浅析PHP substr,mb_substr以及mb_strcut的区别和用法
2013/06/21 PHP
使用php计算排列组合的方法
2013/11/13 PHP
PHP中魔术变量__METHOD__与__FUNCTION__的区别
2014/09/29 PHP
Yii获取当前url和域名的方法
2015/06/08 PHP
基于JQuery 滑动与动画的说明介绍
2013/04/18 Javascript
CSS鼠标响应事件经过、移动、点击示例介绍
2013/09/04 Javascript
JS实现固定在右下角可展开收缩DIV层的方法
2015/02/13 Javascript
使用requestAnimationFrame实现js动画性能好
2015/08/06 Javascript
jQuery取消特定的click事件
2016/02/29 Javascript
分享12个实用的jQuery代码片段
2016/03/09 Javascript
AngularJS 所有版本下载地址
2016/09/14 Javascript
深入学习jQuery中的data()
2016/12/22 Javascript
Vue 兄弟组件通信的方法(不使用Vuex)
2017/10/26 Javascript
如何编写一个d.ts文件的步骤详解
2018/04/13 Javascript
JS使用setInterval实现的简单计时器功能示例
2018/04/19 Javascript
微信小程序中进行地图导航功能的实现方法
2018/06/29 Javascript
jQuery+css实现的点击图片放大缩小预览功能示例【图片预览 查看大图】
2020/05/29 jQuery
JavaScript中reduce()的5个基本用法示例
2020/07/19 Javascript
Linux下用Python脚本监控目录变化代码分享
2015/05/21 Python
python编程实现希尔排序
2017/04/13 Python
django框架如何集成celery进行开发
2017/05/24 Python
简单了解python模块概念
2018/01/11 Python
scrapy spider的几种爬取方式实例代码
2018/01/25 Python
python自定义时钟类、定时任务类
2021/02/22 Python
python3.6生成器yield用法实例分析
2019/08/23 Python
Python搭建代理IP池实现存储IP的方法
2019/10/27 Python
广州地球村科技数据库题目
2016/04/25 面试题
教师自我评价范文
2013/12/16 职场文书
超市开学活动方案
2014/03/01 职场文书
大学班级学风建设方案
2014/05/01 职场文书
监督检查工作方案
2014/05/28 职场文书
募捐感谢信
2015/01/22 职场文书
机关保密工作承诺书
2015/05/04 职场文书
辞职信怎么写?
2019/05/21 职场文书
Python+Appium新手教程
2021/04/17 Python