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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

3062閲覧

requests.post時に 日本語データでUnicodeEncodeErrorが発生してしまう

XYZ

総合スコア2

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2022/09/05 01:30

前提

pythonで CSVを読んでOracle DBに登録したり、Oracle RestAPI を使い、ERPとOracle DBで受け渡しを行ったりしてります。
requests.post時に UnicodeEncodeErrorが発生してしまいます。
対応方法を教えていただきたいです。

実現したいこと

API操作(あるURLにrequests.post) してOracle  ERP環境に情報登録をしたい

発生している問題・エラーメッセージ

File "c:\Users\XX\20220905\main_test.py", line 945, in main response = requests.post(url, data=json.dumps(json_data, indent=4, ensure_ascii=False), auth=HTTPBasicAuth(user, password), headers=headers) File "C:\Users\XX\Miniconda3\lib\http\client.py", line 168, in _encode raise UnicodeEncodeError( UnicodeEncodeError: 'latin-1' codec can't encode characters in position 66-78: Body ('レジ部') is not valid Latin-1. Use body 部') is not valid Latin-1. Use body.encode('utf-8') if you want to send it encoded in UTF-8.

該当のソースコード

Python

1import requests 2import json 3 4#jsonのセットなど省略 5 6headers = {"content-type": "application/json; charset=utf-8"} 7# response = requests.post(url, json_data, headers=headers) 8response = requests.post(url, data=json.dumps(json_data, indent=4, ensure_ascii=False), headers=headers) 9response.encoding = response.apparent_encoding 10print(response.status_code) 11print(response.text) 12 13・utf-8で情報をPOSTしたい・ ( response.apparent_encoding=”UTF8") 14

試したこと

https://qiita.com/tmhknkmr12/items/0f5c3c6f6584933397f2

補足情報(FW/ツールのバージョンなど)

Python 3.9.12 Anaconda(Miniconda)

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

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

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

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

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

XYZ

2022/09/05 01:40 編集

headers = {"content-type": "text/html; charset=utf-8"} # utf-8でエンコードし、Str型にする urlencode_post_data = urllib.parse.urlencode("{0}".format(json_data).replace("'", '"').encode("utf-8”), encoding="utf-8") response2 = requests.post(url, urlencode_post_data, auth=HTTPBasicAuth(user, password), headers=headers) などで送付すると結果が    ステータス 400    Unable to parse the provided payload ( 提供されたペイロードを解析できません  になってしまいます
quickquip

2022/09/05 01:59 編集

情報の追記をこの欄にしないでください。 質問を編集しましょう。(紛らわしいです/紛れてしまいます)
XYZ

2022/09/05 02:40

了解しました
guest

回答2

0

ベストアンサー

https://requests.readthedocs.io/en/latest/api/#requests.post

data – (optional) Dictionary, list of tuples, bytes, or file-like object to send in the body of the Request.

辞書か、タプルのリストか、bytesか、file-likeかでリクエストのボディを指定する
となっているのに文字列を渡しています。

文字列を渡すと
https://github.com/python/cpython/blob/v3.10.6/Lib/http/client.py#L1324

python

1 if isinstance(body, str): 2 # RFC 2616 Section 3.7.1 says that text default has a 3 # default charset of iso-8859-1. 4 body = _encode(body, 'body')

でチェックされiso-8859-1の範囲かチェックされます。
だから、日本語を渡してはいけませんensure_ascii=FalseでASCII以外の文字を残してはいけません。


というかボディ部がJSON形式のデータ(JSONとして妥当なバイト列)のリクエストを出すなら、辞書のjson_dataをjsonパラメータに渡して、

python

1response = requests.post(url, json=json_data, headers=headers)

でよくないですか。

投稿2022/09/05 03:01

編集2022/09/05 03:03
quickquip

総合スコア11038

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

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

0

Use body.encode('utf-8') if you want to send it encoded in UTF-8.

とエラーに記載あるように、以下のようにUTF-8に変換してやればよいかと思います。

Python

1data = json.dumps(json_data, indent=4, ensure_ascii=False) 2data = data.encode('utf-8') 3response = requests.post(url, data=data, headers=headers)

投稿2022/09/05 01:44

can110

総合スコア38266

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

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

XYZ

2022/09/05 01:53 編集

やってみたのですが「status 400:Invalid attribute "ItemNumber" in the payload.」が発生してしまいます。 ensure_ascii=Falseにしているからエスケープというかエンコードがされていないはずなのにある項目で payloadエラーになってしまいます
can110

2022/09/05 01:55

送信しているデータおよびサーバ側の処理の内容が分からないのでなんともですが data = json.dumps(~) した結果をprintしてみて意図踊りのjson文字列になっているか確認してはどうでしょうか?
XYZ

2022/09/05 02:05 編集

data出力してみると日本語部分がエスケープというかエンコードがされてしまっており、そのせいで"ItemNumberの紐づけが正しくない状態になっているようです。 ensure_ascii=False が期待通りの効果を発揮していないです。 dataの内容 b'{\n "OrganizationId": 32530,\n "OrganizationName": "\xe3\x83\xac\xe3\x82\xb8\xe3\~",\n "ItemNumber": "UC9999",\n "LocatorId": 1685,\n "InventoryItemId": 727,\n "TransferLocatorName": "\xe6\x96\xb0\xe5\~.",\n "TransactionTypeName": "Miscellaneous issue",\n "TransactionQuantity": "-1",\n "TransactionUOM": "PC",\n "TransactionUnitOfMeasure": "\xe5\x80\x8b",\n "TransactionDate": "2022-09-30T00:00:00+00:00",\n "TransactionMode": "1",\n "serials": [\n {\n "FmSerialNumber": "UC9999_I000386",\n "ToSerialNumber": "UC9999_I000386"\n }\n ],\n "SourceHeaderId": "1",\n "SourceLineId": "1",\n "SubinventoryCode": "AAAA_07",\n "SourceCode": "RR",\n "UseCurrentCostFlag": "true"\n}'
can110

2022/09/05 02:20

提示されているdataの内容はdata = data.encode8'utf-8')にてエンコードした後のバイナリデータのようです。 その前のjson文字列化した内容で確認ください。 バイナリで見る限り、日本語文字列はちゃんとエスケープされていない(意図通り?)のようです。
XYZ

2022/09/05 02:52 編集

json_data はエンコードされていない状態のものが出力されました。 pythonで実行すると「status 400:Invalid attribute "ItemNumber" in the payload.」が発生してしまう理由がわからないです postmanで実行宇すると status 202:created となり、OKになります
can110

2022/09/05 02:55

とりあえず通信まではできるようになったようなので、この質問はクローズして サーバ開発元に問い合わせるべきと思います。
XYZ

2022/09/05 03:57 編集

了解しました ためになりました。 ありがとうございました。
XYZ

2022/09/05 04:33

data = data.encode('utf-8') print(type(data)) をすると data が <class 'bytes'> のbyte配列に変わってしまいます 結果、  requests.post で json=data で実行すると TypeError: Object of type bytes is not JSON serializable (参考 https://www.12-technology.com/2022/05/python-typeerror-object-of-type-bytes.html ) になります。 data = data.encode('utf-8').decode('utf-8') print(type(data)) だと <class 'str'>のstringなのでrequests.post で json=data がTypeErrorがなくpostできました。
can110

2022/09/05 04:42

> をすると data が <class 'bytes'> のbyte配列に変わってしまいます 文字列をバイトデータに変換しようとしているので意図通りの結果です。 > 結果、  requests.post で json=data で実行すると 回答では「json=data」ではなく「data=data」であり、問題なくpostできます。 requests.postの各引数の意味、dataやjsonなどにはどのような型の値を渡すべきかについては 公式マニュアルなどを確認ください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問