Pythonでmultipart/form-dataの送受信
はじめに
以下記事の通り、AWS上のLambdaを使って機械学習モデルのAPIを立てたのですが、
Pythonでmultipart/form-data
のパースが大変だったので共有します。
tmyoda.hatenablog.com
送信
requests
モジュールを使用すればかんたんです。
以下記事が参考になります。
files = {} mine_type = "image/jpeg" file_name = "input_image_quart.jpg" data = なんかバイト列 files = {'key': (file_name, data, mine_type)} r = requests.post(endpoint, files=files)
ちなみに、headers
もpost
の引数に指定できますが、Content-Type
を上書きしてしまうと、boundary
も消えるのでご注意下さい。
(2時間近くハマりました)
受信
AWSのLambda
AWSのLambda限定ですが、以下のパースするスクリプトをStackoverflowで見つけました。
cgi
はデフォルトで入っているので、モジュールを追加する必要はありません。
def lambda_handler(event, context): if 'content-type' in event['headers'].keys(): c_type, c_data = parse_header(event['headers']['content-type']) elif 'Content-Type' in event['headers'].keys(): c_type, c_data = parse_header(event['headers']['Content-Type']) else: raise RuntimeError('content-type or Content-Type not found') encoded_string = event['body'].encode('utf-8') # For Python 3: these two lines of bugfixing are mandatory # see also: # https://stackoverflow.com/questions/31486618/cgi-parse-multipart-function-throws-typeerror-in-python-3 c_data['boundary'] = bytes(c_data['boundary'], "utf-8") # c_data['CONTENT-LENGTH'] = event['headers']['Content-length'] data_dict = parse_multipart(io.BytesIO(encoded_string), c_data) # 整形 formatted_dict = {k: v[0] for k, v in data_dict.items()}
その他
上のstackoverflowからのコピペで恐縮ですが、以下のサンプルがわかりやすいです。
requests_toolbelt
のインストールが別途必要です。
from requests_toolbelt.multipart import decoder multipart_string = b"--ce560532019a77d83195f9e9873e16a1\r\nContent-Disposition: form-data; name=\"author\"\r\n\r\nJohn Smith\r\n--ce560532019a77d83195f9e9873e16a1\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example2.txt\"\r\nContent-Type: text/plain\r\nExpires: 0\r\n\r\nHello World\r\n--ce560532019a77d83195f9e9873e16a1--\r\n" content_type = "multipart/form-data; boundary=ce560532019a77d83195f9e9873e16a1" for part in decoder.MultipartDecoder(multipart_string, content_type).parts: print(part.text) John Smith Hello World