Python 如何批量发送包含多个URL的多部分html帖子?

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和第三方

我正在与gmail api交谈,我想批量处理请求。他们在这里有一个友好的指南,建议我应该能够使用multipart/mixed并包含不同的URL

我正在使用Python和请求库,但不确定如何发布不同的URL。像这样的答案并没有提到改变那个部分的选项

如何做到这一点?

不幸的是,请求在其API中不支持多部分/混合。这已经在一些GitHub问题(和)中提出,但目前还没有更新。如果您在请求源中搜索“混合”并得到零结果,这一点也会变得非常清楚:(

现在您有了几个选项,这取决于您希望使用Python和第三方库的程度

谷歌API客户端 现在,这个问题最明显的答案是使用Google提供的官方Python API。它附带了一个
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期)

多好的概述,完美!