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

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

新規登録して質問してみよう
ただいま回答率
85.50%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Python

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

Q&A

解決済

2回答

1812閲覧

Python3でGETリクエストでJSONデータを送る

otera05

総合スコア11

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Python

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

0グッド

1クリップ

投稿2018/08/08 09:58

前提・実現したいこと

Python3のrequestsモジュールを使って外部APIからデータを取得したいのですが、
ベンダーから提供されているAPI仕様書に則ってリクエストを送ってもステータスコード400が返ってきて上手くいきません。

ベンダーからはPHPで以下のサンプルコードが送られてきており、自分のローカルにPHPの実行環境を作って実行したところ、
上手く動作しました。
こちらが作るアプリケーションの言語はPython3で決定しているのでこれをPython3で書き直したいのです。。

なお、ベンダーから提供されているAPI仕様書には以下の指定があります。

HTTPメソッド:GET

リクエストヘッダに以下のパラメータを付与する

要素名説明
Content-Typeapplication/json; charset=UTF-8
X-Auth「ID:パスワード」をBASE64エンコードしたもの

リクエストボディに以下の検索条件を付与しJSON形式で送る

キー説明
from開始時刻
to終了時刻

ベンダーから提供されたPHPのサンプルコード

PHP

1<?php 2$loginName = 'username'; 3$password = 'password'; 4 5$header = array( 6 'Content-type: application/json; charset=UTF-8', 7 'X-Auth:' . base64_encode($loginName . ':' . $password), 8 ); 9 10$context = stream_context_create( 11 array( 12 'http' => array( 13 'method'=> 'GET', 14 'header'=> implode("\r\n", $header), 15 'content' => json_encode( 16 array( 17 'from' => '2018-07-01 00:00:00', 18 'to' => '2018-07-27 23:59:00', 19 'maximumresponse' => '1000' 20 ) 21 ,JSON_UNESCAPED_UNICODE) 22 ) 23 ) 24); 25 26print file_get_contents('https://xxxxxxxxx.jp/api/v1/hoge.json', false, $context); 27?>

サンプルコードを実行すると以下のようなJSONのレスポンスが得られます。

JSON

1{ 2 "result":"000000", 3 "accepttime":"2018-08-08T17:26:41+09:00", 4 "count":1, 5 : 6 以下略 7 : 8}

PHPのコードの $context の中身は以下の通りです。

PHP

1php > var_dump(stream_context_get_params($context)); 2array(1) { 3 ["options"]=> 4 array(1) { 5 ["http"]=> 6 array(3) { 7 ["method"]=> 8 string(3) "GET" 9 ["header"]=> 10 string(116) "Content-type: application/json; charset=UTF-8 11X-Auth:******************************" 12 ["content"]=> 13 string(82) "{"from":"2018-07-01 00:00:00","to":"2018-07-27 23:59:00","maximumresponse":"1000"}" 14 } 15 } 16}

自分が書いたPython3のコード(上手くいかない)

Python3

1import base64 2import requests 3import json 4 5 6ID = 'username' 7PASS = 'password' 8URL = 'https://xxxxxxxxx.jp/api/v1/hoge.json' 9auth_str = ID + ':' + PASS 10 11authkey = base64.b64encode(auth_str.encode('utf-8')).decode() 12 13headers = { 14 'Content-Type': 'application/json; charset=UTF-8', 15 'X-Auth': authkey 16} 17 18payload = { 19 'from': '2018-07-01 00:00:00', 20 'to': '2018-07-27 23:59:00', 21 'maximumresponse': 1000 22} 23 24r = requests.get(URL, headers=headers, json=payload)

このコードを実行したら以下のようにHTTPのステータスコードが400になります。

>>> r = requests.get(URL, headers=headers, json=payload) >>> r.status_code 400

試したこと

ちなみにリクエストを送る際の引数を変えてみたりしましたがダメでした…。

Python3

1>>> r = requests.get(URL, headers=headers, params=json.dumps(payload)) 2>>> r.status_code 3400

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

実行環境は以下の通りです。

  • Python3.6
  • requests2.19.1

当然、パラメータはサンプルコードに記載されたものと全く同じにしているのでパラメータに問題はなく、Pythonのコードの問題だと思っています。
お知恵を貸していただければ幸いです。

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

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

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

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

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

guest

回答2

0

ベストアンサー

提示いただいたサンプルをPHP版、Python版とも動かしてみました。ただし、HTTPSではなくHTTPにして、ローカルの4444ポートでやりました。リクエストを受け取るのは、以下のようにnetcatコマンドを用いました。

sh

1$ netcat -l 4444

PHP版の実行結果は以下の通り。

HTTP

1GET /api/v1/hoge.json HTTP/1.0 2Host: localhost:4444 3Connection: close 4Content-Length: 82 5Content-type: application/json; charset=UTF-8 6X-Auth:dXNlcm5hbWU6cGFzc3dvcmQ= 7 8{"from":"2018-07-01 00:00:00","to":"2018-07-27 23:59:00","maximumresponse":"1000"}

Python版の実行結果は以下の通り。

HTTP

1GET /api/v1/hoge.json HTTP/1.1 2Host: localhost:4444 3User-Agent: python-requests/2.18.4 4Accept-Encoding: gzip, deflate 5Accept: */* 6Connection: keep-alive 7Content-Type: application/json; charset=UTF-8 8X-Auth: dXNlcm5hbWU6cGFzc3dvcmQ= 9Content-Length: 85 10 11{"from": "2018-07-01 00:00:00", "to": "2018-07-27 23:59:00", "maximumresponse": 1000}

ご覧のように、ほとんど違いはないですねぇ。しいて言えば、maximumresponseがPHPは文字列であるのに対して、Pythonは数値です。ここは型を揃えて試してみたいところです。
あとは、X-Auth:の後の空白の有無とか…

ところで、本当にGETが正しい仕様なのでしょうか? リクエストボディがあるので、POSTが正しいと思うのですが、この点は間違いないですか?

投稿2018/08/08 11:46

ockeghem

総合スコア11701

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

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

otera05

2018/08/09 00:12

検証いただきありがとうございます。 maximumresponseについては、API仕様書では型の定義が「数値」となっていたので数値にしていましたが、確かにベンダーのPHPでは文字列ですね…。 また、maximumresponseは指定してもしなくてもよいという仕様になっているので一旦指定なしで確認してみましたが同様にステータスコードは400のままでした。 私もリクエストボディがあるのでPOSTなのでは…?と思っていたのですが、仕様書にはGETと明記されているのとPHPのコードにはやはりGETが指定されていて、且つそれでちゃんと動作するのでうーん…といった感じで悩んでいますね…。 半ばやけくそな感じで、パラメータは同一(maximumresponseは削除しました)でPOSTも含めてリクエストを送ってみましたが結果は以下の通りです。。 >>> r = requests.get(URL, headers=headers, params=json.dumps(payload)) >>> r <Response [400]> >>> r = requests.get(URL, headers=headers, json=payload) >>> r <Response [400]> >>> r = requests.post(URL, headers=headers, json=payload) >>> r <Response [400]> >>> r = requests.post(URL, headers=headers, data=payload) >>> r <Response [400]> >>> r = requests.post(URL, headers=headers, data=json.dumps(payload)) >>> r <Response [400]> 他にどんなところが怪しそうでしょうか。。
ockeghem

2018/08/09 00:43

既に怪しそうなところはコメントした通りで私にはわかりません。ベンダーに問い合わせるのが筋かと思います。その際に、前述したリクエストをつけて、「どこがおかしいですか?」と聞くべきかと思います。その際に、GET/POSTの点も確認した方がよいと思います。
otera05

2018/08/09 01:31

ありがとうございます。 仰る通りです。 Pythonのサンプルコードをベンダーからいただければそれが一番よかったのですが、 ベンダーには「Pythonのサンプルコードはない」と突っぱねられており、記載したPythonのソースコードを送っても「サポートしかねる」といった回答だったのでこちらでお聞きした次第です。 事前情報が不足しており失礼しました。 とは言え、GET/POSTの件はHTTPの一般的な話なので改めてベンダーに問い合わせてみます。
guest

0

本件、無事解決しました。
結論から申し上げますと、私が最初に書いたコードで問題ありませんでした…。

python3

1>>> r = requests.get(URL, headers=headers, json=payload) 2>>> r.status_code 3200 4>>> r.json() 5{'result': '000000', 'processkey': 'Processkeytest', 'accepttime': '2018-08-09T16:05:00+09:00', 'count': 1,…以下略…}

といった形でレスポンスが返ってきました。
恐らくベンダー側で何らかの調整を行ったのではないかと推測しています。(問合せ中です。)

ockeghem様、色々とありがとうございました。
ローカルでのHTTPリクエスト内容の確認の手法について知らなかったので大変勉強になりました。
また、お騒がせ致しました。

投稿2018/08/09 07:18

otera05

総合スコア11

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問