Python 如何批量发送包含多个URL的多部分html帖子?
我正在与gmail api交谈,我想批量处理请求。他们在这里有一个友好的指南,建议我应该能够使用multipart/mixed并包含不同的URL 我正在使用Python和请求库,但不确定如何发布不同的URL。像这样的答案并没有提到改变那个部分的选项 如何做到这一点?不幸的是,请求在其API中不支持多部分/混合。这已经在一些GitHub问题(和)中提出,但目前还没有更新。如果您在请求源中搜索“混合”并得到零结果,这一点也会变得非常清楚:( 现在您有了几个选项,这取决于您希望使用Python和第三方库的程度 谷歌API客户端 现在,这个问题最明显的答案是使用Google提供的官方Python API。它附带了一个Python 如何批量发送包含多个URL的多部分html帖子?,python,python-requests,multipartform-data,gmail-api,Python,Python Requests,Multipartform Data,Gmail Api,我正在与gmail api交谈,我想批量处理请求。他们在这里有一个友好的指南,建议我应该能够使用multipart/mixed并包含不同的URL 我正在使用Python和请求库,但不确定如何发布不同的URL。像这样的答案并没有提到改变那个部分的选项 如何做到这一点?不幸的是,请求在其API中不支持多部分/混合。这已经在一些GitHub问题(和)中提出,但目前还没有更新。如果您在请求源中搜索“混合”并得到零结果,这一点也会变得非常清楚:( 现在您有了几个选项,这取决于您希望使用Python和第三方
HttpBatchRequest
类,可以处理您需要的批处理请求。这在中有详细的说明
基本上,您创建一个HttpBatchRequest
对象,并将所有请求添加到该对象中。然后,库将把所有内容放在一起(摘自上面的指南):
现在,如果出于任何原因,您不能或不愿意使用官方的Google库,那么您必须自己构建部分请求主体
请求+email.mime
正如我已经提到的,请求并不正式支持multipart/mixed
。但这并不意味着我们不能“强制”它。当创建Request
对象时,我们可以使用参数来提供多部分数据
files
是一个接受以下格式的4元组值的字典:(文件名、文件对象、内容类型、标题)。文件名可以为空。现在我们需要将请求
对象转换为文件(-like)我写了一个小方法,涵盖了Google示例中的基本示例。它的部分灵感来自Google在Python库中使用的内部方法:
import requests
from email.mime.multipart import MIMEMultipart
from email.mime.nonmultipart import MIMENonMultipart
BASE_URL = 'http://www.googleapis.com/batch'
def serialize_request(request):
'''Returns the string representation of the request'''
mime_body = ''
prepared = request.prepare()
# write first line (method + uri)
if request.url.startswith(BASE_URL):
mime_body = '%s %s\r\n' % (request.method, request.url[len(BASE_URL):])
else:
mime_body = '%s %s\r\n' % (request.method, request.url)
part = MIMENonMultipart('application', 'http')
# write headers (if possible)
for key, value in prepared.headers.iteritems():
mime_body += '%s: %s\r\n' % (key, value)
if getattr(prepared, 'body', None) is not None:
mime_body += '\r\n' + prepared.body + '\r\n'
return mime_body.encode('utf-8').lstrip()
此方法将requests.Request
对象转换为UTF-8编码的字符串,该字符串稍后可用于mimonmultipart
对象的有效负载,即不同的多部分
现在,为了生成实际的批处理请求,我们首先需要压缩一个列表(GoogleAPI)请求进入请求库的文件
字典。以下方法将获取请求列表。请求
对象,将每个对象转换为mimonmultipart,然后返回符合文件
字典结构的字典:
import uuid
def prepare_requests(request_list):
message = MIMEMultipart('mixed')
output = {}
# thanks, Google. (Prevents the writing of MIME headers we dont need)
setattr(message, '_write_headers', lambda self: None)
for request in request_list:
message_id = new_id()
sub_message = MIMENonMultipart('application', 'http')
sub_message['Content-ID'] = message_id
del sub_message['MIME-Version']
sub_message.set_payload(serialize_request(request))
# remove first line (from ...)
sub_message = str(sub_message)
sub_message = sub_message[sub_message.find('\n'):]
output[message_id] = ('', str(sub_message), 'application/http', {})
return output
def new_id():
# I am not sure how these work exactly, so you will have to adapt this code
return '<item%s:12930812@barnyard.example.com>' % str(uuid.uuid4())[-4:]
我已经尽了最大努力,通过《批处理指南》中的谷歌示例来测试这一点:
sheep = {
"animalName": "sheep",
"animalAge": "5",
"peltColor": "green"
}
commands = []
commands.append(requests.Request('GET', 'http://www.googleapis.com/batch/farm/v1/animals/pony'))
commands.append(requests.Request('PUT', 'http://www.googleapis.com/batch/farm/v1/animals/sheep', json=sheep, headers={'If-Match': '"etag/sheep"'}))
commands.append(requests.Request('GET', 'http://www.googleapis.com/batch/farm/v1/animals', headers={'If-None-Match': '"etag/animals"'}))
files = prepare_requests(commands)
r = requests.Request('POST', 'http://www.googleapis.com/batch', files=files)
prepared = r.prepare()
finalize_request(prepared)
s = requests.Session()
s.send(prepared)
POST http://www.googleapis.com/batch
Content-Length: 1006
Content-Type: multipart/mixed; boundary=a21beebd15b74be89539b137bbbc7293
--a21beebd15b74be89539b137bbbc7293
Content-Type: application/http
Content-ID: <item8065:12930812@barnyard.example.com>
GET /farm/v1/animals
If-None-Match: "etag/animals"
--a21beebd15b74be89539b137bbbc7293
Content-Type: application/http
Content-ID: <item5158:12930812@barnyard.example.com>
GET /farm/v1/animals/pony
--a21beebd15b74be89539b137bbbc7293
Content-Type: application/http
Content-ID: <item0ec9:12930812@barnyard.example.com>
PUT /farm/v1/animals/sheep
Content-Length: 63
Content-Type: application/json
If-Match: "etag/sheep"
{"animalAge": "5", "animalName": "sheep", "peltColor": "green"}
--a21beebd15b74be89539b137bbbc7293--
最终的请求应该足够接近谷歌在其批处理指南中提供的内容:
sheep = {
"animalName": "sheep",
"animalAge": "5",
"peltColor": "green"
}
commands = []
commands.append(requests.Request('GET', 'http://www.googleapis.com/batch/farm/v1/animals/pony'))
commands.append(requests.Request('PUT', 'http://www.googleapis.com/batch/farm/v1/animals/sheep', json=sheep, headers={'If-Match': '"etag/sheep"'}))
commands.append(requests.Request('GET', 'http://www.googleapis.com/batch/farm/v1/animals', headers={'If-None-Match': '"etag/animals"'}))
files = prepare_requests(commands)
r = requests.Request('POST', 'http://www.googleapis.com/batch', files=files)
prepared = r.prepare()
finalize_request(prepared)
s = requests.Session()
s.send(prepared)
POST http://www.googleapis.com/batch
Content-Length: 1006
Content-Type: multipart/mixed; boundary=a21beebd15b74be89539b137bbbc7293
--a21beebd15b74be89539b137bbbc7293
Content-Type: application/http
Content-ID: <item8065:12930812@barnyard.example.com>
GET /farm/v1/animals
If-None-Match: "etag/animals"
--a21beebd15b74be89539b137bbbc7293
Content-Type: application/http
Content-ID: <item5158:12930812@barnyard.example.com>
GET /farm/v1/animals/pony
--a21beebd15b74be89539b137bbbc7293
Content-Type: application/http
Content-ID: <item0ec9:12930812@barnyard.example.com>
PUT /farm/v1/animals/sheep
Content-Length: 63
Content-Type: application/json
If-Match: "etag/sheep"
{"animalAge": "5", "animalName": "sheep", "peltColor": "green"}
--a21beebd15b74be89539b137bbbc7293--
POSThttp://www.googleapis.com/batch
内容长度:1006
内容类型:多部分/混合;边界=a21beebd15b74be89539b137bbbc7293
--a21beebd15b74be89539b137bbbc7293
内容类型:应用程序/http
内容ID:
获取/农场/v1/动物
如果没有匹配:“etag/动物”
--a21beebd15b74be89539b137bbbc7293
内容类型:应用程序/http
内容ID:
获取/农场/v1/动物/小马
--a21beebd15b74be89539b137bbbc7293
内容类型:应用程序/http
内容ID:
PUT/农场/v1/动物/绵羊
内容长度:63
内容类型:application/json
如果匹配:“etag/羊”
{“动物名称”:“5”,“动物名称”:“绵羊”,“毛皮颜色”:“绿色”}
--a21beebd15b74be89539b137bbbc7293--
最后,我强烈推荐谷歌官方图书馆,但如果你不能使用它,你将不得不临时凑合一下:)
免责声明:我实际上没有尝试将此请求发送到Google API端点,因为身份验证过程太麻烦了。我只是试图尽可能接近批处理指南中描述的HTTP请求。根据Google端点的严格程度,\r和\n行结尾可能会有一些问题
来源:
- (特别是第935期和第1081期)