🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python 3.x

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

WebSocket

WebSocketとは双方向・全二重コミュニケーションのためのAPIでありプロトコルのことを指します。WebSocketはHTML5に密接に結びついており、多くのウェブブラウザの最新版に導入されています。

Python

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

Q&A

解決済

1回答

912閲覧

WebSocketで二つの値を利用する方法2

step595

総合スコア2

Python 3.x

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

WebSocket

WebSocketとは双方向・全二重コミュニケーションのためのAPIでありプロトコルのことを指します。WebSocketはHTML5に密接に結びついており、多くのウェブブラウザの最新版に導入されています。

Python

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

0グッド

0クリップ

投稿2021/03/27 02:48

下記のようなコードで2個の値を取得することまではできたのですが、このclosea, closebという値を利用しようとしたときに困っています。

例えば下記のようにmainでコードを利用して代入しようとした場合、両方から値が来ていればいいですが、来ていない場合に、値がなくなってしまい、プログラムが動かないということが起きます。

これを値が来ていないときは片方は前回の値を(初回だけは両方揃うまでは片方は0でもいいのですが)したいと考えているのですが、どのようにしたらいいかで詰まってしまいました。。。
(試しにb.pyのようにmainの中にclosea, closebを0と定義してみたりすればコードは動きますが、そうなると次の時に片方が0になってしまって前回の値でなくなってしまうのでどうしたものかと。。。)

対応法があればお伺いできれば幸いです。
(def mainの中はとりあえず適当なコードです。実際にはもっと長いコードが使われるものとご認識いただければと思います)

python3

1(a.py) 2import websocket 3import json 4 5 6def main(closea, closeb): 7 closea = closea + 10 8 closeb = closeb + 10 9 10 print (closea, closeb) 11 12 13def on_message(ws, message): 14 try: 15 rs = json.loads(message) 16 channel = rs["params"]["channel"] 17 if channel == "lightning_ticker_FX_BTC_JPY": 18 closefx = round(float('{ltp}'.format(**(rs["params"]["message"])))) 19 elif channel == "lightning_ticker_BTC_JPY": 20 closespot = round(float('{ltp}'.format(**(rs["params"]["message"])))) 21 else: 22 print("Got other channel data:", channel, rs) 23 except Exception as e: 24 print(e) 25 26 27 main(closefx, closespot) 28 29def on_error(ws, error): 30 print(error) 31 32 33def on_close(ws): 34 print("### closed ###") 35 36 37def on_open(ws): 38 print("### open ###") 39 ws.send(json.dumps([{'method': 'subscribe', 'params': {'channel': 'lightning_ticker_FX_BTC_JPY'}},{'method': 'subscribe', 'params': {'channel': 'lightning_ticker_BTC_JPY'}}])) 40 41 42if __name__ == "__main__": 43 ws = websocket.WebSocketApp("wss://ws.lightstream.bitflyer.com/json-rpc", 44 on_message=on_message, 45 on_error=on_error, 46 on_close=on_close) 47 ws.on_open = on_open 48 ws.run_forever()

python3

1(b.py) 2 3import websocket 4import json 5 6 7def main(closea, closeb): 8  closea = 0 9 closeb = 0 10 11 closea = closea + 10 12 closeb = closeb + 10 13 14 print (closea, closeb) 15 16以下省略 17

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

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

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

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

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

guest

回答1

0

ベストアンサー

websocketにこだわるならば、例として下記のように別スレッドでデータを取得し
使いたい値をTickerオブジェクト経由でアクセスするようなプログラムを考えることはできます。

a.py(データを取得する方)

python

1# a.py 2 3import websocket 4import json 5import threading 6 7 8class Ticker: 9 10 def __init__(self): 11 self.values = dict(closea=0, closeb=0) 12 13 def start(self): 14 def on_message(ws, message): 15 try: 16 # valuesにそれぞれの値を格納する。 17 rs = json.loads(message) 18 channel = rs["params"]["channel"] 19 if channel == "lightning_ticker_FX_BTC_JPY": 20 self.values["closea"] = round(float('{ltp}'.format(**(rs["params"]["message"])))) 21 elif channel == "lightning_ticker_BTC_JPY": 22 self.values["closeb"] = round(float('{ltp}'.format(**(rs["params"]["message"])))) 23 else: 24 print("Got other channel data:", channel, rs) 25 except Exception as e: 26 print(e) 27 28 29 def on_error(ws, error): 30 print(error) 31 32 def on_close(ws): 33 print("### closed ###") 34 35 def on_open(ws): 36 print("### open ###") 37 ws.send(json.dumps([ 38 {'method': 'subscribe', 'params': {'channel': 'lightning_ticker_FX_BTC_JPY'}}, 39 {'method': 'subscribe', 'params': {'channel': 'lightning_ticker_BTC_JPY'}} 40 ])) 41 42 def run(ws): 43 ws.run_forever() 44 45 self.ws = websocket.WebSocketApp("wss://ws.lightstream.bitflyer.com/json-rpc", 46 on_message=on_message, 47 on_error=on_error, 48 on_open =on_open, 49 on_close=on_close) 50 self.th = threading.Thread(target=run,args=(self.ws,)) 51 self.th.start() 52 53 def shutdown(self): 54 self.ws.close()

 

b.py (値を使う方のプログラムの例)

python

1# b.py (値を使う方のプログラムの例) 2 3 4from a import Ticker # a.pyからTickerクラスをインポート。 5import time 6 7# 開始処理 8ticker = Ticker() 9ticker.start() 10 11# ~~~任意のコード~~~ 12 13# プログラム中で、任意のタイミングでtickerのvaluesを呼び出せばよい。 14while True: 15 try: 16 print("closea", ticker.values["closea"]) 17 print("closeb", ticker.values["closeb"]) 18 time.sleep(1) 19 except KeyboardInterrupt: 20 break 21 22# ~~~任意のコード~~~ 23 24 25# 終了前に必ずshutdownを呼び出す。 26ticker.shutdown() 27 28print("end")

スレッドを使っているため、a.py内でのエラー処理に気を付けないとハマります。
プログラムの目的にもよりますが、API制限の範囲内でアクセス頻度でよいなら、websocketではなく下記のようにHTTP APIを使った方が圧倒的に楽かと思います。

# そもそもwebsocketを使わない例。 import requests import json url = "https://api.bitflyer.com/v1/ticker" def get_fx_btc_jpy(): res = requests.get(url, params={"product_code": "FX_BTC_JPY"}) return res.json()["ltp"] def get_btc_jpy(): res = requests.get(url, params={"product_code": "BTC_JPY"}) return res.json()["ltp"] # 欲しいタイミングでそのときの値を取得できる。 print(get_fx_btc_jpy()) print(get_btc_jpy())

投稿2021/03/27 06:42

編集2021/03/27 12:06
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

step595

2021/03/27 09:33

ご回答ありがとうございます。 httpであればできたのですが、察しの通り制限の問題でwebsocketにこだわりがありました。 並列処理についてもっと勉強しないとですね。。。 あとこのコードを起動させてみたのですが、a.pyもb.pyも両方起動させるということであってますでしょうか? それだとa.pyがうごかず、b.pyだけだとずっと0を取得し続ける状況です。 初歩的なミスであればすみません。
退会済みユーザー

退会済みユーザー

2021/03/27 12:15 編集

動かすのは(pythonコマンドで実行するのは)b.pyだけとなります。 (b.pyの中でaをインポートしているため、aまで実行する必要はないです) (aとbを同じディレクトリに入れてそのディレクトリからb.pyを実行するという想定です) b.pyのコードを一部修正しました。(whileで1秒ごとに表示) 最初の数秒は、websocketからデータが来ていないので、0が表示される場合があります。 このコードをそのまま実行した場合でも、うごかないでしょうか? もし質問者さんがカスタマイズされた特定のコードの場合だと動かなくなるorうまく表示されない、というのであれば、 当該コード(少なくともb.pyはそのまま全部、あと、もしa.pyも回答欄のコードから一部でもカスタマイズされている場合はa.pyも)を質問欄に追記していただくことは可能でしょうか? こちらで調べてみます。
step595

2021/03/27 12:31 編集

ご丁寧にありがとうございます。 特に編集せずにまるまるコピペで起動してみてるつもりなのですが、ずっと値が0.0の取得なんですよね。。。(編集後のものでもためしました) ちなみにどこまでコードが届いているかを調べるために別途on_message内に適当にprint("1")とか記入してみてるのですがprintの文章が起動されずそこまで動いている感じがしないのです。。どっかで詰まっているのでしょうか。。。
退会済みユーザー

退会済みユーザー

2021/03/27 12:40 編集

私の手元ではきちんと表示されるので不思議ですね・・・ 考えられるのは (1)websocketで取得できるはずのデータ(Realtime API)が、IPアドレスで制限されている可能性 (2)OS、python、ライブラリ固有の環境 によってうまく動いていない可能性があります。 (1)については、前の質問の回答(https://teratail.com/questions/328811#reply-454944)のプログラムだったらうまく表示されるのであれば、あてはまりません。 (2)については、 pip install --upgrade websocket-client を実行してwebsocket-clientを最新版にしてみるか、 とりあえずOS環境、pythonバージョン、および pip show websocket-client をコマンドプロンプト(ターミナル)で実行したときに表示されるwebsocket-clientのバージョンを教えていただけないでしょうか。 自分の環境は、Python3.8.6、windows10、websocket-client 0.58.0で a.pyとb.pyを同じディレクトリにいれ、そのディレクトリからコマンドプロンプトで python b.py を実行しています。
退会済みユーザー

退会済みユーザー

2021/03/27 12:43 編集

あとは、2つのファイルに分けているのが不具合の原因かもしれません。 1つのファイルにして実行してみるとどうでしょうか。 具体的には、a.pyのコードの後ろに、b.pyのコードをくっつけて(ただし、from a import Tickerの行は削除)、a.pyを実行してみる、ということです。
step595

2021/03/27 14:12

できました!ありがとうございます。 ちなみにちょっとお伺いできたらありがたいのですが、b.py 修正後 while True:を付けた影響でticker.shutdown()まで届いていなくてもうごいているのですが、ticker.shutdown()はいるのでしょうか?
退会済みユーザー

退会済みユーザー

2021/03/27 14:19

ticker.shutdown() はあくまでプログラム終了時にwebsocketからのデータ取得を終了させるためのものです。 なのでwhileループが動いている間は届いていなくても構いません(届いていないのが正常です) 回答の例示コードでは、プログラム停止のためにCtrl+Cを押すとKeyboardInterrupt例外が発生し、whileループを抜けるようになっています。 whileループを抜けた後、ticker.shutdown()が実行されて、websocketからのデータ取得も終了されます。
step595

2021/03/27 14:35

ありがとうございます。解決してたすかりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問