最近,要在Python模拟表单上上传文件,我搜索了一些常见的解决方案。
模拟提交不包含文件字段的表单时,实现起来很简单,但与文件上传相关的情况有点复杂,需要自己编码文件或使用第三方模块。
但是,因为PycURL需要使用curl,所以在Windows上安装可能有点麻烦。 除了PycURL以外,还有多种方法可以实现POST文件的上传。 例如,这里的二楼发布了一种方法,可以对文件进行编码,然后开机自检。 另外,还有MultipartPostHandler、urlib2_fost,但是名为MultipartPostHandler的模块似乎很旧。 已尝试urllib2_file,但出现错误时未成功。 我想介绍的是另一个第三方模块poster。
如果计算机上安装了Python设置工具,则可以通过以下命令安装poster :
1 sudo easy_install poster
1 #test_client.py
2
3 from poster.encodeimportmultipart _ encode4from poster.streaminghttpimportregister _ opener S5 importurlib 26
在urllib2中注册http流处理句柄
8
9 register_openers () 10
启动11 #文件' DSC0001.jpg '的多art/form-data编码
12
13 #'image1 '是参数的名称,通常由HTML标记的name参数设置
14
15 #headers包含必需的内容类型和内容长度
16 #datagen是生成器对象,它返回编码的参数。 这里有多个参数的话依次添加就可以了
17
18数据gen,headers=multipart _ encode { ' image1 ' : open (DSC 0001.jpg ',' Rb'}} ) 19
20 #创建请求对象
21
22 request=urllib2. request (http://localhost :5000/upload _ image (,datagen,headers ) 23
24 #实际执行要求,获得回报
25
26打印urllib2. urlopen (request ).read )。
很简单。 文件上传完成。
其中,register_openers ()相当于以下操作:
1 from poster.encodeimportmultipart _ encode2from poster.streaminghttpimportstreaminghttphandler,streaminghttpredirecthandithandior
4 handlers=[ streaming httphandler,StreamingHTTPRedirectHandler,StreamingHTTPSHandler]5
6 opener=urllib2. build _ opener (* handlers ) 7
8urllib2.install_opener(opener ) )。
另外,海报者也可以携带cookie。 例如:
1 opener=poster.streaming http.register _ openers (2
3 opener.add _ handler (urllib2. http cookie processor (cookie lib.cookie jar () ) 4
5 params={ ' file ' : open ' ' test.txt ',' Rb'},' name': 'upload test'}6
7数据gen,headers=poster.encode.multipart _ encode (params ) 8
9 request=urllib2. request (upload _ URL,datagen,headers ) 10
11 result=urllib2. urlopen (request )
如果在上载过程中遇到授权问题: register_openers ),则可以自己定义方法以加入用户验证的处理程序。 示例:
1 from poster.encodeimportmultipart _ encode 2
3 from poster.streaminghttpimportstreaminghttphandler,StreamingHTTPRedirectHandler,StreamingHTTPSH
andler45
6
7 #create a password manager
8
9 password_mgr =urllib2.HTTPPasswordMgrWithDefaultRealm()10
11 #Add the username and password.
12
13 #If we knew the realm, we could use it instead of None.
14
15 #add_password('realm','url','username','password')
16
17 password_mgr.add_password('realm', 'url', 'username', 'password')18
19 handler =urllib2.HTTPBasicAuthHandler(password_mgr)20
21 handlers =[handler,StreamingHTTPHandler, StreamingHTTPRedirectHandler, StreamingHTTPSHandler]22
23 opener = urllib2.build_opener(*handlers)24
25 urllib2.install_opener(opener)
或者直接将上面的内容加到上传文件的代码中。
今天突然图片不能上传了,发现上面的认证方式失效了。很是奇怪。于是再来一种解决方案。
其实问题就是解决python环境下HTTP Basic Authorization 的问题
在HTTP中,基本认证是一种用来允许Web浏览器或其他客户端程序在请求时提供用户名和口令形式的身份凭证的一种登录验证方式。
在发送之前是以用户名追加一个冒号然后串接上口令,并将得出的结果字符串再用Base64算法编码。例如,提供的用户名是Aladdin、口令是open sesame,则拼接后的结果就是Aladdin:open sesame,然后再将其用Base64编码,得到QWxhZGRpbjpvcGVuIHNlc2FtZQ==。最终将Base64编码的字符串发送出去,由接收者解码得到一个由冒号分隔的用户名和口令的字符串。
虽然对用户名和口令的Base64算法编码结果很难用肉眼识别解码,但它仍可以极为轻松地被计算机所解码,就像其容易编码一样。编码这一步骤的目的并不是安全与隐私,而是为将用户名和口令中的不兼容的字符转换为均与HTTP协议兼容的字符集。
例子
这一个典型的HTTP客户端和HTTP服务器的对话,服务器安装在同一台计算机上(localhost),包含以下步骤:
客户端请求一个需要身份认证的页面,但是没有提供用户名和口令。这通常是用户在地址栏输入一个URL,或是打开了一个指向该页面的链接。
服务端响应一个401应答码,并提供一个认证域。
接到应答后,客户端显示该认证域(通常是所访问的计算机或系统的描述)给用户并提示输入用户名和口令。此时用户可以选择确定或取消。
用户输入了用户名和口令后,客户端软件会在原先的请求上增加认证消息头(值是base64encode(username+":"+password)),然后重新发送再次尝试。
在本例中,服务器接受了该认证屏幕并返回了页面。如果用户凭据非法或无效,服务器可能再次返回401应答码,客户端可以再次提示用户输入口令。
注意:客户端有可能不需要用户交互,在第一次请求中就发送认证消息头。
客户端请求(没有认证信息):
1 GET /private/index.html HTTP/1.0
2
3 Host: localhost
(跟随一个换行,以回车(CR)加换行(LF)的形式)
服务端应答:
1 HTTP/1.0 401Authorization Required2 Server: HTTPd/1.0
3 Date: Sat, 27 Nov 2004 10:18:15GMT4 WWW-Authenticate: Basic realm="Secure Area"
5 Content-Type: text/html6 Content-Length: 311
7
8 /p>
9 "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
10
11
12
Error13
14
15
401 Unauthorized.16
客户端的请求(用户名“"Aladdin”,口令, password “open sesame”):
1 GET /private/index.html HTTP/1.0
2 Host: localhost3 Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
(跟随一个空行,如上所述)
Authorization消息头的用户名和口令的值可以容易地编码和解码:
服务端的应答 :
1 HTTP/1.0 200OK2 Server: HTTPd/1.0
3 Date: Sat, 27 Nov 2004 10:19:07GMT4 Content-Type: text/html5 Content-Length: 10476
所以,用python解决问题的话:
1 importurllib22 importsys3 importre4 importbase645 from urlparse importurlparse6
7 theurl = 'http://api.minicloud.com.cn/statuses/friends_timeline.xml'
8
9 username = 'qleelulu'
10 password = 'XXXXXX' #你信这是密码吗?
11
12 base64string =base64.encodestring(13 '%s:%s' % (username, password))[:-1] #注意哦,这里最后会自动添加一个n
14 authheader = "Basic %s" %base64string15 req.add_header("Authorization", authheader)16 try:17 handle =urllib2.urlopen(req)18 exceptIOError, e:19 #here we shouldn't fail if the username/password is right
20 print "It looks like the username or password is wrong."
21 sys.exit(1)22 thepage = handle.read()
就是在header中加上:
1 base64string = base64.encodestring('username:password')[:-1]2 authheader = "Basic %s" %base64string3 headers['Authorization'] = authheader
r案后再请求就可以了。原理就是添加了请求头Authorization。