TwitterAPI V2とTweepyで作る 経済指標ツイートbot つまずいたポイント②【スクレイピング編】
このnoteは自作のTwitterBotである経済指標ツイートbot(@Bot64990849)を作成・実行する際につまずいたポイントについて解説します。
開発環境などの前提条件に関しては以下のnoteをご覧ください。
また、経済指標ツイートBotの仕様説明や使い方に関しては当ブログの以下の記事をご覧ください。
このnoteで解説すること
このnoteではスクレイピング編と題している通り、Twitterでつぶやくための経済指標をスクレイピングで取得する際につまずいたポイントについて解説します。
主に今回スクレイピングで使用したライブラリである「Playwright」について解説します。
Playwrightとは
PlaywrightはMicroSoftが開発したインターネットブラウザ自動操作ライブラリの一種です。
公式サイトによると以下のように説明されています。
同じようなライブラリとして有名なのが「Selenium」です。
しかし、使ってみた感じとしては明らかにPlaywrightの方がユーザーフレンドリーで使いやすかったです。
Playwrightのインストール方法
特に難しいこともありませんが、インストール方法について解説します。
まずはいつも通りpipでインストールを行います。
pip playwright
通常のライブラリであればこれで使用可能になりますが、Playwrightの場合、ブラウザを自動操作するためのドライバーなどのモジュールが必要になります。
Seleniumであればわざわざネットで検索→ダウンロード→フォルダに配置というような手順を踏む必要があります。
しかし、Playwrightの場合、以下のコマンドで必要なモジュールを一括でインストールすることができます。
playwright install
勝手にドライバーのパスも通してくれるのでめちゃくちゃ便利です。
Playwrightの実装
次にPlaywrightの基本的な使い方を見てみます。
以下のようにすると一発で目的のURLのページが取得できます。
with sync_playwright() as playwright:
browser = playwright.chromium.launch()
context = browser.new_context(user_agent=ua)
page = context.new_page()
page.goto(url)
html = page.content()
(詳しい使い方や各関数で何やってるかなどは公式ドキュメントをご覧ください。)
JavaScriptによってレンダリングされていないページの場合、これでページ内のコンテンツが取得できます。
そうです、JavaScriptによってレンダリングされていないページの場合です。
残念ながら今どきそんなページはほとんど存在しないので、実質機能しません。
よって当然今回の目的である経済指標のデータを取得するということもできませんでした。
ここがスクレイピング編第一のつまずきポイントです。
JavaScriptに対応したPlaywrightの実装
トライアンドエラーを繰り返した結果以下の実装でJavaScriptでレンダリングされたページに対応できました。
with sync_playwright() as playwright:
browser = playwright.chromium.launch()
context = browser.new_context(user_agent=ua)
page = context.new_page()
page.goto(url, wait_until='networkidle')
html = page.content()
5行目のpage.gotoの引数にwait_until='networkidle'を追加しています。
この引数によって、少なくとも500ミリ秒ネットワークからの応答がなくなるまで待機してくれます。
500ミリ秒は最低でも待機してしまうので、JavaScriptでレンダリングしていない場合、動作が遅くなる点には注意が必要です。
なおnetworkidle以外にも指定できるので、詳しく知りたい方はこちらをご覧ください。
変更箇所としてみるとたったの1行ですが、Playwrightの情報がなさ過ぎて公式ドキュメントを検索しまくり読みまくる羽目になりました。
先述の通り、今どき大体どのページもJavaScript使ってるので最初からこの書き方を使ったほうが良いと思います。
PlayWrightをWindowsSearverで実際に動作させてみる
さて、私は実行環境にWindowsServerのVPSを利用しています。
そのため、pyinstallerというライブラリを用いてexe化して実行します。
pyinstallerは依存関係や実行環境ごとexe化できるので便利です。
(pyinstallerについてはここでは触れません。)
さぁ、pythonスクリプトをexeして実行します!
例外が発生しました。
は?
動かなかった原因
そうです、動きません。
ここが第二のつまずきポイントです。
pythonスクリプトの状態では正常に動作していたのに、exe化すると例外が発生するようになりました。
原因は単純で、Playwrightの外部モジュールであるドライバまでのパスが見えなくなってしまっていたのが原因でした。
対策
基本的にpyinstallerは依存関係までみて一緒にexe化してくれますが、それはpython内でのimport文を解釈しているだけです。
よって、外部モジュールであるドライバーまでは持ってきてくれません。(当然ですが)
そこで、以下のように実装を変更します。
with sync_playwright() as playwright:
browser = playwright.chromium.launch(
executable_path=CHROME_DRIVER_PATH)
context = browser.new_context(user_agent=ua)
page = context.new_page()
page.goto(url, wait_until='networkidle')
html = page.content()
2行目のplaywright.chromium.launchの引数executable_pathにドライバまでのパスを渡すように変更しています。
WindowsServer上にドライバーを配置し、そこまでのパスを指定してあげることで動作するようになります。
タスクスケジューラに設定してPlaywrightを定期実行してみる
ドライバーのパスも通して実際に動作することを確認しました。
経済指標は定期的に取得する必要があるので、タスクスケジューラにスケジュールを登録して定期実行するようにします!
ちゃんと経済指標は取得できているかな?
SELECT COUNT(*) FROM 経済指標テーブル;
>>0
え?
タスクスケジューラで動作しなかった原因
そうです、やっぱり動きません。
ここが第三のつまずきポイントです。
exe化してWindowsServer上で手動実行した場合は正常に動作することを確認していました。
しかし、タスクスケジューラに登録するとなぜか動作していません。
この原因は、タスクスケジューラに登録した場合、バックグラウンドプロセスとして登録されるため、プロセスの優先順位が低となり、PCのリソースが割り振られなくなっていたからでした。
おそらくこのような状態になったのは、私がVPSをスペックの限界ギリギリまで酷使していたことも原因だと思います。
なので、もしかしたらスペックに余裕のあるVPSで実行する場合、この不具合は発生しないかもしれません。
対策
今回はプログラム側ではなく、タスクスケジューラ側の問題(?)なので、タスクスケジューラに登録する際、優先順位を上げて登録するようにします。
手順としては以下の通りです。
タスクスケジューラにタスクを登録
タスクをエクスポート
タスクを削除
2.でエクスポートしたxmlを編集
タスクをインポート
xmlを編集してエクスポートするには以下のように行います。
登録したタスク上で右クリックをすると「エクスポート」と表示されているので、クリックします。
任意の名前を付けて、xml形式で保存します。
その後、インポートするためにエクスポートしたタスクは削除しておきます。
エクスポートしたxml内の「Priority」タグの値を「3」に変更します。
タスクスケジューラの右メニューからタスクのインポートを選択し、編集したxmlファイルを選択してインポートします。
これで優先度を上げてタスクスケジューラに登録することができます。
ここまでやってようやく、経済指標の定期取得ができるようになります。
さいごに
いかがでしたでしょうか。
今回は経済指標をPlaywrightで用いて取得する際につまずいたポイントについて解説しました。
正直最後のはWindowsServer側の問題ですが、ここにたどり着くためにかなり時間を浪費してしまったので、対策を載せておきました。
Playwrightは素晴らしいライブラリで、正直スクレイピングを自動テストもSeleniumよりもこちらでやったほうが遥かに良いと個人的には思っています。
今回の記事がスクレイピングをやりたい方やTwitterでBotを作りたい方のお役に立てれば幸いです。
それではまた次回、TwitterAPI編でお会いしましょう。
この記事が気に入ったらサポートをしてみませんか?