色々あって
Twitter がデザイン変更して、スクレイピングが失敗するようになり、またDOM解析して修正かー・・・とか思ったら、SPA 化かなんかで全然 DOM の把握ができず、スクレイピングどころではないってなって、あー!!
ってことで、以前から気になっていた Selenium を使ってみます。
大体、Twitter が提供している API でちゃんと全部情報が取れないのが悪い。センシティブと判定された tweet とか取れないんだよなー
Perl 側の準備
ためらうことなく cpanm
$ cpanm Selenium::Remote::Driver
Perl のモジュールインストールが終わったか確認
$ perl -e -MSelenium::Remote::Driver
これは、ワンライナーという Perl の書き方。モジュールを呼び出しただけのコード。ここでエラーが出なければok
引数の説明はこんな感じ。
- -e 引数をPerlのコードとして解釈して実行する
- -M モジュールを呼び出す
上記のワンライナーをコードに起こすとこう。この1行。
use Selenium::Remote::Driver;
ここで use
できないとエラーが出る。エラーが出ない、ってことはとりあえずインストールはできている。
ワンライナーは短くかけるので、ギュッとまとめるとこう。
$ perl -eMSelenium::Remote::Driver
この perl -eMモジュール名
ってワンライナーでインストールの成否を見たりするのはワンライナーの定番。
Mac 側の準備
Perl (とか他のプログラム言語)側からブラウザを操作するためのドライバをインストールする。
$ brew install geckodriver $ brew cask install chromedriver
brew の formula がインストールされたか確認
まずは Chrome のドライバを実行
$ chromedriver Starting ChromeDriver 83.0.4103.39 (ccbf011cb2d2b19b506d844400483861342c20cd-refs/branch-heads/4103@{#416}) on port 9515 Only local connections are allowed. Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe. ChromeDriver was started successfully.
こちらは大丈夫そう。CTRL-C で閉じる。
次は Firefox 用のドライバ。Gecko ってのは Firefox のHTML描画エンジンなのだけど、最近はあまり名前聞かなかったんで懐かしくなった。
$ geckodriver
応答ないので CTRL-C で閉じる・・・大丈夫かなぁ。
Google のトップページを表示してタイトル取得して終了するだけ
初めてなので、基礎からやっていく。まずは Google のトップページを出して、タイトルを取得するだけ。
#!/usr/bin/env perl use strict; use warnings; # Selenium::Web::Driver と一緒にインストールされる Chrome 用のドライバを呼び出す use Selenium::Chrome; # ドライバのインスタンスを起動する。初期化みたいなもの。 my $driver = Selenium::Chrome->new; # Google のトップページに移動する。Get は Perl入学式 第5回でやったアレです。メソッドってやつです。 $driver->get('https://www.google.com'); # 移動した後のページのタイトルを表示する print $driver->get_title() . "\n"; # Google # ドライバを終了する $driver->shutdown_binary();
Chrome が立ち上がって、Googleのトップページを表示して自動的に終了する。コンソールにはページのタイトルが表示されている。
次は Firefox。説明は省略。
use Selenium::Firefox; my $driver = Selenium::Firefox->new; $driver->get('https://www.google.com'); print $driver->get_title() . "\n"; # Google $driver->shutdown_binary();
ドライバが何も表示しなかったんで不安だったけど、ちゃんと動いた。よかった。
なお、Firefox の場合は終了時にポートの情報などが表示される。
Killing Driver PID 46947 listening on port 49580...
Yahoo.co.jp からニュースを持ってくる
これの Selenium 版をやってみます
#!/usr/bin/env perl use strict; use warnings; use Selenium::Chrome; # utf8 で出力する binmode STDOUT, ":utf8"; my $driver = Selenium::Chrome->new; # Yahooのトップページに移動する $driver->get('https://www.yahoo.co.jp/'); # ニュース一覧のDOMを特定する my $news = $driver->find_element_by_xpath( '/html/body/div/div/main/div[2]/div[1]/article/div/section/div/div[1]/ul' ); # ニュース一覧のDOMから、個別のニュースの要素を取得する my $articles = $news->children( './li//h1/span', 'xpath' ); # 1記事ずつタイトルを取得する for my $article ( @{$articles} ) { print $article->get_text() . "\n"; } # ニュース一覧のDOMから、個別のニュースのURLを取得する my $aTags = $news->children( './li//a[@href]', 'xpath' ); # 1記事ずつURLを取得する for my $aTag ( @{$aTags} ) { print $aTag->get_attribute('href') . "\n"; } sleep 3; # WebDriver を終了する $driver->shutdown_binary();
給付金委託 元電通社員に委任 激しい雨 東京や埼玉竜巻注意 習主席の国賓来日 年内見送り 緊急宣言 再指定に消極的な訳 加首相 デモ参加し片膝をつく 夜は高架下 困窮の留学生帰国 ヤクルト スアレスの陰性発表 鬼滅に続く?若手集うジャンプ https://news.yahoo.co.jp/pickup/6361779 https://news.yahoo.co.jp/pickup/6361787 https://news.yahoo.co.jp/pickup/6361782 https://news.yahoo.co.jp/pickup/6361778 https://news.yahoo.co.jp/pickup/6361780 https://news.yahoo.co.jp/pickup/6361781 https://news.yahoo.co.jp/pickup/6361783 https://news.yahoo.co.jp/pickup/6361762
うまく取れたんだけど、結構時間がかかる・・・20 〜 30 秒くらい。
あと、タイトルとURLはもう少しスマートな取り方があると思う・・・
Twitter にログインしてみる
さて、本命。
$username_or_email
と $password
を変更して実行
#!/usr/bin/env perl use strict; use warnings; use utf8; use Selenium::Chrome; my $username_or_email = 'hogehoge'; my $password = 'fugafuga'; my $driver = Selenium::Chrome->new; # Twitter のログイン画面に移動する $driver->get('https://www.twitter.com/login'); # name 属性でユーザー名の入力欄の要素を特定する my $username = $driver->find_element_by_name('session[username_or_email]'); # 特定した入力欄にユーザー名を入力する $username->send_keys($username_or_email); sleep 1; # 1秒待つ # パスワードも、ユーザー名と同様に処理 my $psw = $driver->find_element_by_name('session[password]'); $psw->send_keys($password); sleep 1; # 1秒待つ # ログインボタン には name 属性がないので、div タグと role 属性で要素を特定する my $button = $driver->find_element('//div[@role="button"]'); # ボタンをクリックする $button->click(); sleep 5; # 5秒待つ # WebDriver を終了する。ブラウザも閉じられる。 $driver->shutdown_binary();
うちの環境ではうまくいきました。
これで、あとはソースを解析することができればー、なのですが本日はここまで。
補足
Twitter側にはこのような通知が出ます。
あまりやりすぎると「不正アクセスされてる!」って判断されちゃうかな。
参考にしたサイト
Perl の情報は少ないんですが、他の言語のリファレンスが大変参考になりました。