今回はSeleniumで仮想通貨取引所Zaifの取引価格を抽出するPythonプログラムを作ってみました。

シェルに表示するだけのシンプルなものではありますが、ここからメールを送信して通知したり、CSVに抽出したデータを格納したりすることも可能です。

プログラムの概要

フローチャート図

フローチャート図

作りはとても簡単です。ヘッドレスモードで起動したブラウザに表示される価格を、一定時間ごとに抽出してシェルに表示させます。

ただ、それだけです。

ソースコード

#! /usr/bin/python3
import bs4,time,sys,random,re,datetime
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.webdriver import Firefox, FirefoxOptions

#ヘッドレスモードで起動させる。
options = FirefoxOptions()
options.add_argument('-headless')

browser = webdriver.Firefox(options=options)
browser.get("https://zaif.jp")

TIMEOUT         = 10
WAIT_TIME       = 0.5 
RANDOM_TIME     = 30
STABLE_TIME     = 60

past_string = []

class Color:
    RED      =   "\033[31m"
    GREEN    =   "\033[32m"
    END      =   "\033[0m"
    REVERCE  =   "\033[07m"

#前日比の下落と上昇の処理
def down_up(parsed_content):

    percentage = parsed_content.getText()

    if   "arrow-up" in str(parsed_content):
        
        print(Color.GREEN,end="")
        percentage = "+" + percentage
        print(percentage.rjust(10),end="")
        print(Color.END,end="")
    elif "arrow-down" in str(parsed_content):
        print(Color.RED,end="")
        percentage = "-" + percentage
        print(percentage.rjust(10),end="")
        print(Color.END,end="")
    else:
        print(percentage.rjust(10),end="")

def check_price(past_string):

    output_list     = []

    try:
        html_wait = WebDriverWait(browser,3)
        #print("HTML取得中")
        html_elem = html_wait.until(expected_conditions.visibility_of_element_located((By.TAG_NAME, "html")))
        #print("HTML取得完了")
    except:
        print("HTMLの取得に失敗しました")

    else:

        date    = datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")
        print("\n" + date)

        parsed_page     = bs4.BeautifulSoup(browser.page_source, "lxml")

        btc_price   = parsed_page.select(".currency-list-area > div > div > div > ul[data-coin-name='btc_jpy'] > li")
        eth_price   = parsed_page.select(".currency-list-area > div > div > div > ul[data-coin-name='eth_jpy'] > li")
        xem_price   = parsed_page.select(".currency-list-area > div > div > div > ul[data-coin-name='xem_jpy'] > li")
        bch_price   = parsed_page.select(".currency-list-area > div > div > div > ul[data-coin-name='bch_jpy'] > li")
        mon_price   = parsed_page.select(".currency-list-area > div > div > div > ul[data-coin-name='mona_jpy'] > li")
        zai_price   = parsed_page.select(".currency-list-area > div > div > div > ul[data-coin-name='zaif_jpy'] > li")

        for i in range(1,4):

            string      = []

            #要素の文字列を抜き取る
            string.append(btc_price[i].getText())
            string.append(eth_price[i].getText())
            string.append(xem_price[i].getText())
            string.append(bch_price[i].getText())
            string.append(mon_price[i].getText())
            string.append(zai_price[i].getText())

            if i == 1:
                print("銘柄 ",end="")
                for i in range(len(string)):
                    print(string[i].rjust(10),end="")
            if i == 2:
                print("価格 ",end="")

                #過去の価格の記録がある場合の比較処理
                if past_string != [] and len(past_string) == len(string):
                    for i in range(len(string)):
                        
                        if   float(re.sub(",","",string[i])) < float(re.sub(",","",past_string[i])):
                            print(Color.RED + Color.REVERCE,end="")
                            print(string[i].rjust(10),end="")
                            print(Color.END,end="")
                             

                        elif float(re.sub(",","",string[i])) > float(re.sub(",","",past_string[i])):
                            print(Color.GREEN + Color.REVERCE,end="")
                            print(string[i].rjust(10),end="")
                            print(Color.END,end="")
                        else:
                            print(string[i].rjust(10),end="")
                else:
                    for i in range(len(string)):
                        print(string[i].rjust(10),end="")

                #過去の価格を記録する
                past_string = []
                for i in range(len(string)):
                    past_string.append(string[i])

            if i == 3:
                print("前日比",end="")
                #btc_priceなどの要素名から色を変更

                down_up(btc_price[3])
                down_up(eth_price[3])
                down_up(xem_price[3])
                down_up(bch_price[3])
                down_up(mon_price[3])
                down_up(zai_price[3])

            print("")

    return past_string

if __name__ == "__main__":
    try:

        while True:
            past_string = check_price(past_string)
            timer   = random.random() * RANDOM_TIME + STABLE_TIME
            time.sleep(timer)

        browser.close()

    except KeyboardInterrupt:
        print("\nprogram was ended.\n")
        sys.exit()
        browser.close()

このプログラムの解説

このプログラムは、Zaifのトップページに表示されている、価格情報を抽出します。

抽出した情報は前回の値と比較して、下がっていれば赤、上がっていれば緑でシェルに表示させています。bashのエスケープ文字に依存しているので、色表示はbashでしか機能しない点に注意しましょう

Zaif側のJavaScriptが非同期で価格情報を更新してくれるので、こちら側はブラウザの更新をしなくてもリアルタイムで価格情報を取得できます。

プログラム冒頭の待ち時間を調節するだけで、価格を取得する間隔を自由に設定可能です。

工夫したところ

価格の色つけ

価格の値動きが視覚的にわかるように、色つけして表示してみました。

過去の価格をリストに保管しておき、その値を比較して色を判定しています。過去より大きければ緑、小さければ赤、同じならそのままで表示させています。

動作環境

  • Python3を搭載したbashを装備しているOS
  • Selenium、BeautifulSoup等がインストール済み

実際に動かしてみる

使い方は簡単です。bashを起動して実行すれば良いだけです。

デフォルトでヘッドレスモードは有効になっているので、ブラウザは表示されません。bashに以下のように表示されます。

仮想通貨の価格が表示されている

終了するときは、Ctrl+Cを押せば終了します。

メリットとデメリット

メリット

  • 価格が色付きで表示されるので見やすい
  • 自由な時間間隔で表示を制御できる

価格が色付きで表示されるので見やすい

上がったら緑、下がったら赤で表示されるので見やすいです。

自由な時間間隔で表示を制御できる

冒頭の時間を指定するだけでいいので、好きな間隔に指定できます。

デメリット

  • Zaifを直接ブラウザで表示させれば良いんじゃね?
  • bashを持っていないOSでは使えない

Zaifを直接ブラウザで表示させれば良いんじゃね?

現状では、価格をシェルに表示させるだけなので、ほとんど意味がありません。

価格をチェックして、メールで送信する機能も考えていましたが、難航しそうなのでオミットさせました。

bashを持っていないOSでは使えない

bashのエスケープ文字に依存しているので、当然ただのWindowsでは使えません。

結論

今回はテストとしてSeleniumを使い、リアルタイムで変動する値を掴んでみましたが、予想通りうまく掴むことができました。

クラス名が変動する場合であったとしても、SeleniumのXpathを使えばなんとかなりそうですね。

後は、指定した価格になったらメールで送信したり、最終的には自動で売買ができるようにしてみたいところです。

セキュリティの問題は気になりますが、理論上はできるでしょう。

関連記事

Seleniumを使ったTwitterボット

【内部リンク】Seleniumで動く自動ツイートプログラム(ボット)をcronに対応させてみた【連投防止機能付き】

Seleniumを使ったTwitterボットです。

いずれはユーザーのツイートを自然言語処理にかけて、価格の変動を事前に予測できるようなプログラムを作ってみたいものです。

Amazonのほしい物リストの値下げを検知

【内部リンク】Amazonのほしい物リストから値下げされた商品だけをメールで通知するPythonプログラム

こっちは値下げを検知して、メール送信までしてくれます。

Amazonはスクロールしないと読み込まない仕様になっているので、Seleniumで自動でスクロールさせています。