利用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中dir函数用法分析
Apr 17 Python
pandas.dataframe中根据条件获取元素所在的位置方法(索引)
Jun 07 Python
将tensorflow的ckpt模型存储为npy的实例
Jul 09 Python
详解爬虫被封的问题
Apr 23 Python
python实现抽奖小程序
Apr 15 Python
python数据预处理之数据标准化的几种处理方式
Jul 17 Python
Django对models里的objects的使用详解
Aug 17 Python
详解Python并发编程之从性能角度来初探并发编程
Aug 23 Python
使用Python给头像戴上圣诞帽的图像操作过程解析
Sep 20 Python
python使用 request 发送表单数据操作示例
Sep 25 Python
Python3 shutil(高级文件操作模块)实例用法总结
Feb 19 Python
django Model层常用验证器及自定义验证器详解
Jul 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脚本[带参数]的方法
2010/01/22 PHP
php5.3中连接sqlserver2000的两种方法(com与ODBC)
2012/12/29 PHP
php class类的用法详细总结
2013/10/17 PHP
php读取csv文件并输出的方法
2015/03/14 PHP
关于扩展 Laravel 默认 Session 中间件导致的 Session 写入失效问题分析
2016/01/08 PHP
[原创]php使用strpos判断字符串中数字类型子字符串出错的解决方法
2017/04/01 PHP
PHP的微信支付接口使用方法讲解
2019/03/08 PHP
thinkPHP3.2使用RBAC实现权限管理的实现
2019/08/27 PHP
PHP 实现缩略图
2021/03/09 PHP
9个javascript语法高亮插件 推荐
2009/07/18 Javascript
Jquery EasyUI中弹出确认对话框以及加载效果示例代码
2014/02/13 Javascript
JavaScript的函数式编程基础指南
2016/03/19 Javascript
JS克隆,属性,数组,对象,函数实例分析
2016/11/26 Javascript
bootstrap 下拉多选框进行多选传值问题代码分析
2017/02/14 Javascript
jQuery实现元素的插入
2017/02/27 Javascript
AngularJS前端页面操作之用户修改密码功能示例
2017/03/27 Javascript
微信小程序实现红包雨功能
2018/07/11 Javascript
在vue中使用SockJS实现webSocket通信的过程
2018/08/29 Javascript
小程序中手机号识别的示例
2020/12/14 Javascript
[01:13]2015国际邀请赛线下观战现场
2015/08/08 DOTA
Python模拟三级菜单效果
2017/09/11 Python
python 爬虫 批量获取代理ip的实例代码
2018/05/22 Python
Scrapy框架使用的基本知识
2018/10/21 Python
pandas DataFrame 删除重复的行的实现方法
2019/01/29 Python
python实现抠图给证件照换背景源码
2019/08/20 Python
美国新蛋IT数码商城:Newegg.com
2016/07/21 全球购物
介绍一下UNIX启动过程
2013/11/14 面试题
新闻编辑自荐信
2013/11/03 职场文书
对孩子的寄语
2014/04/09 职场文书
2014年小学国庆节活动方案
2014/09/16 职场文书
交通事故协议书范文
2014/10/23 职场文书
2015年度个人业务工作总结
2015/04/27 职场文书
法律意见书范文
2015/06/04 职场文书
2016年小学生教师节广播稿
2015/12/18 职场文书
Python线程池与GIL全局锁实现抽奖小案例
2022/04/13 Python
苹果的回收机器人可以通过拆解iPhone获取大量的金和铜并外公布了环境保护最新进展
2022/04/21 数码科技