エミ眠太の自由帳
 エミ眠太の自由帳
    
 
 やってみた      2024-12-08      

Webページの情報を自動取得する。

Language:
 Python HTML
Framework/Library:
 BeautifulSoup Selenium Scrapy
Technology:
 クローラ Webスクレイピング
Platform/Tool:

記事一覧へ

目次


はじめに

通知機能が搭載されていないWebページについて、毎日手動でアクセスして情報を取得するのが面倒なので自動化してみました。

スクレイピング(Webスクレイピング)について

Webスクレイピングとは主にWebサイト上に掲載されている情報を取得したのち、必要な部分のみ抽出(+保存)する作業を指します。例えば任意のページのとある情報(商品情報・天気予報・Web記事)の特定部分を抽出したい場合に利用できます。 また、似た言葉にクローリングというものがありますがこちらはWebサイト全体を網羅的に巡回しデータを収集することを指します。例えばこのクローリングという技術はGoogleの検索インデックスの構築に利用されていますね。

Webスクレイピング実施時の注意点

ここまで聞くと「便利やん、使い倒したろ」となるかも知れませんが、チョット待って!!! 賢い方ならお気づきかもしれませんが、この技術、Webサイト運営者の立場としては少々厄介モノだったりするんですわ。個人情報に関わる情報は抽出禁止はもちろんのこと、著作権侵害の恐れもあり、短時間で大量のリクエストを実施することになるのでサーバーへ多少なりとも負荷をかけることになります。そのため、Webスクレイピングを実施する前には必ず事前に当該Webサイトを確認してください。robots.txtの内容や利用規約ページの確認が必要ですが、利用規約内には「スクレイピング」と限定した書き方ではなく、「ロボット等によるデータ抽出・収集」といった書き方がされていることが多いです。スクレイピングはもちろんそれに含まれるため、このような記載がある場合にはスクレイピングはしないように注意してください。本ブログの利用に起因するいかなる損害についても、当方は一切の責任を負いかねます。なお本ブログにおいても利用規約内に同様の記載をしておりますので、スクレイピングはくれぐれもお控えください。とはいえ大変便利な技術ですので早速使い方を紹介しますね。今回は私のブログでWebスクレイピングを実施してみました。自分自身のページにおけるWebスクレイピングであれば誰が文句を言えようか(以下略)。

Pythonのスクレイピングライブラリ比較

Webスクレイピングについての概要は前述の通りですが、どうやって実施をしましょうか?まあお決まりの話ですが、Pythonなので便利なライブラリがいくつもあるんですよね。まずはいくつか代表的なものを紹介します。

Requests & BeautifulSoup

BeautifulSoup、美味しそうですよね。こちらはHTML・XMLの解析と特定の情報の抽出に特化しており、通常Requestsライブラリと一緒に使われます。DOMツリー構造を使って操作が可能なので静的ページにはもってこいのライブラリです。初学者向けで最も学習コストが低いとも言われていますが、標準のhtml.parserだけでなくC言語で書かれたlxmlパーサーと組み合わせることもできるため、比較的高速な処理が可能で、簡単な処理には重宝されています。一方でHTMLをそのまま解析するだけなので、ブラウザ側(=JavaScript)でレンダリングされるSPAのようなWebサイトや、lazy laodが組み込まれた動的ページの解析には不向きです。

Scrapy

こちらは膨大なデータの処理に向いており、スクレイピングとクローリングの両方が利用可能なフレームワークです。ライブラリではなくフレームワークであることがポイントで、他のライブラリと比較して幅広く機能が提供されています。また並行処理も可能であるため非常に高速な処理が期待できます。一方で、BeautifulSoupと同様に動的ページの解析には不向きです。

Selenium

Seleniumは既出の2ライブラリとは少し毛色の違うライブラリです。一番の特徴はブラウザをどのように操作するかを指示できることにより、静的ページだけでなく動的ページからの抽出が可能であることです。これにより、例えばJavaScriptによるページの読み込みが完了してから操作を実行できたり、入力フォームへのテキスト入力・ボタン押下・スクロール動作ができたりと、さながら実際にページを手動で操作するような感覚です。RPAっぽいとも言えるかもしれませんね。ここまで褒めちぎりましたが、反対に一番のネックは処理速度です。クライアント上でブラウザを実際に起動しているので、手動よりは格段に速いですがそれはもう時間がかかります。

比較表

ここまでの情報を以下の通りまとめてみました。

BeautifulSoup Scrapy Selenium
HP URL URL URL
特徴 簡単!速い! 大規模な処理が得意 動的ページの処理が可能
静的コンテンツの処理 ✔︎ ✔︎ ✔︎
動的コンテンツの処理 - - (一部可能) ✔︎
処理スピード
学習コスト

Webスクレイピング、実際にやってみた。

RequestsとBeautifulSoupを使ったWebスクレイピング

まずは一番簡単なこちらから。解析するページは以前執筆したPythonでGoogle Driveにファイルをアップロード・ダウンロードする。という記事にします。ここからmetaタグとh2タグを取得してみましょう。 まずはbeautifulsoup4タグとrequestsをインストールします。

pip install beautifulsoup4 requests

続いて以下の通りコードを書いていきましょう。

「一行解説」を見る
  1. (l.1-2) ライブラリをインポートします。
  2. (l.4) 対象のWebページのURLを用意します。
  3. (l.6) requests.get()メソッドを使って4行目のURLに対してHTTP GETリクエストを送信し、HTMLデータを取得します。結果をresponseに格納します。
  4. (l.7) 6行目のresponseを解析するためにDOMツリー構造に変換します。そのために第一引数にはresponsex.textを、第二引数にはhtml.parserをセットしてBeautifulSoup()メソッドを実行します。responseについて.textという属性をつけたのは、BeautifulSoupが解析可能なテキスト形式に変換する必要があるからです。また、第二引数にhtml.parserをセットしたのは、あくまでもBeautifulSoupに自体にはパース済みのHTML・XMLを操作する機能しかなく、パース自体はパーサーの役割となるからです。なお、responseについては、テキスト属性の他にも、ステータスコードを取得できる.status_code属性やJSONデータを取得できる.json属性があります。
  5. (l.9) DOMツリー構造への変換が完了したので、ここからはBeautifulSoup()メソッド内のメソッドを使って抽出したい要素を探索します。まずはfind()メソッドを使用して、HTML内の特定のmetaタグを検索します。ここで第二引数に{'name': 'description'}を設定することで、name属性がdescriptionとなっているページ名が登録されているmetaタグのみに限定することができます。これをmeta_descriptionに格納します。
  6. (l.10) 9行目のmeta_descriptionに格納されたmetaタグについて、'content'属性の値を.get()メソッドで抽出します。この'content'属性内の値こそが今回欲しかった値です。
  7. (l.12) 続いて9行目と同様に、今度はブログ記事内の各章の見出しであるh2タグを取得します。こちらは複数存在するため、.find_all()メソッドで該当するh2タグをすべて検索します。
  8. (l.13-14) h2タグについて、そのまま出力するとタグごと出力されてしまうので、今回も.text属性を利用してテキスト部分のみ抽出し出力します。
こんな具合にで簡単に取得できることが分かりましたね。処理時間も一瞬でしたね。

ちなみにこちらのブログでは記事の検索もちょっとだけ可能なのですが、検索の実行+結果からの抽出はBeautifulSoupでは難しいんですよね。。これを実現するのが、そう、Seleniumなんです。

Seleniumを使ったWebスクレイピング実施

ということでSeleniumを使ったスクレイピングについては、検索キーワード入力→検索の実施→検索結果の出力という手順を踏みたいと思います。まずはライブラリをインストールします。

pip install selenium

続いて以下の通りコードを書いていきましょう。

「一行解説」を見る
  1. (l.1-3) Seleniumとして利用するコンポーネントをインストールしていきます。webdriverとはブラウザを操作するために必要なコンポーネントです。selenium.webdriver.common.keys.Keysはキーボード操作を受け付けるためのモジュール、selenium.webdriver.common.by.ByはHTMLの要素を検索する際に方法を指定するためのモジュールです。
  2. (l.4) クライアントの処理に時間がかかることを想定して、timeもインポートします。
  3. (l.6-8) webdriver.Chrome()メソッドを利用してSeleniumのChrome WebDriverを起動します。その後URLを指定して.get()メソッドでページを開きます。
  4. (l.10) Seleniumはクライアントでブラウザを利用して実行されるのでエラー発生を想定した処理を記述するためエラーハンドリングを記述します。
  5. (l.11) 続いて検索キーワードを入力するためのフィールドを検索します。第一引数にはBy.CSS_SELECTORとすることでCSSセレクタを使うことを指定、第二引数にはinputタグのtype属性がtextであることを指定して、find_element()メソッドでフィールドを検索します。今回はCSSセレクタを指定する方法を取りましたが、TAG_NAMEIDも利用できます。
  6. (l.12-14) 検索キーワードを指定します。今回はGoogleとしました。それをsend_keys()メソッドに渡すことでフィールドへの入力を実行し、send_keys(Keys.RETURN)とすることでEnterキーを押下しました。これにより検索の実行が完了しました。
  7. (l.17) time.sleep(3)として、検索結果表示までの時間を確保します。
  8. (l.19-20) 続いて、検索結果の要素数をカウントします。このブログでは検索結果は長方形のdivタグの箱で表示されるようにしていますが、クラス名はいずれもArticleItem_eachArticleを含むことがわかっています。そのため、部分一致を表す*=でクラス名を指定してfind_element()メソッドの第二引数に設定します。検索結果はelements内にリスト形式で入っているのでlen()メソッドで個数を確認します。
  9. (l.23) エラーハンドリングの例外処理としてExceptを記述します。
  10. (l.26) 処理が完了したら、.quit()でブラウザを切ります。
というわけで検索キーワード入力→検索の実施→検索結果の出力が完了しました。このような動作はBeautifulSoupでは実施できないため、Seleniumの活用によりWebスクレイピングの幅を広げることができたのではないでしょうか?ただ、この程度の処理にもかかわらず約10秒要したため、使い所の見極めは大事そうです。

まとめ

スクレイピングについて解説してきましたが、どのライブラリを使うにしろ一番のネックはWebページの構造・デザイン自体が変更されるリスクです。海外の有名なSaaSアプリ等は単なる機能追加だけでなくデザインのアップデートも頻繁になされるため、その度にコードを修正するのは骨が折れると思います。提供されているのであればWebAPI経由の方が、抜け漏れの少ない構造的な情報を取得可能なのでそちらをおすすめしたいです。


記事をシェアする


関連する記事

よろしければこちらの記事も参考にしてみてください。

Loading...




記事一覧へ