C# - SelenumでWebクローリング、スクレイピング

ブラウザの操作を自動化する、(多分有名だろうけど)Seleniumというものがあります。

Webのクローリングやスクレイピングをする最も基本的なやり方は、
プログラムからHTTPリクエストを投げ、帰ってきたレスポンスを解析することだと思う。
だが、これだとjavascriptで非同期に更新されるようなページではうまくいかないことが多い。
そこでSeleniumを使う。
そうすると実際にブラウザに表示される内容を取得できるので、
手動でブラウザを操作する手順をそのまま書き起こすだけでクローリングやスクレイピングがうまくいく。
最近は、ヘッドレスといってウインドウを表示しない動作モードも普通に搭載されているので、実行時にも鬱陶しくない。便利。

準備

ブラウザとそのブラウザをSeleniumから操作する用のドライバ(WebDriver)が必要です。
大体どのブラウザでも対応しているはずなので、こだわりがなければシェアの高いものが良い。
シェアが高いほうがどのサイトでも正しく動作するだろうからね。
ということでChromeを使う。(Chrome用のドライバはこれ)

ライブラリ

使用言語用のライブラリが必要(あたりまえ)。
メジャーな言語は大体対応している。
C# + Chrome用のは以下

  • Selenium.WebDriver
  • Selenium.Support

Supportは用途によっては不要かもしれない。

実装例

あとは、WebDriverおよびAPIのドキュメントを読みながら粛々とやるのみ。

using System;

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace SeleniumDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // タイムアウト
            Int32 timeout = 30;
            // アクセスするWebサイト
            string url = @"https://siteurl.com/";
            // ドライバが存在するディレクトリ
            string pathToDriver = @"/path/to/driver";
            // ブラウザの起動オプション. Chromeの場合はこれでウインドウがでなくなる。
            string[] execParams = { @"--headless" };

            // 実行パラメータの設定
            var options = new ChromeOptions();
            options.AddArguments(execParams);

            // ドライバオブジェクト経由で操作する
            using (IWebDriver driver = new ChromeDriver(pathToDriver, options))
            {
                // 暗黙的タイムアウトを設定
                driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(timeout);
                // URLバーへURLを入力する
                driver.Navigate().GoToUrl(url);
                // 該当の要素を検索
                IWebElement element = driver.FindElement(By.XPath(@"XPath"));
                // 見つかったらクリック
                element.Click();
            }
        }
    }
}

少し解説

ドライバオブジェクトについて

ドライバオブジェクト生成時にWebDriverソフトウェアと起動オプションを指定する。
WebDriverは実行ファイルではなく、実行ファイルのあるディレクトリを指定することに注意。

あたりまえだけど、IWebDriverとせずにChromeDriver型としたほうが、より細かな制御ができるようになる。

ウェイトについて

非同期処理のあるページだと、ロード完了後、要素が現れるまでに時間がかかることがある。
ウェイトを指定して、それを待つようにおくと処理が速すぎて失敗ということがなくなる。
必ず一定時間待つわけではない(要素が見つかればすぐ帰ってくる)ので、気持ち長めが良いかもしれない。

一律に指定する暗黙的ウェイトと都度設定する明示的ウェイトがある(参照)
明示的ウェイトのとき、Supportパッケージが要る。

ブラウザおよびページ内操作について

Navigateがブラウザのナビゲーションバーを表しているようで、ほかに進む、戻る、更新とかもできる。
FindElementで検索条件に合致する最初の要素を取得。s付き(FindElements)ですべて取得。
IWebElementも同メソッドもっているので、順次選択ということもやりやすい。

要素に対して、クリック(Click)、テキスト入力(SendKeys)、フォーム送信(Submit)がIWebElementから簡単に実行できる。
より複雑な操作(ドラッグアンドドロップとか)がしたい場合は、OpenQA.Selenium.Interactions.Actions で行う。

要素の検索について

検索対象の要素は実際にブラウザを手で操作して調べる。
Chromeの場合は、ページ内で右クリック->検証 とすると表示結果の内容を確認できるので、そこから拾ってくる。
対象要素のXPathとCSSセレクタを取得できるので、検索条件にはそのどちらかで指定するのが楽。

別の得意なやり方があるのであれば、ページソースを取得できる(driver.PageSource)のでFindElementせずとも良い。

その他

ほとんどのことをブラウザがやってくれるので、
深い知識も複雑な操作もあんまり要らなくなって簡単になったなぁと思いました。

ちょっと複雑なことをやろうとすると一気にめんどくさくなるのが常なんだけどね。

以上。


See also