如何在 Python 中模拟 post 表单来上传文件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在 Python 中模拟 post 表单来上传文件相关的知识,希望对你有一定的参考价值。

在机器上安装了Python的setuptools工具,可以通过下面的命令来安装 poster:

easy_install poster

装完之后,安装下面代码就可以实现post表单上传文件了:

from poster.encode import multipart_encode
from poster.streaminghttp import register_openers
import urllib2
 
# 在 urllib2 上注册 http 流处理句柄
register_openers()
 
# 开始对文件 "DSC0001.jpg" 的 multiart/form-data 编码
# "image1" 是参数的名字,一般通过 html 中的 <input> 标签的 name 参数设置
 
# headers 包含必须的 Content-Type 和 Content-Length
# datagen 是一个生成器对象,返回编码过后的参数
datagen, headers = multipart_encode("image1": open("DSC0001.jpg", "rb"))
 
# 创建请求对象(localhost服务器IP地址,5000服务器端口)
request = urllib2.Request("http://localhost:5000/upload_image", datagen, headers)
# 实际执行请求并取得返回
print urllib2.urlopen(request).read()
参考技术A

发个以前用urllib2模块来做的

class HTTPError(urllib2.HTTPDefaultErrorHandler):
    def __init__(self):
        self.errMsg = ''
        
    def getErrorMsg(self):
        return self.errMsg
    
    def http_error_default(self, req, fp, code, msg, hdrs):
        if code >= 400 :
            self.errMsg  = fp.read()        
        raise urllib2.HTTPError(req.get_full_url(), code, msg, hdrs, fp)
'''
urllib2 post request: eg. uploadfile
'''
def sendMultipartPost(url, params, files):
    #params like this :'type':'upload','id':'xxxx'
    #files like this: 'file':'C:/xxxx.txt'
    posterParams = []
    for key in params:
        value = params[key]
        try:                
            posterParams.append(poster.encode.MultipartParam(key, value))
        except Exception, e:
            print e, key, value    
            raise e
        
    for key in files:
        value = files[key]
        try:
            value = value.encode(sys.getfilesystemencoding())
            posterParams.append(poster.encode.MultipartParam.from_file(key, value))
        except Exception, e:
            print e, key, value    
            raise e
    
    try:    
        datagen, headers = poster.encode.multipart_encode(posterParams)
    except Exception, e:
        print e, key, value    
        raise e

    if headers is None:
        headers =             
    
    try: 
        request = urllib2.Request(url, datagen, headers)   
        request.add_header('Accept-encoding', 'gzip')   
        request.add_header("Accept", "*/*")     
#             print request   
#             print request.get_data()
        opener,err = getUrllib2(True, False)
        response = opener.open(request)
    except Exception, e:
        print e, url, files
        print err.getErrorMsg()
        raise e
    data = response.read()
    '''
    data = response.read(16*1024)
    length = len(data)
    _data = None
    while length:
        if _data: data += _data
        _data = response.read(16*1024)
        length = len(_data)
    '''    
    if 'gzip' == response.headers.get('content-encoding', ''):
        compressedstream = StringIO.StringIO(data)
        gzipper = gzip.GzipFile(fileobj=compressedstream)
        data =gzipper.read()            
        
    return data

def getUrllib2(upload = False, redirect = False):
    if upload:
        handlers = poster.streaminghttp.get_handlers()
    else:
        handlers = []
    err = HTTPError() 
    handlers.append(err)  
    handlers.append(getCookie())
    
    try:
        opener = urllib2.build_opener(*handlers)
    except Exception, e:
        print err.getErrorMsg()
        raise e
    return opener,err

def getCookie():
    global _cookieProcessor
    cookiefile = "./cookies.txt"         
    try:
        httpcookie = cookielib.MozillaCookieJar(cookiefile)
        httpcookie.load(ignore_discard=True, ignore_expires=True)
        httpcookie = urllib2.HTTPCookieProcessor(httpcookie)
    except Exception, e:
        print e    
        httpcookie = _cookieProcessor
            
#    _cookieProcessor = urllib2.HTTPCookieProcessor(cookielib.CookieJar())    
    return httpcookie

本回答被提问者和网友采纳
参考技术B Python-Requests 非常方便。
我的某个上传文件代码(是的,multipart / form-data 上传就这一行)
r = requests.post (server('new'), files='content' : open('test.md', 'rb'))

CURL模拟表单post提交及相关常用参数的使用(包括提交表单同时上传文件)

转载自:https://blog.csdn.net/freedomwjx/article/details/43278157
一. 首先,最简单的情况是我们只需要提交一个不带文件上传的表单,这种情况下,只需要在curl中使用--data(注意是--不是-)或者它的缩写-d即可。
[plain] view plain copy
 
  1. curl -d "key=value&key=value" "url"  
    或者
[plain] view plain copy
 
  1. curl --data "key=value&key=value" "url"  
    (注意:如果键值对只有一个的话,可以不写双引号,但是如果有多个键值对,必须加上双引号,键值对之间用&连接)
 
    现在假设我们有一个登陆表单,它看起来可能是这样的
[html] view plain copy
 
  1. <form  action="doLogin" method="post">  
  2.     <input type="text"  name="username"  value="admin"/>  
  3.     <input type="password"  name="password"  value="admin"/>  
  4.     <button type="submit"  value="submit" />  
  5. </form>  
    那我们的curl就应该写成这样
[plain] view plain copy
 
  1. curl -d "username=admin&password=admin" "www.xxxx.com/doLogin"  
    如果登陆后网页被重定向,而我们想追踪这个重定向的话可以加上-L参数(L必须大写),表示追踪重定向
[plain] view plain copy
 
  1. curl -L  -d "username=admin&password=admin" "www.xxx.com/doLogin"  
二. 稍微复杂的情况:现在我们希望进行一些必须在登陆前提下的post请求,那就需要先保存我们之前的成功登陆的cookie信息,然后再携带登陆信息进行post请求
    1.保存登陆cookie信息到文件可以通过以下2个选项中的任意一个实现
    -c :保存cookie信息
    -D:保存整个header信息,包括cookie
    示例:
[plain] view plain copy
 
  1. curl -c cookie.txt  -d "username=admin&password=admin" "www.xxx.com/doLogin"  
    运行后会在你执行指令的目录下生成一个cookie.txt文件,当然你也可以指定该文件的创建路径,相对路径绝对路径皆可(如cookie.txt可以改成 /path/cookie.txt)
 
    2.携带登陆信息进行post请求需要使用-b选项
        -b:指定使用哪个文件
        示例:
[plain] view plain copy
 
  1. curl -L -b cookie.txt -d "key=value" "url"  
三. 模拟表单文件上传,相当于form表单中method="POST"和enctype="multipart/form-data"的情况
        
        这个时候就需要用到-F选项了
        curl -F "[email protected]" "url"
 
        假目前我们的文件上传表单是这样的:
[html] view plain copy
 
  1. <form  action="upload" method="post" enctype="multipart/form-data">  
  2.     <input type="file"  name="myfile" />  
  3.     <button type="submit"  value="submit" />  
  4. </form>  
        我们想提交一个名为hellocurl.zip的文件,该文件在我们指令所在的根目录下。
 
        那我们的curl就是这样的
[plain] view plain copy
 
  1. curl -F "[email protected]" "www.xxx.com/upload"  
        如果上传的文件不止一个,可以写多个-F "[email protected]"
[plain] view plain copy
 
  1. curl -F "[email protected]" -F "[email protected]" "www.xxx.com/upload"  
        再来看一个更加贴近实际的情况:很多时候,我们的表单还会包含许多其他表单元素,如text,checkbox,select等等。
        
        现在我们在上面表单的基础上加入更多元素,变成下面这样:
[html] view plain copy
 
  1. <form  action="upload" method="post" enctype="multipart/form-data">  
  2.     <span style="color:#990000;"><input type="text"  name="filename"  value="hellocurl"/></span>  
  3.     <input type="file"  name="myfile" />  
  4.     <button type="submit"  value="submit" />  
  5. </form>  
        同时我们想提交hellocurl.zip文件
 
        这时候我们可能会想到加上-d
 
        特别注意,这个时候我们不能同时使用-d和-F,这2个选项在curl中是两种方式的请求,-d为application/x-www-url-encoded方式发送post请求,而-F为multipart/form-data方式,
        如果在一次curl中同时使用-d和-F选项会报Warning: You can only select one HTTP request!的警告,导致指令无法执行
 
        这种情况下,现在网上很多给出的解决方案是通过增加-F的方式来解决
 
        即:
[plain] view plain copy
 
  1. curl -F "filename=hellocurl" -F "[email protected]" "www.xxx.com/upload"  
        但是我在一个spring mvc的项目中测试这个方法的时候发现,由于拿不到filename的值,无法绕过服务器端的验证,导致提交失败
        如果你也碰到类似的情况,可以尝试下以下解决方法:
[plain] view plain copy
 
  1. curl -F "[email protected]" "www.xxx.com/upload?key1=value1&key2=value2"  
        具体到当前的问题我们的curl就是:
[plain] view plain copy
 
  1. curl -F "[email protected]" "www.xxx.com/upload?filename=hellocurl"  
        该方法亲测通过,并且仍然是post的提交方式。
 
        其他一些实用选项:
        -v:查看请求的整个完整的过程
        -i:查看请求头信息
       -o:保存响应结果到指定路径的文件中,如: curl -o tmp.txt http://www.csdn.net   #保存响应到tmp.txt

以上是关于如何在 Python 中模拟 post 表单来上传文件的主要内容,如果未能解决你的问题,请参考以下文章

JAVA模拟HTTP post请求上传文件

CURL模拟表单post提交及相关常用参数的使用(包括提交表单同时上传文件)

HTML表单的POST上传方式

java模拟post方式提交表单实现图片上传

用python复制form表单的一个问题?

在 Python 请求中使用 POST 表单数据上传图像