首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >上传包含Python请求库的大型XML文件

上传包含Python请求库的大型XML文件
EN

Stack Overflow用户
提问于 2012-11-11 21:42:03
回答 3查看 6.7K关注 0票数 5

我正在尝试用Python & requests库替换curl。使用curl,我可以使用curl -T选项将单个XML文件上传到REST服务器。我无法对requests库做同样的事情。

一个基本的场景是:

代码语言:javascript
复制
payload = '<person test="10"><first>Carl</first><last>Sagan</last></person>'
headers = {'content-type': 'application/xml'}
r = requests.put(url, data=payload, headers=headers, auth=HTTPDigestAuth("*", "*"))

当我通过打开一个XML文件将有效负载更改为更大的字符串时,.put方法挂起(我使用编解码器库来获得正确的unicode字符串)。例如,对于66KB的文件:

代码语言:javascript
复制
xmlfile = codecs.open('trb-1996-219.xml', 'r', 'utf-8')
headers = {'content-type': 'application/xml'}
content = xmlfile.read()
r = requests.put(url, data=content, headers=headers, auth=HTTPDigestAuth("*", "*"))

我一直在考虑使用multipart选项(文件),但服务器似乎不喜欢这样。

所以我想知道是否有一种方法可以在Python请求库中模拟curl -T行为。

更新1:程序在textmate中挂起,但在命令行中抛出UnicodeEncodeError错误。看起来这一定是问题所在。所以问题是:有没有一种方法可以将unicode字符串与请求库一起发送到服务器?

更新2:多亏了Martijn的评论,UnicodeEncodeError消失了,但新的问题出现了。对于文字(ASCII) XML字符串,日志记录显示以下行:

代码语言:javascript
复制
2012-11-11 15:55:05,154 INFO Starting new HTTP connection (1): my.ip.address
2012-11-11 15:55:05,294 DEBUG "PUT /v1/documents?uri=/example/test.xml HTTP/1.1" 401 211
2012-11-11 15:55:05,430 DEBUG "PUT /v1/documents?uri=/example/test.xml HTTP/1.1" 201 0

服务器似乎总是退回第一次身份验证尝试(?)然后再接受第二个。

通过将文件对象(open('trb-1996-219.xml','rb'))传递给data,日志文件显示:

代码语言:javascript
复制
2012-11-11 15:50:54,309 INFO Starting new HTTP connection (1): my.ip.address
2012-11-11 15:50:55,105 DEBUG "PUT /v1/documents?uri=/example/test.xml HTTP/1.1" 401 211
2012-11-11 15:51:25,603 WARNING Retrying (0 attempts remain) after connection broken by 'BadStatusLine("''",)': /v1/documents?uri=/example/test.xml

因此,第一次尝试会像以前一样被阻止,但不会进行第二次尝试。

根据Martijn (下面)的说法,第二个问题可以通过故障服务器(空行)来解释。我会调查这个问题,但如果有人有解决办法(除了使用curl),我不介意听到它。

我仍然对requests库对于小字符串和文件对象的行为如此不同感到惊讶。文件对象在到达服务器之前不是序列化的吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-11-11 22:01:12

要放入大文件,请不要将它们读入内存。只需将文件作为data关键字传递即可:

代码语言:javascript
复制
xmlfile = open('trb-1996-219.xml', 'rb')
headers = {'content-type': 'application/xml'}
r = requests.put(url, data=xmlfile, headers=headers, auth=HTTPDigestAuth("*", "*"))

此外,您以unicode格式打开文件(从UTF-8解码它)。因为您将把它发送到远程服务器,所以您需要原始字节,而不是Unicode值,您应该以二进制格式打开该文件。

票数 9
EN

Stack Overflow用户

发布于 2013-05-17 16:14:12

摘要身份验证始终要求您至少向服务器发出两个请求。第一个请求不包含任何身份验证数据。第一个请求将失败,并返回一个401 "Authorization required“响应码和一个用于散列您的密码等的摘要挑战(称为This )(确切的细节在这里无关紧要)。这用于向服务器发出包含您的凭据的第二个请求,该凭据与质询一起散列。

问题出在这两步身份验证中:您的大文件已经与第一个未经授权的请求一起发送(无效发送),但是在第二个请求中,文件对象已经位于EOF位置。由于文件大小也是在第二个请求的Content-length头中发送的,这会导致服务器等待一个永远不会发送的文件。

您可以使用一个请求会话来解决这个问题,并首先出于身份验证的目的发出一个简单的请求(比如GET请求)。然后,使用与第一个请求相同的摘要质询,发出包含实际有效负载的第二个PUT请求。

代码语言:javascript
复制
sess = requests.Session()
sess.auth = HTTPDigestAuth("*", "*")
sess.get(url)
headers = {'content-type': 'application/xml'}
with codecs.open('trb-1996-219.xml', 'r', 'utf-8') as xmlfile:
    sess.put(url, data=xmlfile, headers=headers)
票数 1
EN

Stack Overflow用户

发布于 2018-07-24 19:09:08

我使用python中的请求通过命令上传了一个XML文件。首先打开文件,使用open() file = open("PIR.xsd") fragment = file.read() file.close()复制请求有效负载中的XML文件的数据并将其发布到payload = {'key':'PFAkrzjmuZR957','xmlFragment':fragment} r = requests.post(URL,data=payload)以检查html验证码print (r.text)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13331640

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档