web-dev-qa-db-ja.com

Pythonリクエスト:単一のリクエストでJSONとファイルを投稿する

API呼び出しを行って、ファイルの詳細を含むJSON文字列とともにファイルをアップロードする必要があります。

python要求libを使用してこれを実行しようとしています:

import requests

info = {
    'var1' : 'this',
    'var2'  : 'that',
}

data = json.dumps({
    'token' : auth_token,
    'info'  : info,
})

headers = {'Content-type': 'multipart/form-data'}

files = {'document': open('file_name.pdf', 'rb')}

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

これにより、次のエラーがスローされます。

    raise ValueError("Data must not be a string.")
 ValueError: Data must not be a string

リクエストから「ファイル」を削除すると、機能します。
リクエストから「データ」を削除すると、機能します。
JSONとしてデータをエンコードしない場合、動作します。

このため、エラーはJSONデータとファイルを同じリクエストで送信することに関係していると思います。

これを機能させる方法についてのアイデアはありますか?

26
oznu

Jsonを使用してエンコードしないでください。

import requests

info = {
    'var1' : 'this',
    'var2'  : 'that',
}

data = {
    'token' : auth_token,
    'info'  : info,
}

headers = {'Content-type': 'multipart/form-data'}

files = {'document': open('file_name.pdf', 'rb')}

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

これは別のフォームデータセクションになるため、必ずしも必要なものではないことに注意してください。

19
proteneer

このスレッドを参照してください マルチパートPOSTリクエストの一部としてJSONを送信する方法

自分でContent-typeヘッダーを設定しないで、生成するpyrequestsにそのままにしてください

def send_request():
payload = {"param_1": "value_1", "param_2": "value_2"}
files = {
     'json': (None, json.dumps(payload), 'application/json'),
     'file': (os.path.basename(file), open(file, 'rb'), 'application/octet-stream')
}

r = requests.post(url, files=files)
print(r.content)
14
ralf htp

マルチパートでエンコードされたファイルでデータとファイルの両方を送信できるとは思わないので、データも「ファイル」にする必要があります。

files = {
    'data' : data,
    'document': open('file_name.pdf', 'rb')
}

r = requests.post(url, files=files, headers=headers)
2
AChampion

Facebook Messenger APIを送信するために、すべてのペイロードディクショナリ値を文字列に変更しました。その後、ペイロードをdataパラメーターとして渡すことができます。

import requests

ACCESS_TOKEN = ''

url = 'https://graph.facebook.com/v2.6/me/messages'
payload = {
        'access_token' : ACCESS_TOKEN,
        'messaging_type' : "UPDATE",
        'recipient' : '{"id":"1111111111111"}',
        'message' : '{"attachment":{"type":"image", "payload":{"is_reusable":true}}}',
}
files = {'filedata': (file, open(file, 'rb'), 'image/png')}
r = requests.post(url, files=files, data=payload)
0
wannik

さらに何ですか:

files = {
    'document': open('file_name.pdf', 'rb')
}

ファイルがスクリプトと同じディレクトリにある場合にのみ機能します。

別のディレクトリからファイルを追加する場合は、次を実行する必要があります。

files = {
    'document': open(os.path.join(dir_path, 'file_name.pdf'), 'rb')
}

dir_path'file_name.pdf'ファイルがあるディレクトリです。

しかし、複数のPDFを送信したい場合はどうでしょうか?

必要なファイルのリストを返すためのカスタム関数を作成するだけです(この場合、拡張子は。pdfのファイルのみです)。これには、サブディレクトリ内のファイルも含まれます(ファイルを再帰的に検索します)。

def prepare_pdfs():
    return sorted([os.path.join(root, filename) for root, dirnames, filenames in os.walk(dir_path) for filename in filenames if filename.endswith('.pdf')])

それからあなたはそれを呼び出すことができます:

my_data = prepare_pdfs()

そして、単純なループで:

for file in my_data:

    pdf = open(file, 'rb')

    files = {
        'document': pdf
    }

    r = requests.post(url, files=files, ...)
0
tc_qa