注意:この記事で取り扱っているスクレイピング先のサイトの仕様が変わってました。記事で紹介している手法は汎用的なものなので、皆さん他のサイトで工夫して使っていただけると幸いです
今回はseleniumを使ったwebクローリング&スクレイピングの記事になります。
事前準備
まずは、selenium(pythonライブラリ)のインストールです。
pip install selenium
or
conda install -c anaconda selenium
続いて、seleniumからブラウザを操作する用のドライバをダウンロードします。
seleniumは、pythonから他のブラウザ(google chromeなど)を起動して、
そのインターフェイスを利用していろいろやるのですが、
その際に、seleniumが他のブラウザを操作できるようにするのがドライバです。
以下のseleniumの公式サイトからご利用のブラウザに対応するドライバを入手してみてください。
https://www.selenium.dev/downloads/
以上、 ①seleniumのインストール と ②ドライバのダウンロード の2つが終われば事前準備は完了です。
クローリング&スクレイピングする先は?
今回は以下の仮想通貨デリバティブの取引所(webアプリ)を題材に
データを取得してみたいと思います。(ガッツリreactで書かれているぽい)
https://app.lien.finance/trade
この取引所アプリでは、
販売されているデリバティブの価格が適正価格からある程度乖離したら、
ページの右上の方にアラートメッセージが表示される仕組みになっています。
実際にトレーディングで裁定取引をやろうとすると、今回のやり方だとスピード的にアレな気もしますが、
とりあえずwebのデータ取集の練習として 、
右上のarbitrage alertを取得するコードを書いてみたいと思います。
コード
ざっくりと以下のようなコードを書いてみました。
from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.webdriver.chrome.options import Options import datetime as dt import time URL = "https://app.lien.finance/trade" DRIVER_PATH = "./chromedriver" for _ in range(10): # とりあえず10回やる. 定期実行ならcronでやった方が良さげ options = Options() options.add_argument('--headless') driver = webdriver.Chrome(DRIVER_PATH, options=options) driver.get(URL) is_arbitrage = False arbitrage = 0 arbitrage_atr = "" try: WebDriverWait(driver, 30).until( EC.presence_of_element_located( (By.XPATH, "//div/div/div/span/p/span") ) ) time.sleep(5) now = dt.datetime.now() elements = driver.find_elements_by_xpath( "//*[contains(@class, 'font-bold')]" ) for element in elements: if element.text=='Arbitrage Alert!!': is_arbitrage = True _comments = driver.find_elements_by_xpath( "//div/div/div/span/p" ) arbitrage_atr = _comments[0].text _arbitrage = driver.find_elements_by_xpath( "//div/div/div/span/p/span" ) arbitrage = float(_arbitrage[0].text) break except: now = dt.datetime.now() if is_arbitrage and abs(arbitrage) > 10: # gas代高いですからね... print('{}: {}'.format(now, arbitrage_atr)) driver.close() driver.quit()
適宜確認していきます。
まず初めにドライバの読み込みです。
ディレクトリ構造は、今回動かす.pyファイルとドライバが同じディレクトリにある想定で
. ├── 今回のファイル.py └── chromedriver
みたいな感じを想定しています。
options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome(DRIVER_PATH, options=options)
上の2行でドライバのオプションを指定しているのですが、
"--headless"の内容はseleniumから動かすブラウザを非表示にするというものです。
このオプションはなくても当然問題無いので、
動作を目で確認したい人はオプションを外してもらっても大丈夫です。
続いてwait処理です。
# arbitrage alert!! or timeoutするまで待機.timeoutしたらexceptに流れる WebDriverWait(driver, 30).until( EC.presence_of_element_located((By.XPATH, "//div/div/div/span/p/span")) ) # 描画にラグがあることがあるので少し待つ time.sleep(5)
サイトをブラウザで見てもらえばわかるのですが、実はこのサイト結構重いです。
ですので、driver.getした後にすぐに処理を開始しようとするとダメです。
そこで、右上のarbitrage alertの最下層のxpathが取得できるまで一旦停止する処理がWebDriverWaitになります。
また、arbitrage-alertのあとも少し待つことで
ちゃんとブラウザを目視したときと同じ情報が取れます。
このあたりでめんどくさくなってきたのですが、
_comments = driver.find_elements_by_xpath("//div/div/div/span/p") arbitrage_atr = _comments[0].text _arbitrage = driver.find_elements_by_xpath("//div/div/div/span/p/span") arbitrage = float(_arbitrage[0].text)
ここで、arbitrage alertの内容を取得しています。
取得の仕方は絶対にもっと良いやり方があるのですが、めんどくさ(略
で、最後にログを吐き出してオワオワリです。
if is_arbitrage and abs(arbitrage) > 10: # 10%以上のarbitrage alertのみ反応 print('{}: {}'.format(now, arbitrage_atr)) # notifyを追加したければここに
通知
notifyとしては、例えばmacのローカルだったら
import subprocess import datetime as dt import platform def mac_notify(txt): now = dt.datetime.now() pf = platform.system() if pf == 'Darwin': # 使ってるOSがmacなら script = """osascript -e 'display notification "{}: {}"'""".format(now, txt) subprocess.run(script, shell=True)
こんな感じで通知を飛ばしたりできます。
他にも以下のような関数を用意してLINEに通知を送ったりもできます。
import requests def line_notify(message): line_notify_token = '' # 発行したトークン line_notify_api = 'https://notify-api.line.me/api/notify' payload = {'message': message} headers = {'Authorization': 'Bearer ' + line_notify_token} requests.post(line_notify_api, data=payload, headers=headers)
ではまた!
今回の関連書籍
この本は昔読みましたよかった気がします。ただ、最近の本はあんまり見てないので、もっといい本が出ている可能性はありそうです。