2013-04-01 14 views
8

私は、Pythonでリクエストを使用してマルチパート/関連メッセージを送信しようとしています。このスクリプトは、ドキュメントが明らかにこのようなことを明記していないにもかかわらず、複数の/フォームデータメッセージを送信できるようにする要求を除いて、単純なように見えます。リクエストで「マルチパート/関連」をどのように送信するのですか?

私の使用例は、添付ファイル付きの石鹸を送信しています。私は、内容がテスト石鹸メッセージである2つのファイルと、送信しようとしているテスト文書を辞書に提供できます。最初のものはすべての指示を含む石鹸メッセージを含み、2番目のものは実際の文書です。

ただし、ヘッダーの値を指定しないと、filesオプションを使用している場合にのみmultipart/form-dataが使用されます。しかし、異なるマルチパートタイプを指定しようとしてヘッダを指定すると、リクエストはMIME境界情報を追加していないようです。

url = 'http://10.10.10.90:8020/foo' 
headers = {'content-type': 'multipart/related'} 
files = {'submission': open('submission_set.xml', 'rb'), 'document': open('document.txt', 'rb')} 
response = requests.post(url, data=data, headers=headers) 
print response.text 

リクエストを使用してこれを行う方法はありますか?それとも、私が見なければならない別のツールがありますか?

+0

[python] [python-requests] + multipart'を検索した結果、これらの22の質問を確認しましたか? –

+3

@PiotrDobrogost:これらは 'multipart/form-data'に関するもので、' requests'があなたのために処理します。これは* 'multipart/related' *です。これは' POST'の共通エンコーディングではなく、 'requests'は自動的にそれを処理しません。 –

答えて

19

あなた自身でMIMEエンコードを作成する必要があります。あなたはemail.mimeパッケージでそうすることができます。

import requests 
from email.mime.multipart import MIMEMultipart 
from email.mime.text import MIMEText 

related = MIMEMultipart('related') 

submission = MIMEText('text', 'xml', 'utf8') 
submission.set_payload(open('submission_set.xml', 'rb').read()) 
related.attach(submission) 

document = MIMEText('text', 'plain') 
document.set_payload(open('document.txt', 'rb').read()) 
related.attach(document) 

body = related.as_string().split('\n\n', 1)[1] 
headers = dict(related.items()) 

r = requests.post(url, data=body, headers=headers) 

私はXMLファイルを使用すると、おそらく同様にdocumentエントリの文字セットを設定したい場合は、UTF-8を使用していますと推定します。

requestsポストボディmultipart/form-dataの作成方法のみを知っています。 multipart/relatedは一般的には使用されません。

+0

ありがとう!これは非常に役に立ちます。私は実際に以前の 'email.mime'パッケージを使ってみましたが、2つのサービスを結びつける方法を理解できませんでした。あなたは私の2つの代替スクリプトを1つに統合する手助けをしました! しかし、小さな問題があるようで、サービスの組み合わせか他の何らかの過ちであるかどうかはわかりません。[row、col {unknown-source}]:[1,0] 'のプロローグで予期せぬEOFが表示され、送信される最初の文字がEOFとして相互運用されているように見えます。これはツールチェーン/エンコーディングのためでしょうか? –

+0

私は全く考えていません。 XML解析の問題のように聞こえるが、そのエラーはよく知られていない。 –

+0

これは素晴らしいようですが、私の要求は永久にハングアップするようです。すべての手がかりは? – zapatilla

0

私はrequestsとGoogleドライブAPIの「マルチパート」アップロードを行っています。

email.mimeのソリューションはGoogleのAPIでは動作しませんでした。multipart/form-dataボディの実装方法を確認するには、requestsソースコードを掘りました。

ここ
import json 
from urllib3.fields import RequestField 

def encode_media_related(metadata, media, media_content_type): 
    rf1 = RequestField(
     name='placeholder', 
     data=json.dumps(metadata), 
     headers={'Content-Type': 'application/json; charset=UTF-8'}, 
    ) 
    rf2 = RequestField(
     name='placeholder2', 
     data=media, 
     headers={'Content-Type': media_content_type}, 
    ) 
    return encode_multipart_related([rf1, rf2]) 

は次のとおりです。

from urllib3.filepost import encode_multipart_formdata, choose_boundary 

def encode_multipart_related(fields, boundary=None): 
    if boundary is None: 
     boundary = choose_boundary() 

    body, _ = encode_multipart_formdata(fields, boundary) 
    content_type = str('multipart/related; boundary=%s' % boundary) 

    return body, content_type 

は、今、私たちはGoogleの要件に合致する(body, content_type)タプルを作成するためにencode_multipart_related()を使用することができます。

requestsmultipart/relatedを提供するためにラップすることができurllib3.filepost.encode_multipart_formdata()ヘルパーを使用していますencode_media_related()を使用して、google_authライブラリを使用して、helloワールドファイルをGoogleドライブにアップロードする完全な例です。

from google.oauth2 import service_account 
import google.auth.transport.requests 

credentials = service_account.Credentials.from_service_account_file(
    PATH_TO_SERVICE_FILE, 
    scopes=['https://www.googleapis.com/auth/drive.file'], 
) 
session = google.auth.transport.requests.AuthorizedSession(credentials) 

metadata = { 
    'mimeType': 'application/vnd.google-apps.document', 
    'name': 'Test Upload', 
} 
body, content_type = encode_media_related(
    metadata, 
    '<html><body><p>Hello World!</body></html>', 
    'text/html; charset=UTF-8', 
) 
resp = session.post(
    'https://www.googleapis.com/upload/drive/v3/files', 
    data=body, 
    params={'uploadType': 'multipart'}, 
    headers={'Content-Type': content_type}, 
) 

print 'Uploaded to file with id: %s' % resp.json()['id'] 
関連する問題