利用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 多进程和数据传递的理解
Oct 09 Python
在python中使用正则表达式查找可嵌套字符串组
Oct 24 Python
python3 图片referer防盗链的实现方法
Mar 12 Python
在Pycharm中自动添加时间日期作者等信息的方法
Jan 16 Python
python调用webservice接口的实现
Jul 12 Python
Python datetime包函数简单介绍
Aug 28 Python
python3实现高效的端口扫描
Aug 31 Python
python实现输出一个序列的所有子序列示例
Nov 18 Python
Django对接支付宝实现支付宝充值金币功能示例
Dec 17 Python
解决python-docx打包之后找不到default.docx的问题
Feb 13 Python
scrapy框架携带cookie访问淘宝购物车功能的实现代码
Jul 07 Python
python四种出行路线规划的实现
Jun 23 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/09/15 PHP
深入Memcache的Session数据的多服务器共享详解
2013/06/13 PHP
PHP和JavaScrip分别获取关联数组的键值示例代码
2013/09/16 PHP
javascript 面向对象全新理练之继承与多态
2009/12/03 Javascript
什么是json和jsonp,jQuery json实例详详细说明
2012/12/11 Javascript
JQuery中form验证出错信息的查看方法
2013/10/08 Javascript
JS+CSS实现自适应选项卡宽度的圆角滑动门效果
2015/09/15 Javascript
node.js实现爬虫教程
2020/08/25 Javascript
关于JSON与JSONP简单总结
2016/08/16 Javascript
BOM系列第一篇之定时器setTimeout和setInterval
2016/08/17 Javascript
详解Vue路由开启keep-alive时的注意点
2017/06/20 Javascript
在Vant的基础上实现添加表单验证框架的方法示例
2018/12/05 Javascript
微信小程序新手教程之启动页的重要性
2019/03/03 Javascript
JS array数组检测方式解析
2020/05/19 Javascript
vue@cli3项目模板怎么使用public目录下的静态文件
2020/07/07 Javascript
pycharm 使用心得(六)进行简单的数据库管理
2014/06/06 Python
Python迭代和迭代器详解
2016/11/10 Python
python模块之re正则表达式详解
2017/02/03 Python
用Python逐行分析文件方法
2019/01/28 Python
基于python监控程序是否关闭
2020/01/14 Python
解决TensorFlow GPU版出现OOM错误的问题
2020/02/03 Python
HTML5实时语音通话聊天MP3压缩传输3KB每秒
2019/08/28 HTML / CSS
美国在线家居装饰店:Belle&June
2018/10/24 全球购物
豪华床上用品 :Jennifer Adams
2019/09/15 全球购物
美国亚马逊旗下时尚女装网店:SHOPBOP(支持中文)
2020/10/17 全球购物
Yahoo-PHP面试题2
2014/12/06 面试题
三月学雷锋月活动总结
2014/04/28 职场文书
理发店策划方案
2014/06/05 职场文书
我爱幼儿园演讲稿
2014/09/11 职场文书
党员干部群众路线教育实践活动个人对照检查材料
2014/09/23 职场文书
领导走群众路线整改措施思想汇报
2014/10/12 职场文书
2015年学校心理健康教育工作总结
2015/05/11 职场文书
丧事酒宴答谢词
2015/09/30 职场文书
敬业奉献模范事迹材料(2016精选版)
2016/02/26 职场文书
分析Python list操作为什么会错误
2021/11/17 Python
清空 Oracle 安装记录并重新安装
2022/04/26 Oracle