質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Curl(プログラミング言語)

Curl(プログラミング言語)は、Webコンテンツ向けのプログラミング言語。HTMLのようなテキスト記述やレイアウトデザイン、JavaScript のようなオブジェクト指向プログラム言語、Java のような重量機能など複数の言語の特徴を一つのフレームワークに統合しています。

cURL

cURLはHTTP, FTPやTelnetなど複数のプロトコルを用いてデータを転送するライブラリとコマンドラインツールを提供します。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

3100閲覧

【curl -F hoge=・・】に対応する【Python Requestsモジュール】の書き方がわからない..

oppai

総合スコア2

Curl(プログラミング言語)

Curl(プログラミング言語)は、Webコンテンツ向けのプログラミング言語。HTMLのようなテキスト記述やレイアウトデザイン、JavaScript のようなオブジェクト指向プログラム言語、Java のような重量機能など複数の言語の特徴を一つのフレームワークに統合しています。

cURL

cURLはHTTP, FTPやTelnetなど複数のプロトコルを用いてデータを転送するライブラリとコマンドラインツールを提供します。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/10/31 09:33

背景

現在、python requestsライプラリを用いて、Boxと呼ばれるクラウドサービスにおける、
ファイルアップロードAPIエンドポイント(BoxAPIリファレンス)へPOSTリクエストを行っております.

問題

下記のPython upload_file関数を実行して、Box APIから発行されたアクセストークンを用いて、
ファイルアップロードしようとしています.
ここで、問題として、pythonのRequestsモジュールを使用したときにcurl -Fオプションコマンドに対応するコードは、どう書いたら良いのか??です。
もし知っている方がいらっしゃいましたら、教えていただけないでしょうか??

Python

1def upload_file(self, mime_type, file_path, newfile_name, parent_id): 2 """ 3 Boxサービスに対して、ファイルをアップロードする関数 4 5 Parameters 6 ---------- 7 mime_type : str 8 アップロードするファイルのMIME TYPE 9 file_path : str 10 アップロードするファイルパス 11 newfile_name : str 12 アップロード後のファイル名 13 parent_id : str 14 アップロードするファイルの親フォルダID 15 16 Returns 17 ---------- 18 Http Responseの内容 19 """ 20 headers = { 21 "Authorization": f"Bearer {self.access_token}", 22 "Content-Type": "multipart/form-data" 23 } 24 file_bin = open(file_path, 'rb').read() 25 files_json = {'file': (newfile_name, file_bin, mime_type)} 26 item_data = { 27 "attributes" : { 28 "name" : newfile_name, 29 "parent" : { 30 "id" : parent_id 31 } 32 } 33 } 34 # TODO (curl -Fオプションの場合、requests.postはどう対応されるのか) 35 response = requests.post(self.UPLOAD_API + "files/content/", json=item_data, files=files_json) 36 37 print(response.status_code) 38 print(response.content)

error

1400 # クライアント側エラー.. 2b'{"code":"bad_request","help_url":"http://developers.box.com/docs/#errors","status":400,"message":"Invalid API request path /api/2.0/files/content/","type":"error"}'

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

toast-uz

2020/10/31 13:15

curl -F でBOXにアップロードはできているのでしょうか?
oppai

2020/10/31 13:44

toast-uz さんへ、ご質問ありがとうございます!たった今、curlコマンドで試してみたのですが、同様のエラーが出てきていたので、Python側の問題ではないとわかりました。そして、curlコマンドをより精査したところ、ダブルクオーテーションの中にダブルクオーテーションがあるという単純なミスであったことがわかり、curl 側で通すことができたので、今からPython側も修正しようと思います。もし解決できた場合は、回答を載せておこうと思います。すみません、ありがとうございます!!
guest

回答1

0

ベストアンサー

BOXのリファレンス上のcurlでのポスト例には

-F attributes="{"name":"Contract.pdf", "parent":{"id":"11446498"}}"

という行がありますが、この例文のようにattributesオプションの構造をそのまま辞書化またはJSONフォーマット文字列にしてrequestsで指定しまうと、
うまくattributesの内容がBOX APIに渡らないようです。

したがって、下記のように、parent_idだけ別途、requestsモジュールのdataパラメータに指定してPOSTしてやるか、json.dumpsを使用して、ネストされたパラメータを文字列化して渡す必要があります。

<全文>

import requests class Uploader: def __init__(self, access_token): # API エンドポイント self.UPLOAD_API = "https://upload.box.com/api/2.0/" self.access_token = access_token def upload_file(self, file_path, newfile_name, parent_id): headers = { "Authorization": f"Bearer {self.access_token}" } file_bin = open(file_path, 'rb').read() data = { "parent_id": parent_id } ''' または、下記のようにする。 data = { "attributes" : json.dumps({ "name" : newfile_name, "parent" : { "id" : parent_id } }) } ''' # requestsでファイルアップロードするときの構成 files = {"file" : (newfile_name, file_bin)} # requests.postのやりかた response = requests.post(self.UPLOAD_API + "files/content", data=data, files=files, headers=headers) # status_code 201 が返ってくれば正常にアップロードされているはず。 print(response.status_code) print(response.content) # プログラムのエントリポイント # 開発者トークンを引数に指定 uploader = Uploader("YOUR_DEVELOPER_TOKEN") # parent_idは文字列で指定。この例では"0"すなわちBOXのルートディレクトリを指定している。 uploader.upload_file(file_path="C:/temp/test.bin", newfile_name="test.bin", parent_id="0")

(その他)
元質問文では、APIエンドポイントのURLが(コピペミスなのか)誤っています。
"files/content/" ではなく 正しくは"files/content"(末尾スラッシュなし)です。

(まとめ)
そもそもcURLとpythonのrequestsは完全に一対一対応するものではありません。
cURLは原始的な手段であり、上記のようなURLコピペミス1つでも、正常に動作しないことがあります。

また今後、APIの仕様が変わる可能性もあります。
したがって、pythonでBOXを使用する場合は、cURLではなく、BOXのpython ライブラリ(https://github.com/box/box-python-sdk)を使用されることを強く推奨します。

投稿2020/10/31 13:48

編集2020/10/31 14:45
sfdust

総合スコア1135

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

oppai

2020/10/31 14:15

sfdustさん、非常に詳細かつ素晴らしいご指摘ありがとうございます。curlとpython requestsでは完全一致ではないこと、身を以てしりました。すみません、真夜中なのに再度ご質問させてください。upload_file()関数の中にある、data辞書内の、"parent_id"キーは、python sdk内のプログラムから、探したものなのでしょうか??
sfdust

2020/10/31 14:36 編集

回答ソース内にdataの別の指定方法も追記しました。(「または下記のようにする」以下)。これならばcURLの記述と似た形になります。 data辞書内の、"parent_id"キーですが、ソースに attributes = request.forms.get('attributes') or request.forms.get('metadata') という行があり、これによりattributeの中に指定しても、直接parent_idキーを指定しても同じとして解釈されるようだったので、 直接指定したところうまく行っただけです。 正攻法は回答ソースのコメント中にあるjson.dumpsを使う方法になります。
oppai

2020/10/31 14:48

なるほど、sfdustさん、すごいですね.. 自分も貴殿のようなエンジニアになれるよう精進します! ありがとうございました.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問