目次。
書いたプログラムが証券会社の口座にログインできなければ、株の自動売買は夢のまた夢なので、「まずは証券会社の口座にログインするぞ」というお話。
自動株式売買プログラムを思い立った話。については、以下の記事をどうぞ。
この文章を読んで、面白い!役に立った!...と思った分だけ、投げ銭していただけると嬉しいです。
【宣伝】ギターも歌も下手だけど、弾き語りをやっているので、よければ聴いてください。
ざっくりと。
ブラウザ(Google chrome, Firefox, internet explorer, safariとか)を開いて、証券会社のwebページ(サーバー)にアクセスして、ユーザーID、パスワードを入力して、、、
これがログイン。今回は、この過程をプログラムで実装しようという話。
http、ついでにhtmlの話。
httpという言葉は、皆さん知っているはず。ブラウザのアドレスバーによく出てくるやつ。このブログを見ている人ならアドレスバーに「https://blog.sun-ek2.com/~」と表示されていると思う。この例では、「http」ではなく「https」になっているが「s」の話をするとめんどくさいので割愛。
httpの正式名称は、「HyperText Transfer Protocol」。日本語でいうと「ハイバーテキストを送るための約束事」。もっと言うと「テキストを超越したテキストを送るための約束事」。
実は、今読んでいるこの文章も「テキストを超越したテキスト」。「テキストを超越したテキスト」というとなんだかものすごい気がするが、実はそうでもなくで、単にリンク(ハイパーリンク)が貼られたテキストのこと。今の感覚からすると、ネーミングがちょっと大げさな気がする。(もちろん、昔は画期的なアイデアだったんだろう)
ハイパーテキストは、特別な言葉で書かれていて、通常それはhtmlと呼ばれる。htmlは、「HyperText Markup language」、つまり「ハイパーテキストを飾り付ける言語」。そのままである。そしてハイパーテキストが書かれたファイルは、htmlファイルと言われる。
ブラウザでこのブログにアクセスして内容を表示するという一連の過程の裏側でやられていることは、HTTP通信とレンダリング。
ブラウザがblog.sun-ek2.comというニックネームがつけられているサーバー(はてなブログのサーバー。僕は、サーバー持ってない。高校の時にサーバー構築しようと一瞬だけ血迷ったが)に「htmlファイルをください」とお願いするとサーバーは、僕のブログの記事が入ったhtmlファイルを送る。これがHTTP通信。
送られてきたhtmlファイルは、とても人が読める代物ではない。このhtmlファイルはブラウザによって人が読みやすいように加工される。これがレンダリング。
そして今回、注目するのはHTTP通信。
HTTP通信の勉強をするのであれば、RFCのHTTPのところを読むか(僕は読んだことないし、読もうとは思わない)、ネットワークの本を読むかのどちらか。HTTPが単独で説明された本は、あんま見たことがない。
証券会社のサーバー、ブラウザ間のHTTP通信を調べる話。
HTTP通信を調べるのは、実は簡単。ブラウザにデフォでついている開発ツールを使えばいい。Firefoxの場合は、[Ctrl] + [shift] + [E]で出てくる。ブラウザが行ったHTTP通信一覧は、「ネットワーク」というところで見れる。
開発ツールを開いたまま、証券会社のwebサイトにログインするとこんな感じ。最初にやることは、この一覧の中からユーザーID, パスワードが渡されたHTTPリクエストを探すこと。
しばらくいじくっていると、、、見つかった!
ログによると、ブラウザは「ユーザーID」,「パスワード」, 「その他諸々」をHTTP通信の「POST」メソッドによって「http://(証券会社のwebサイトURL)/(ログイン処理をするプログラム)」に送ったっぽい。
ブラウザがやったことをブログラムで実装すれば、自動ログインができる!
、、、と言いたいとこだが、それだけでは上手くいかない。
セッションの話。
HTTPはステートレスなプロトコル。つまりHTTPには、昔行われたHTTPリクエストを覚えておくだなんて約束事は一切書かれていない。ユーザーがIDとパスワードを入力してログインしてもwebサーバーはユーザーをすぐに忘れてしまう。
つまり、、、
ユーザー「ログインする」
→サーバー「htmlファイルを送る。ユーザーのことを忘れる」
→ユーザー「別のwebページに移動する」
→サーバー「ユーザーのことを忘れているため、IDとパスワードを要求」
→ユーザー「IDとパスワードを入力」
→サーバー「htmlファイルを送り、すぐさま、ユーザーのことを忘れる」
→ユーザー「…」
といった感じ。毎回IDとパスワードを入力するのはめんどくさい。そして、IDとパスワードの他にも情報を一定期間、保持できたら何かと都合がいい場合がある。
せめてログインからログアウトまでの一定期間(セッション)、サーバーに自分のことを覚えてもらえないものか。こんな悩みを解決するのが、「HTTP Cookie」。HTTP Cookieは、サーバー、ブラウザ間で行き来する情報の小包みたいなもの。その小包に「セッションID」というユーザーを識別する情報を載せて、通信すればサーバーが自分のことを思い出してくれるわけである。
ということで、自動ログインでもう一つ大事なことは、セッションIDをきちんと取り出すこと。
自動ログインの実装の話。
元々は、学部4年の頃にJavaで開発を始めたのだが、開発言語をPythonに変えた。やっぱ、機械学習の分野では、Pythonがむちゃくちゃ強いのと、研究のデータ解析とか、シミュレーションでPythonを使う機会が増えるので慣れたいのが理由。
Pythonで実装。
Pythonの標準ライブラリにあったHTTP通信できるやつ→urllib.request。
リファレンスを見てみると、
参考: より高水準の HTTP クライアントインターフェイスとしては Requests パッケージ がお奨めです。
公式が言うんだから仕方がない、非公式のパッケージ(Requests)を落としてきて、作業開始。
リファレンスにあるサンプルコードを参考に証券会社の口座にログインするコードを書くとこんな感じ。
import requests from bs4 import BeautifulSoup import re login_url = '証券会社のログイン処理をするプログラムがいるところ。' login_parameters = {'ユーザーID':'foo', 'パスワード':'foo', 'その他諸々':'foo'} r = requests.post(login_url, login_parameters) cookie_jar = r.cookies #セッションIDがhtmlファイルの中に埋まっていたので、発掘。 soup = BeautifulSoup(r.text) SessionID = str(soup.hoge()).hogehoge() #BeautifulSoupのメソッドとか正規表現をゴリゴリに使って発掘。
セッションIDはhtmlに埋まっているぽかったので、http通信の後にhtmlファイルをパースするコードが書いてある。教科書的には、セッションIDはHTTP Cookieの中なのだが。別にそういうわけではないっぽい。(詳しい人教えてください)
セッションIDだけでええやろってことで、はじめはHTTP Cookieを無視してhtmlファイルからセッションIDだけ抜き取って、通信を続けようとしたけど、セッションが切れてしまった。どっちにせよHTTP Cookieの管理は必要。
HTTP通信のリクエストヘッダーは特に明示的に設定しなくても上手くいったので、特になんもしてない。(HTTP Cookie以外)
Javaで実装。
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.net.CookieHandler; import java.net.CookieManager; import java.net.MalformedURLException; import java.net.URL; import javax.net.ssl.HttpsURLConnection; public class Login { public static void main(String[] args) { final String StrUrl = "証券会社のログイン処理をするプログラムがいるところ"; final String userid = "ユーザーID=foo"; final String password = "パスワード=foo"; final String others = "その他諸々=foo"; CookieManager cmaneger = new CookieManager(); CookieHandler.setDefault(cmaneger); String sessionID = null; try { URL url = new URL(StrUrl); HttpsURLConnection uc = (HttpsURLConnection) url.openConnection(); uc.setDoOutput(true); OutputStream os = uc.getOutputStream(); String postStr = userid + "&" + password + "&" + others; PrintStream ps = new PrintStream(os); ps.print(postStr); ps.close(); InputStream is = uc.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is, "EUC-JP")); String line; //セッションIDがhtmlファイルの中に埋まっていたので、発掘。 //久しぶりに見返したらHTMLパーサー使っていなかった。 Hoge hoge = new Hoge(); while((line = br.readLine()) != null) { //html解析。証券会社によってhtmlの構成が違うのでhogeで割愛。 sessionID = hoge.parse(line) } br.close(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
最後に。
ログインした状態を維持しないと見れないようなページ(保有株式一覧とか)の情報をプログラムから取ってこれたので、自動で株の買い注文、売り注文をするには、今回得られたセッションIDとHTTP Cookieをお供えして、ブラウザがサーバーに送るHTTPリクエストを真似るコードを書けば実現できると思う。
まあ、それより機械学習の勉強とその知識を応用した売買ロジックを考えることが先なのだが。
"Pattern Recognition and Machine Learning"は、2章まで読み終わったところ。多変量ガウス分布の指数部になんで分散共分散行列の逆行列があるか、ずっと謎だったが解決してスッキリ。
この文章を読んで、面白い!役に立った!...と思った分だけ、投げ銭していただけると嬉しいです。