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

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

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

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

Q&A

解決済

3回答

3006閲覧

KeyError の再試行について

退会済みユーザー

退会済みユーザー

総合スコア0

Python 3.x

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

0グッド

0クリップ

投稿2018/03/22 11:18

編集2018/03/23 05:01

前提・実現したいこと

https://api.cryptowat.chから価格データを取得したいが、サイトが不安定のためかたまに空をかえすため
KeyErrorを起こしてしまいます。
そのためエラーが起きても再度 r = requests.getに戻り、エラーが起きなくなるまで繰り返したい。

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

Key Error: '60'

該当のソースコード

from datetime import datetime, timezone, timedelta
import time
import requests
import json

TIME = 0
CLOSE = 4

while True:

r = requests.get('https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc?periods=60') json = r.json()['result']['60'] close = json[-1][CLOSE] print(str(datetime.fromtimestamp(round(time.time()) + 60 * 60 * 9)) + ' CLOSE: ' + str(close)) #直近の終値の表示 time.sleep(5)

試したこと

独学で勉強しはじめたての初心者のため retry というライブラリがあることまでは発見したのですが、使い方がわからない状況です。。

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

python3.6

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

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

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

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

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

guest

回答3

0

そもそも、攻める方向を間違ってるような気がします。
なんか空を返すからリトライしたい、じゃなく、なぜ空を返すのかの原因を突き止めるのが先じゃないのでしょうか。
それがわからないと、リトライするのが有効なのかそうじゃないのか、リトライするにしてもどういうふうにリトライしなければならないのかもわからないって話で、この質問のスレッド自体、意味がない気がしますが。

投稿2018/03/23 02:55

y_waiwai

総合スコア87747

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

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

umyu

2018/03/23 02:56 編集

本筋としてはそうですね!賛成票を入れました。
guest

0

ベストアンサー

<< 回答が長くなったので、最新のソースコード以外は削除しました。 >>

Can I set max_retries for requests.request?

上記サイトを参考にRetry処理を実装してみてはー。

公開APIには負荷を掛けないように一度取得したものは、2度取得しないような形にしてくださいな。
例えばファイルに書き出して、読み込む形にするなどの対応をしてくださいな。
そうしないとAPIに負荷がかかりすぎて、APIからのアクセス拒否が行われたりやAPIが閉鎖され2度と使えなくなる事もあります。

■参考情報
python requestsでリトライ処理をする


2018/03/23追記

cryptowatch.jp APIのドキュメントを見ると、レートリミットになるとステータスコード:429を返すみたいですね。
APIから帰ってくるステータスコード判定してませんようね・・多分。。

■参考情報
cryptowat APIの使い方(備忘録)


質問文のコードに合わせる形で修正

Python

1import time 2from datetime import datetime 3import json 4import requests 5from urllib3.util.retry import Retry 6from requests.adapters import HTTPAdapter 7 8 9def get_content(url: str='https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc'): 10 s = requests.Session() 11 retries = Retry(total=5, 12 backoff_factor=0.1, 13 status_forcelist=[500, 502, 503, 504]) 14 s.mount('https://', HTTPAdapter(max_retries=retries)) 15 payload = {'periods': '60'} 16 r = s.get(url, params=payload) 17 # ↓テスト用コード 18 # r.status_code = 429 19 if r.status_code == 429: 20 # APIのドキュメントにはr.json()できるかどうかの保証の記述はなかったので注意です。 21 # r.json()出来ない場合は値:Noneを返してくださいな。 22 return r.json(), r.status_code 23 return r.json(), r.status_code 24 25 26def data_write(obj): 27 file_name = f'{datetime.now().strftime("%Y%m%d_%H%M%S_%f")}.json' 28 #print(f'file write:{file_name}') 29 with open(file_name, 'w', encoding='utf-8-sig') as f: 30 json.dump(obj, f) 31 32 33def main() -> None: 34 CLOSE = 4 35 while True: 36 content, status_code = get_content() 37 # rate_limitなら 38 if status_code == 429: 39 # sleepタイムを55秒に 40 time.sleep(55) 41 continue 42 43 json = content['result']['60'] 44 close = json[-1][CLOSE] 45 print(str(datetime.fromtimestamp(round(time.time()) + 60 * 60 * 9)) + ' CLOSE: ' + str(close)) # 直近の終値の表示 46 # ファイルに保存したい時。 47 #data_write(json) 48 49 time.sleep(5) 50 51 52if __name__ == '__main__': 53 main() 54

投稿2018/03/22 13:42

編集2018/03/23 06:21
umyu

総合スコア5846

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

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

退会済みユーザー

退会済みユーザー

2018/03/23 02:50

ご回答ありがとうございます。サンプルコードも記載いただきありがとうございます。 独学で教本をみてつまずきながら初めているためコードをいただけると勉強になり非常に助かります。 そこで一点ご質問なのですが、質問時点で記載していればよかったのですが、コードですが以下のようにつづいてjsonとしたものを次の式で代入しています。 そのためいただいたサンプルコードを次の式に当てはめるとすればどのようにするのがいいのでしょうか? 初期すぎる質問で申し訳ありません。 r = requests.get('https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc?periods=60') json = r.json()['result']['60'] close = json[-1][CLOSE]
umyu

2018/03/23 02:55

>質問文のコードにその部分を追加してくださいな。 そのコード他になにか書いてませんか?こちらの環境で実行するとCLOSEの部分でエラーになるのですが。
退会済みユーザー

退会済みユーザー

2018/03/23 05:01

すみません。質問編集いたしました。
umyu

2018/03/23 05:09

>HIROGRANDさんへ 失礼かもしれませんが2点確認します。 1,このプログラムは自分で全部書いたプログラムですかー? close = json[-1][CLOSE]のところで必ず実行エラーが発生するはずなのですが。 2,requests.get('https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc?periods=60') このURLは本当にこのアドレスで正しいですか? この2点、よろしければ解答のほどお願いします。
退会済みユーザー

退会済みユーザー

2018/03/23 05:41

いえいえ。初心者にお付き合いいただきまして本当にありがとうございます。 1、はい。自分でいろいろなネットや本などから引っ張ってきて作成いたしました。 なので完璧に自分ではありませんが、切り貼りをしながらトライアンドエラーしながら作成している感じです。 もしかしたらですが今見たらコピーしたときにインデントが削除されているみたいのでr = requests.getはインデントされてます。 一応こちらでは記載のコードのままで無事機能しています。 2、はい。http://www.bitbityen.com/entry/2017/11/22/080000   このページを参照しました。   https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlcと?periods=60を足して1分足のみを抽出しています。 コード自体は普通に無事動くのです。ただ一時間とか起動させとくと cryptowatch側のエラー時に価格を取得のタイミングかぶるとシステム自体がとまってしまうのです。。 そのたびに手動で再起動させれば普通に動くのですが、それの繰り返しでして、、 なのでその手動でやらなくてはいけない手間を自動にしたい感じです。。 独学だとなかなか聞ける人がいなくて、ご迷惑をおかけしてすみません。。
退会済みユーザー

退会済みユーザー

2018/03/24 03:03

ご回答いただきありがとうございました!無事実装できました。
guest

0

投稿2018/03/22 11:28

ikapy

総合スコア1167

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

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

退会済みユーザー

退会済みユーザー

2018/03/22 11:36

ありがとうございます。いただいたページですがすでに確認済みでしてtry-exceptもためしてみたのですが、シンプルにretryで実行したいのですが、独学のためいまいちコードの書き方がわからず困っているところです。 pipでインストールをして from retry import retryを冒頭に記載してまではいいのですが、そのあと、エラー部分にどのように @retry()を組み込んでいいのかがわかりません。。 @retry() r = requests.get('https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc?periods=60') json = r.json()['result']['60'] だとエラーがおきてしまうので。。
ikapy

2018/03/22 11:55

それでは、http://techtipshoge.blogspot.jp/2016/04/pythonretry.html はどうでしょうか。 上記URLの中の関数crawl_url()をあなたの行いたいことに書きなおせばよいと思いますが。 なお、上記URLの中の@retry(tries=4, delay=5, backoff=2)のtriesはリトライ回数、delayはディレイ間隔(秒)、backoffはディレイ間隔の倍数ですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問