博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python中利用urllib2使用POST方式上传文件,并解决Authorization问题
阅读量:6974 次
发布时间:2019-06-27

本文共 4774 字,大约阅读时间需要 15 分钟。

  hot3.png

    最近要用 Python 模拟表单上传文件,搜索了一下常见的解决方案。

    如果只是要模拟提交一个不包含文件字段的表单,实现起来是很简单的,但涉及到文件上传就有一点小复杂,需要自己对文件进行编码,或者使用第三方模块。

  如果机器上有 ,那么可以

  不过,由于 PycURL 需要用到 curl,在 Windows 下安装可能会有点麻烦,除 PycURL 外,也有一些其它实现 POST 文件上传的方式,比如  的 2 楼有人贴出了一个将文件进行编码之后再 POST 的方法,另外还有 等第三方模块。但 MultipartPostHandler 这个模块似乎比较老了,urllib2_file 我试用了一下遇到错误没有成功,这儿我想介绍的是另外一个第三方模块 poster。

  如果机器上安装了 Python 的 ,可以通过下面的命令来安装 poster:

sudo easy_install poster
# test_client.pyfrom poster.encode import multipart_encodefrom poster.streaminghttp import register_openersimport urllib2# 在 urllib2 上注册 http 流处理句柄register_openers()# 开始对文件 "DSC0001.jpg" 的 multiart/form-data 编码# "image1" 是参数的名字,一般通过 HTML 中的  标签的 name 参数设置# headers 包含必须的 Content-Type 和 Content-Length# datagen 是一个生成器对象,返回编码过后的参数,这里如果有多个参数的话依次添加即可datagen, headers = multipart_encode({"image1": open("DSC0001.jpg", "rb")})# 创建请求对象request = urllib2.Request("http://localhost:5000/upload_image", datagen, headers)# 实际执行请求并取得返回print urllib2.urlopen(request).read()

很简单,文件就上传完成了。

其中那个 register_openers() 相当于以下操作:

from poster.encode import multipart_encodefrom poster.streaminghttp import StreamingHTTPHandler, StreamingHTTPRedirectHandler, StreamingHTTPSHandlerhandlers = [StreamingHTTPHandler, StreamingHTTPRedirectHandler, StreamingHTTPSHandler]opener = urllib2.build_opener(*handlers)urllib2.install_opener(opener)

另外,poster 也可以携带 cookie,比如:

opener = poster.streaminghttp.register_openers()opener.add_handler(urllib2.HTTPCookieProcessor(cookielib.CookieJar()))params = {'file': open("test.txt", "rb"), 'name': 'upload test'}datagen, headers = poster.encode.multipart_encode(params)request = urllib2.Request(upload_url, datagen, headers)result = urllib2.urlopen(request)
如果在上传过程中遇到Authorization问题:可以自己定义register_openers()方法加入用户验证的handler,例如:
from poster.encode import multipart_encodefrom poster.streaminghttp import StreamingHTTPHandler, StreamingHTTPRedirectHandler, StreamingHTTPSHandler# create a password managerpassword_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()# Add the username and password.# If we knew the realm, we could use it instead of None.# add_password('realm','url','username','password')password_mgr.add_password('realm', 'url', 'username', 'password')handler = urllib2.HTTPBasicAuthHandler(password_mgr)handlers = [handler,StreamingHTTPHandler, StreamingHTTPRedirectHandler, StreamingHTTPSHandler]opener = urllib2.build_opener(*handlers)urllib2.install_opener(opener)

或者直接将上面的内容加到上传文件的代码中。

今天突然图片不能上传了,发现上面的认证方式失效了。很是奇怪。于是再来一种解决方案。

其实问题就是解决python环境下HTTP Basic Authorization  的问题

首先我们要理解

在HTTP中,基本认证是一种用来允许Web浏览器或其他客户端程序在请求时提供用户名和口令形式的身份凭证的一种登录验证方式。

在发送之前是以用户名追加一个冒号然后串接上口令,并将得出的结果字符串再用算法编码。例如,提供的用户名是Aladdin、口令是open sesame,则拼接后的结果就是Aladdin:open sesame,然后再将其用Base64编码,得到QWxhZGRpbjpvcGVuIHNlc2FtZQ==。最终将Base64编码的字符串发送出去,由接收者解码得到一个由冒号分隔的用户名和口令的字符串。

虽然对用户名和口令的Base64算法编码结果很难用肉眼识别解码,但它仍可以极为轻松地被计算机所解码,就像其容易编码一样。编码这一步骤的目的并不是安全与隐私,而是为将用户名和口令中的不兼容的字符转换为均与兼容的字符集。

例子

这一个典型的HTTP客户端和HTTP服务器的对话,服务器安装在同一台计算机上(localhost),包含以下步骤:

  • 客户端请求一个需要身份认证的页面,但是没有提供用户名和口令。这通常是用户在地址栏输入一个,或是打开了一个指向该页面的。
  • 服务端响应一个401,并提供一个认证域。
  • 接到应答后,客户端显示该认证域(通常是所访问的计算机或系统的描述)给用户并提示输入用户名和口令。此时用户可以选择确定或取消。
  • 用户输入了用户名和口令后,客户端软件会在原先的请求上增加认证消息头(值是base64encode(username+":"+password)),然后重新发送再次尝试。
  • 在本例中,服务器接受了该认证屏幕并返回了页面。如果用户凭据非法或无效,服务器可能再次返回401应答码,客户端可以再次提示用户输入口令。

注意:客户端有可能不需要用户交互,在第一次请求中就发送认证消息头。

客户端请求(没有认证信息)

GET /private/index.html HTTP/1.0Host: localhost
(跟随一个换行
,以回车(CR)
换行(LF)
的形式)

服务端应答

HTTP/1.0 401 Authorization RequiredServer: HTTPd/1.0Date: Sat, 27 Nov 2004 10:18:15 GMTWWW-Authenticate: Basic realm="Secure Area"Content-Type: text/htmlContent-Length: 311       Error    

401 Unauthorized.

客户端的请求(用户名“"Aladdin”,口令, password “open sesame”)

GET /private/index.html HTTP/1.0Host: localhostAuthorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

(跟随一个空行,如上所述)

Authorization消息头的用户名和口令的值可以容易地编码和解码:

服务端的应答

HTTP/1.0 200 OKServer: HTTPd/1.0Date: Sat, 27 Nov 2004 10:19:07 GMTContent-Type: text/htmlContent-Length: 10476
所以,用python解决问题的话:

import urllib2 import sys import re import base64 from urlparse import urlparse theurl = 'http://api.minicloud.com.cn/statuses/friends_timeline.xml' username = 'qleelulu' password = 'XXXXXX'  # 你信这是密码吗? base64string = base64.encodestring(                 '%s:%s' % (username, password))[:-1] #注意哦,这里最后会自动添加一个\n authheader =  "Basic %s" % base64string req.add_header("Authorization", authheader) try:     handle = urllib2.urlopen(req) except IOError, e:     # here we shouldn't fail if the username/password is right     print "It looks like the username or password is wrong."     sys.exit(1) thepage = handle.read()
就是在header中加上:

base64string = base64.encodestring('username:password')[:-1]authheader =  "Basic %s" % base64string headers['Authorization'] = authheader
r案后再请求就可以了。
原理就是添加了请求头Authorization。

转载于:https://my.oschina.net/whp/blog/127909

你可能感兴趣的文章
IIS编译器错误信息: CS0016:未能写入输出文件
查看>>
Python 的命令行参数处理 optparse->argparse
查看>>
label和input对齐的方法(转)
查看>>
【算法学习笔记】49.暴力穷举 BFS 剪枝 SJTU OJ 1357 相邻方案
查看>>
T51658 【wsy】签到题
查看>>
mysql 控制台上传数据库
查看>>
洛谷P1196 银河英雄传说
查看>>
aop为系统添加操作日志,注入或配置声明的方式来实现
查看>>
好用的日期控件jeDate
查看>>
Ajax学习之------>Ajax和Json实现无限下拉框联动(上)
查看>>
古今之成大事业、大学问者,必经过三种之境界
查看>>
我的Android进阶之旅------>Android中编解码学习笔记
查看>>
我的Android进阶之旅------>android如何将List请求参数列表转换为json格式
查看>>
转载:负载均衡器技术Nginx和F5的优缺点对比
查看>>
【资源共享】5G AP分析
查看>>
APP测试与Web测试的区别
查看>>
模式识别,计算机视觉领域,期刊
查看>>
AngularJs的UI组件ui-Bootstrap分享(三)——Accordion
查看>>
中缀、前缀和后缀表达式
查看>>
Redis 自定义对象 cannot be cast to java.lang.String
查看>>