MetatraderをUbuntu上で動かす
Metatrader
久しぶりにMetatraderを触るかもしれない。
基本的にMetatraderはWindows環境でしか動かない。 UbuntuをメインOSとしている者としては何らかの形でUbuntu上でWindows環境を作ってやらないといけない。
集中的にEAを作ったり、為替のデータ分析に勤しんでいた時はWine上でMetatraderを動かしていた。 Wineだから使いにくいとか、極度にもっさりしているとかいうことはなかった。 むしろ、思ったよりモッサリ感はなく、同時に動かしている他のソフトウェアも快適に動いた。 ただ、あまりに負荷をかけ過ぎたりすると、クラッシュすることもあったのは確かである。 それでも、不便さは許容範囲内だったし、むしろ自分の開発環境が整っていないWindows上で作業することを考えれば、Wineの方が良かったと思う。
Windowsの仮想マシンがあるらしい
最近、LinuxでVirtualBoxなどの仮想化ソフトウェアを使って、Windows環境を無料で動かせることを知った。 Microsoftが主にEdgeやIEのブラウザテストのために準備しているもののようだ。 もしかすると、こちらのほうが作業する上で便利なのかもしれない。 そんな期待を抱いて、ちょっとMetatraderを動かしてみた。
ovaファイルを入手する
まずは、ここにアクセスしてovaファイルが入ったzipを入手する。
なぜか当方のPCではWin10が動かないので、今回はIE11 + Win8を選択。
ダウンロードできたら、unzipしてovaファイルを取り出す。
VirtualBoxにovaをインポート
VirtualBox以外の仮想化ソフトウェアでもできるみたいだが、今回はVirtualBoxで。
- Oracle VM VirtualBox を起動
- メニューから [ファイル]-[仮想アプライアンスのインポート] を選択
- 『インポートしたいアプライアンス』に、解凍した IE11 - Win8.ova を指定して、[次へ] ボタンを押す
- 必要な項目を変更して、[インポート] ボタンを押す
- インポート完了後、VirtualBox に追加される
VirtualBoxで起動
Win8の仮想マシンを選択し、起動。
無事起動。
Metatraderもインストール、起動したことを確認。
結論
URLを移動しても、React-Tableで今見ていたページ数を覚えておく
React-TableというReactのテーブル・コンポーネントがある。
以下のような特徴がある。
1. ヘッダー、セル、フッターの細部までカスタマイズ可能
2. デフォルトですでに多機能(フィルタリング、ソート、行数の変更、リサイズなど)
3. ドキュメントが丁寧
個人的なWeb開発に利用しているのだが、結局テーブルはこのコンポーネント一つで事足りた。
他のテーブルは使っていないので、比較はできないが、
本当にありがたいコンポーネントだった。
ごっつぁんでした。
ちなみに、Nozzle.ioという会社の共同創業者が書いたらしい。 なぜ、この人がReact-Tableを書いたのか、その熱い思いはここに書かれている。
困ったこと
明瞭なインターフェースと分かりやすいドキュメントでほとんど困ることはなかったのだが、一つだけ詰まったのが「いかにして、違うURLに移動しても、今見ていたテーブルのページ数を覚えておくか」ということだった。 移動前のページ数を覚えておかないと、例えば「テーブルの2ページ目を開いている時に違うURLに移動し、そのURLから戻ってきた時にテーブルが1ページ目になってしまっている」という問題が起きる。 言い換えると、違うURLから戻るボタンで戻ってきて、テーブルの続きを見ようかなと思っていると、1ページ目が表示されていて、肩透かしを食らってしまうというわけである。
この問題を解決するために、以下のようなコードを書いた。
class Table extends React.Component { constructor (props) { super(props) if (typeof window !== "undefined") { let stringAfterQuestion = window.location.href.match(/page=.*/, "") if (stringAfterQuestion === null) { this.state = { tablePage: 0 } } else { this.state = { tablePage: Number(stringAfterQuestion[0].replace(/page=/, "")) - 1 } } } } render () { //GatsbyのURLを変更するメソッド const navigateTo = require("gatsby-link").navigateTo return ( <ReactTable className="-striped -highlight" data={tableData} columns={tableColumns} loading={this.props.loading} page={this.state.tablePage} pageSizeOptions={[20]} defaultPageSize={20} onPageChange={(pageIndex) => { if (typeof window !== "undefined") { this.setState({tablePage: pageIndex}) navigateTo(window.location.pathname + '?page=' + String(pageIndex + 1)) window.scrollTo(0, this.props.scrollPosition) } }} /> ) } }
基本的には、テーブルのページ数をstate
のtablePage
で管理して、ReactTableのpage
プロパティからそれを参照するという仕組みになっている。
プログラムの流れとしては、以下のようになる。
1. ページャーがクリックされたら、onPageChange
でtablePage
を書き換える。
2. tablePage
が書き換えられ、描画処理が始まる。
3. <ReactTable>
のpage
プロパティにtablePage
の値を代入し、そのページを表示させる。
ただ、これだけだと、他のURLから戻るボタンで戻ってきたケースでは、tablePage
の初期値である0がpage
に代入され、テーブルの1ページ目が描画されてしまう。
そこで以下のようなプログラムを付け加える。
1. ページャーがクリックされたら、onPageChange
内でURLに?page=2といったクエリパラメータを付け加える、またはそれを書き換える。
2. ページの初期読み込みの際は、クエリパラメータとして保存した値をtablePage
の初期値とする。
こうすることで、例えば、テーブルの2ページ目を見ていて、他のURLに移動し、また戻るボタンで戻ってきても、コンポーネントの初期化の際にURLの?page=2に保存された2がtablePage
に代入され、移動前に見ていたテーブルの2ページ目が描画される。
もしかすると、「親コンポーネントのstateでテーブルのページを管理する」というやり方でもいけるのかもしれないが、 自分が試した時はページャーをクリックしてもテーブルのページ移動がされないというトラブルが生じた。
コマンドラインでVPNサーバーに接続する
何かの気の迷いからフリーのVPNサーバーに接続したくなるときがある。 そんなとき(Linuxなら)NetworkManagerのアプレットをポチポチして、設定・接続してもよいのだが、 今回はさらに気が迷ったのでコマンドラインで接続してみた。 今回は某国立大学のVPN実験サービスを使ったが、他のサービスでも接続可能だと思う。
環境
- Ubuntu 16.10
- NetworkManager 1.2.6-0ubuntu1.1
ovpnファイルをダウンロード
ポチポチしてダウンロードしてもよし、wgetで取ってきてもよし。
NetworkManagerに接続設定を追加
ovpnディレクトリに入った複数のovpnファイルをインポートして、NetworkManagerに接続設定を追加する。
(シェルはfish shell)
for file in (ls ovpn) nmcli con import type openvpn file "ovpn/$file" end
追加した接続情報を確認する
nmcli con show
VPNサーバーに接続する
$selected_uuid
変数に納められたUUIDのサーバーに接続する。
nmcli con up uuid $selected_uuid
接続を切断する
$active_uuid
変数に納められたUUIDのサーバーとの接続を切断する。
nmcli con down uuid $active_uuid
Pythonから接続したい場合はsubprocessを使えばよいでしょう。
Gatsbyはグレートなのか?
Gatsbyという静的サイトジェネレータ(SSG)がある。
特徴としては、
1. React.jsでフロントエンドを書くために作られた
2. Webapckでビルドする
3. ただのSSGではなく、Progressive Web Appを生成するジェネレータである
4. ブログ記事のデータ等はGraphQLで取ってくる
といったものがある。
静的サイトジェネレータとしては後発であるが、 StaticGenを見ると分かるように、Githubのスターの数はかなり多い。 スターの数では同じJavascriptで作られたHexoに迫らんとしている。 まさに、昇竜の勢いでSSG界を駆け上がっているジェネレータだと言えるだろう。(言い過ぎ?)
早い
Gatsbyを体験するにはGatsbyのドキュメントを開いて、ページ遷移すると良い。 SPAらしくサクサクと遷移し、ユーザー体験としてはかなり快適だ。 おそらく、このドキュメントは高速表示するためにかなり最適化しているとは思うのだが、 まだ割と散らかった状態のコードでビルドしたものでも表示はかなり早い。
データソース
基本的にブログ記事のタイトルや文章などはMarkdownで書く。 そして、そのデータをビルド時にGraphQLで取ってきて、各ページを生成する。 お手軽にブログを作りたい人は、「GraphQLに慣れるのに時間がかかるんじゃ...」と思うかもしれないが、 そんなにGraphQLをがっつり勉強しなくてもとりあえず作ることはできる。
また、データソースはMarkdownだけではなく、WordpressやJSONなどにも対応している。 gatsby-source-wordpressという専用プラグインが用意されており、Wordpress内で管理されているデータをそのままGatsbyに流用することができる。 また、JSONの場合は、gatsby-transformer-jsonがある。
プラグイン
ちなみに、プラグインの数は他のSSGに比べれば、まだまだ少ないのかもしれないが(他のSSGは未確認)、 それでも自分が今サイトを作っている限りでは足りないということはない。 プラグインの一覧を見れば分かるように、このぐらいはある。
SEO対策にはgatsby-plugin-react-helmetやgatsby-plugin-sitemapがあるし、Twitterのツイートを埋め込むためのgatsby-plugin-twitterなどもある。 プラグインとは言えないのだろうが、専用コンポーネントとしてReact RouterのWrapperであるgatsby-linkや画像表示を最適化するgatsby-imageなどもあり、なかなか豊富な機能となっている。
デプロイ
静的サイトであるがゆえに、デプロイも非常に簡単。 Webpackでpublicディレクトリ内にビルドされたビルド物をコマンド一発でデプロイするのみ。 自分はFirebase Hostingにデプロイしているが、当然AWSのS3やGithub Pagesにもデプロイできる。
スターター
「Typescriptで書きたい」とか「CSSフレームワークとしてbootstrapを使いたい」という人はstarterというものが用意されている。 このスターターを使えば、自分でこれらをインストールしなくても、予め必要物がセットになったものからサイト構築を始めることができる。 ちなみに、私はSEOのためのライブラリやGoogle Analyticsサポートなどが用意されている、gatsby-advanced-starterにreact-semantic-uiを入れて使っている。
締め
こんな感じでGatsbyを概観してきた。 日本語情報が少なく、当初は私も敷居の高さを感じていたが、めっちゃ難易度が高いというわけではない。 Calypsoやらrelaxやらが開発される中で この先SSGのGatsbyを使う場面があるのかは分からない。 でも、このタイミングでSPA×SSGでブログやメディアを作ってみたいという人は選択肢としてありかもしれない。
Node.jsとSQLiteで全文検索・一歩前
データベースに文字列を保存して、全文検索できるようにしたい。 でも、マネーレスでクラウドのデータベースサービスは使いたくない。 そんな悩みに答えるかもしれないSQLite。 今ではAWSのLambdaにdbファイルをデプロイして、使う人も出てきている。
AWSのLambda + sqlite でサーバレスRDSもなしでAPI実装
実サービスでAWS Lambda内でsqlite3を使った話
このようにお手軽なSQLiteだが、実は全文検索も行うことができる。 SQLiteで全文検索しようとすると、fts(Full Text Search)という拡張機能を有効にしてコンパイルする必要があるが、npmならこのコンパイルも簡単にできる。
fts機能を有効にしたSQLiteのインストール
export CFLAGS="-DSQLITE_ENABLE_FTS3_PARENTHESIS" npm install sqlite3 --build-from-source
node-sqlite3の導入
npm install https://github.com/mapbox/node-sqlite3/tarball/master
テーブルの作成
このライブラリを使えば、とても簡単にデータベースを操作できる。
例えば、テーブルを作成するコードは以下のようになる。
a,b,cという3つのカラムを持つテーブルを作成する関数である。
クエリ文のVIRTUAL
というのは、仮想テーブルを作成するためのもの。
SQLiteで全文検索するためには、普通のテーブルではなく、専用の仮想テーブルを作成する必要がある。
import sqlite3 from "sqlite3" const createTable = (tableName) => { const db = new sqlite3.Database('test.db') db.serialize(() => { let queryString = "CREATE VIRTUAL TABLE " + tableName + " USING fts4('a', 'b', 'c')" db.run(queryString) db.close() }) } createTable("test")
テーブルにデータを挿入
const insertData = (tableName) => { const db = new sqlite3.Database('test.db') db.serialize(() => { let prepare = db.prepare("INSERT INTO " + tableName + " VALUES (?, ?, ?)") const insertDataList = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] insertDataList.forEach((value, index, array) => { prepare.run(value, (err) => { if(err){ throw err } }) }) }) db.close(); } insertData("test")
テーブルのデータを見る
const showTableData = (tableName) => { const db = new sqlite3.Database('test.db') db.serialize(() => { db.each("select * from " + tableName, (err, row) => { console.log(row) }) }) db.close(); } showTableData("test") /* { a: 1, b: 2, c: 3 } { a: 4, b: 5, c: 6 } { a: 7, b: 8, c: 9 } */
全文検索機能が有効になったことを確認
本題の全文検索であるが、MATCH句を使用して行う。 以下の検索は、検索対象が行に存在すれば、行全体を返してくれる。 今回はMATCH句が使えるようになり、全文検索機能が有効になるところまでを確認しておく。
const searchFullText = (tableName, searchWord) => { const db = new sqlite3.Database('test.db') db.serialize(() => { let queryString = "SELECT * FROM " + tableName + " WHERE " + tableName + " MATCH " + "'" + word + "'" db.each(queryString, (err, row) => { if (err) { throw err } console.log(row) }) }) db.close(); } searchFullText("test", 1) //{ a: 1, b: 2, c: 3 } searchFullText("test", 4) //{ a: 4, b: 5, c: 6 } searchFullText("test", 7) //{ a: 7, b: 8, c: 9 }
まとめ
ここから日本語の全文検索ができるようにするには、検索アルゴリズムをきちんと考えてやらねばならない。 関連キーワードは、部分一致、前方一致、N-Gram、分かち書き、Mecabなど。 マネーで何事も解決できる人は、こんなことやらずともAWSのElasticSearchやAlgoliaを使えばよろし。
雰囲気でネーミングするのを止める
今まで雰囲気でネーミングしてきたように思う。 反省している。 これからは可読性や効率性を高めるネーミングをしていきたい。 そのためには具体的に何をすればよいだろうか。
それぞれのコーディング規約に従う
それぞれの領域で広く参照されているコーディング規約がある。 その規約に従うのが最も確実だと思う。 というのも、多くの人がその規約に従っているので、それに従ったコードは多くの人にとって読みやすいものとなるからである。 もし、チーム内で規約が定められているならば、それに従うことになると思う。
コーディング規約には必ず命名規則が含まれている。 PythonのPEP8にもあるし、 Airbnb Javascript Style Guideや Google Javascript Style Guideにもある。 まずはそれを読み、その命名規則に従うところから始める必要があるだろう。
正しい英語を使う
コーディングしているとパッと適切な英語が思い浮かばないことがしばしばある。 そういう時、知っているが恐らく不適切であろう英語でお茶を濁したりしてきた。 これからはきちんと調べて、なるべく正しい英語を使っていきたい。
開発者の方々によるまとめや命名のためのWEBサービスはとても参考になり、便利である。 例えば、有名だが下記のようなものが参考になると思う。
Naming -名前付け-
著名な書籍の名前付けについての情報をまとめているページ。うまくメソッド名を付けるための参考情報
どのような種類のメソッドにどのような名前を付けるかについて書かれている。
こうした情報を参考にしながら、その時々に適切なネーミングを心がけたい。
変数やメソッドの役割を明確にする
良いアークテクチャは、良いネーミングと対になっていると聞いた。 まだ、この言葉の意味するところがまだ腹から分かっていないような気がする。 でも、何となくは分かる。 例えば、メソッドの役割が自分の中で明確になっている時は、割と自信を持って命名ができる。 そうでない時はなかなか適切な名前が思いつかない。
だから、例えばメソッドなら
- 何を操作するか
- どこからデータを取ってくるのか
- 戻り値の型は何なのか
といったことを先に考えた上でコードを書き始めることが大事なのだろう。 そうすれば、その部分のコードを書き終えた時に自然と名前は浮かんでくる。
上のリンクの記事では、将来的にメソッドや変数の役割が変わるところまで見越して、ネーミングすべきだと書かれている。 自分はまだまだ目の前のタスクをこなすためのコードを書くことに集中するばかりで、その域にはまだ達していない。
とは言え、命名法から始まりプログラムのアーキテクチャにも意識を置いていかねばならないのだろう。
終わりに
これだけは絶対避けましょう。
beautifulsoupのドキュメントの真ん中辺りに書かれている便利な関数
スクレイピングで目的の要素にアプローチする方法は色々あると思う。
1. find系のメソッドでアプローチ
2. CSSセレクタでアプローチ
3. 正規表現でアプローチ
今日は1のアプローチからBeautifulSoupのsibling系のメソッドをご紹介する。
siblingとは英語で兄弟姉妹の意味。
その名の通り、指定のタグの隣にあるタグを返す。
sibling系には次の4つのメソッドがある。
(ここからは以下のようなタグを例にする。)
sibling_soup = BeautifulSoup("<div><a>稀勢の里</a><b>高安</b></b><c>豪栄道</c></div>", "lxml") print(sibling_soup.prettify()) #<html> # <body> # <div> # <a> # 稀勢の里 # </a> # <b> # 高安 # </b> # <c> # 豪栄道 # </c> # </div> # </body> #</html>
1. next_sibling
指定の要素の次にあり、かつ同一階層にある要素を一つだけ返す。
print(sibling_soup.a.next_sibling) ## <b>高安</b> print(sibling_soup.b.next_sibling) ## <c>豪栄道</c> print(sibling_soup.c.next_sibling) ## None
2. next_siblings
指定の要素より後ろにあり、かつ同一階層にある要素をもつジェネレータを返す。
print(sibling_soup.a.next_siblings) ## <generator object next_siblings at 0x7f533daf20f8> for tag in sibling_soup.a.next_siblings: print(tag) ## <b>高安</b> ## <c>豪栄道</c>
3. previous_sibling
指定の要素の前にあり、かつ同一階層にある要素を一つだけ返す。
print(sibling_soup.a.previous_sibling) ## None print(sibling_soup.b.previous_sibling) ## <a>稀勢の里</a> print(sibling_soup.c.previous_sibling) ## <b>高安</b>
4. previous_siblings
指定の要素より前にあり、かつ同一階層にある要素をもつジェネレータを返す。
print(sibling_soup.c.previous_siblings) ## <generator object previous_siblings at 0x7f533daf20f8> for tag in sibling_soup.c.previous_siblings: print(tag) ## <b>高安</b> ## <a>稀勢の里</a>
これならクラス名を変えられても、何とか目的の要素をスクレイプできそう。