利用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 相关文章推荐
Python读写ini文件的方法
May 28 Python
请不要重复犯我在学习Python和Linux系统上的错误
Dec 12 Python
Python字符串处理实现单词反转
Jun 14 Python
python 3.6.4 安装配置方法图文教程
Sep 18 Python
Python 从一个文件中调用另一个文件的类方法
Jan 10 Python
Pytorch之view及view_as使用详解
Dec 31 Python
解决pycharm同一目录下无法import其他文件
Feb 12 Python
Python切割图片成九宫格的示例代码
Mar 10 Python
如何导出python安装的所有模块名称和版本号到文件中
Jun 05 Python
python有几个版本
Jun 17 Python
Django封装交互接口代码
Jul 12 Python
python在package下继续嵌套一个package
Apr 14 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通用分页类page.php[仿google分页]
2008/08/31 PHP
php截取中文字符串函数实例
2015/02/23 PHP
thinkPHP学习笔记之安装配置篇
2015/03/05 PHP
php实现微信公众平台账号自定义菜单类
2015/10/11 PHP
PHP使用内置函数file_put_contents写入文件及追加内容的方法
2015/12/07 PHP
浅谈PHPANALYSIS提取关键字
2019/03/08 PHP
JavaScript的9个陷阱及评点分析
2008/05/16 Javascript
如何确保JavaScript的执行顺序 之jQuery.html深度分析
2011/03/03 Javascript
关于JavaScript与HTML的交互事件
2013/04/12 Javascript
javascript之typeof、instanceof操作符使用探讨
2013/05/19 Javascript
jQuery打印图片pdf、txt示例代码
2014/07/22 Javascript
JavaScript获取网页中第一个链接ID的方法
2015/04/03 Javascript
jquery可定制的在线UEditor编辑器
2015/11/17 Javascript
JS实现回到页面顶部动画效果的简单实例
2016/05/24 Javascript
input 禁止输入特殊字符的四种实现方式
2016/08/24 Javascript
浅谈js中的引用和复制(传值和传址)
2016/09/18 Javascript
详谈jQuery中使用attr(), prop(), val()获取value的异同
2017/04/25 jQuery
微信小程序表单验证错误提示效果
2017/05/19 Javascript
jQuery为某个div加入行样式
2017/06/09 jQuery
JS中将多个逗号替换为一个逗号的实现代码
2017/06/23 Javascript
jQuery EasyUI结合zTree树形结构制作web页面
2017/09/01 jQuery
微信禁止下拉查看URL的处理方法
2017/09/28 Javascript
js实现鼠标移动到图片产生遮罩效果
2017/10/21 Javascript
JS实现左边列表移到到右边列表功能
2018/03/28 Javascript
JavaScript模板引擎原理与用法详解
2018/12/24 Javascript
JS中锚点链接点击平滑滚动并自由调整到顶部位置
2021/02/06 Javascript
python实现自动登录人人网并访问最近来访者实例
2014/09/26 Python
python持久性管理pickle模块详细介绍
2015/02/18 Python
Python单元测试框架unittest简明使用实例
2015/04/13 Python
css3 中translate和transition的使用方法
2020/03/26 HTML / CSS
加拿大女鞋品牌:ALDO
2016/11/13 全球购物
Cult Gaia官网:美国生活方式品牌
2019/08/16 全球购物
社区党务公开实施方案
2014/03/18 职场文书
爱与责任师德演讲稿
2014/08/26 职场文书
银行转正自我鉴定
2014/09/29 职场文书
介绍信格式
2015/01/30 职场文书