Rustでスクレイピング入門|reqwest・scraper・headless_chromeの実践コード付き
Rustでスクレイピングを行いたいものの、どのクレートを選べばよいのか、Pythonとの違いは何か、法的に問題ないのかといった疑問を持つ方は多いのではないでしょうか。Rustはメモリ安全性と実行速度を両立できる言語であり、大量ページの収集や長時間稼働するクローラーの構築にも適しています。 この記事ではRustのHTTPクライアント「reqwest」、HTMLパーサー「scraper」、ヘッドレスブラウザ操作「headless_chrome」を軸に、実際に動作するコードを示しながらスクレイピングの方法を解説します。 Rustがスクレイピングに向いている理由 スクレイピングにはPython(BeautifulSoup / Scrapy)が広く使われていますが、Rustには以下のような強みがあります。 観点 Rust Python 実行速度 C/C++に匹敵するネイティブコンパイル インタプリタ実行のため低速 メモリ効率 所有権システムによりGC不要 GCに依存、大規模処理でメモリ消費大 並行処理 async/awaitとtokioで安全な非同期処理 GILの制約がありマルチスレッドに制限 バイナリ配布 シングルバイナリで依存なし Pythonランタイムと仮想環境が必要 型安全性 コンパイル時に型エラーを検出 実行時エラーが起きやすい 特に数万ページ規模のクロールや、サーバー上で常時稼働させるバッチ処理では、Rustの省メモリ・高スループットが大きな利点です。 開発環境の準備 Rustをまだインストールしていない場合は、公式のrustupを使います。 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh プロジェクトの作成は以下のとおりです。 cargo new rust-scraper-demo cd rust-scraper-demo 静的HTMLページのスクレイピング 静的なHTMLを取得して解析する基本パターンです。HTTPリクエストにはreqwest(v0.13)、HTML解析にはscraper(v0.25)を使います。 Cargo.tomlの設定 [package] name = "rust-scraper-demo" version = "0.1.0" edition = "2021" [dependencies] reqwest = { version = "0.13", features = ["blocking"] } scraper = "0.25" HTMLを取得してタイトルを抽出する reqwest::blockingを使った同期処理の例です。スクリプトやCLIツールなど、非同期が不要な場面で手軽に使えます。 use reqwest::blocking::get; use scraper::{Html, Selector}; fn main() -> Result<(), Box<dyn std::error::Error>> { let url = "https://www.rust-lang.org/"; let response = get(url)?; let body = response.text()?; let document = Html::parse_document(&body); let selector = Selector::parse("title").unwrap(); for element in document.select(&selector) { let title = element.text().collect::<String>(); println!("タイトル: {}", title); } Ok(()) } Selector::parseにはCSSセレクタを渡します。div.class-nameやa[href]など、ブラウザのDevToolsで確認したセレクタをそのまま使えるのがscraperの利点です。 ...