【2024年版】PythonとBeautifulSoupを使ったWebスクレイピング実践講座
はじめに
現代は、まさに「データの時代」です。ビジネスの意思決定から学術研究、個人の趣味に至るまで、あらゆる場面でデータがその価値を発揮しています。そして、そのデータの宝庫こそが、私たちが日常的に利用しているWorld Wide Webです。Web上には、ニュース記事、商品情報、株価、気象データ、SNSの投稿など、無限とも思える情報が溢れています。
これらの情報を手動で一つ一つコピー&ペーストして収集するのは、非常に時間と労力がかかる非効率な作業です。もし、このプロセスを自動化できたらどうでしょうか? それを実現するのが「Webスクレイピング」という技術です。
Webスクレイピングとは、Webサイトから特定の情報を自動的に抽出し、扱いやすい形に加工するコンピュータソフトウェア技術の総称です。この技術を身につけることで、以下のようなことが可能になります。
- 市場調査: 競合他社の製品価格やサービス内容を定期的に収集し、自社の戦略立案に役立てる。
- 価格比較サイトの構築: 複数のECサイトから特定の商品価格を収集し、最安値をユーザーに提示する。
- 学術研究: 特定のキーワードに関連する論文やニュース記事を大量に収集し、テキストマイニングやトレンド分析を行う。
- AI・機械学習のデータセット作成: 画像認識モデルのための画像データや、自然言語処理モデルのためのテキストデータをWebから収集する。
- 個人の興味: 好きなアーティストの最新情報や、特定の趣味に関するブログ記事を自動で集めて通知する。
本講座では、プログラミング言語Pythonと、その強力なライブラリであるRequestsおよびBeautifulSoupを用いて、Webスクレイピングの基礎から実践までを体系的に学びます。
本講座の目的と対象者
目的:
本講座の最終的なゴールは、あなたがPythonとBeautifulSoupを使いこなし、基本的なWebサイトから実践的なWebサイトまで、必要な情報を自信を持って自動収集できるようになることです。単にコードを書き写すだけでなく、「なぜそうするのか」という原理を理解し、未知のサイトにも応用できる問題解決能力を養うことを目指します。
対象者:
* プログラミング初心者の方: Pythonの基本的な文法(変数、データ型、ループ、条件分岐、関数など)を学習済み、または学習中の方を想定しています。
* データ分析やWebマーケティングに関わる方: 業務でデータ収集が必要であり、その効率化を図りたいと考えている方。
* 手作業でのデータ収集に限界を感じている方: ルーチンワークを自動化し、より創造的な業務に時間を割きたい方。
* 新しい技術スキルを身につけたい学生や社会人の方: データサイエンスやAI分野への第一歩として、実践的なスキルを習得したい方。
本講座で学ぶことの概要
この講座は、以下のステップで進められます。
- Webスクレイピングの基礎知識: スクレイピングがどのような仕組みで動いているのか、その裏側にあるHTTP通信やHTMLの構造について学びます。
- 開発環境の準備: Pythonのインストールから、スクレイピングに必要なライブラリ(Requests, BeautifulSoup)のセットアップまでを丁寧に行います。
- RequestsとBeautifulSoupの基本: 実際にPythonコードを書きながら、Webページの内容を取得し、その中から情報を探し出す基本操作をマスターします。
- CSSセレクタを使った高度なデータ抽出: より複雑なHTML構造からでも、狙った情報をピンポイントで抜き出すための強力なテクニック「CSSセレクタ」を学びます。
- 応用テクニックと実践的プロジェクト: 複数ページにわたる情報の収集(ページネーション)、収集したデータのファイル保存(CSV, JSON)、そして現代のWebで主流となりつつある動的サイトへの対応についても触れます。
- スクレイピングにおける倫理と法律: 忘れてはならない最も重要なトピックです。安全かつ合法的にスクレイピングを行うためのルールとマナーを学びます。
さあ、準備はよろしいでしょうか? Webという広大な情報の海へ、データ探索の冒険に出かけましょう!
第1章: Webスクレイピングの基礎知識
コードを書き始める前に、まずはWebスクレイピングがどのような原理で成り立っているのかを理解することが不可欠です。この章では、その根幹をなす技術的な背景と、必ず守るべきルールについて学びます。
1. Webスクレイピングの仕組み
あなたがブラウザでWebサイトを見るとき、裏側では何が起きているのでしょうか? 実は、スクレイピングのプロセスは、このブラウザの動作と非常によく似ています。
-
ステップ1: HTTPリクエスト (情報の要求)
- ユーザーがブラウザのアドレスバーにURLを入力してEnterキーを押すと、ブラウザは指定されたURLのサーバーに対して「このページの情報をください」というリクエスト (Request) を送信します。
- Pythonのスクレイピングプログラムも同様に、対象のWebサーバーに対してHTTPリクエストを送信します。この役割を担うのがRequestsライブラリです。
-
ステップ2: HTMLレスポンス (情報の受信)
- リクエストを受け取ったWebサーバーは、要求されたWebページの情報、主にHTML (HyperText Markup Language) ファイルをブラウザに送り返します。これをレスポンス (Response) と呼びます。
- Pythonプログラムも、このHTMLデータを文字列として受け取ります。
-
ステップ3: HTMLパース (情報の解析)
- ブラウザは、受け取ったHTMLを解釈(パース)し、画面上に美しくレンダリング(描画)して表示します。
- 一方、Pythonプログラムは、受け取ったHTMLの文字列をそのままでは扱いにくいため、プログラムで操作しやすいデータ構造(ツリー構造)に変換します。このパース処理を行うのがBeautifulSoupライブラリの役割です。
-
ステップ4: データ抽出 (情報の抜き出し)
- ブラウザを通して人間は視覚的に「この部分がタイトルだ」「ここが価格だ」と判断します。
- プログラムは、パースされたHTMLのツリー構造の中から、あらかじめ指定された目印(タグや属性)を頼りに、目的のデータ(テキストやURLなど)を正確に抜き出します。
この4つのステップが、Webスクレイピングの基本的な流れです。
2. HTMLとCSSの基本
スクレイピングを成功させる鍵は、「ステップ4: データ抽出」で、いかに正確に目的のデータの場所をプログラムに伝えられるかにかかっています。そのためには、Webページの設計図であるHTMLと、その見た目を定義するCSSの基本的な知識が必須です。
HTML (HyperText Markup Language)
HTMLは、Webページの構造を定義するための言語です。文章の見出し、段落、リスト、リンク、画像などが、それぞれ特定のタグを使ってマークアップ(意味付け)されています。
“`html
“`
- タグ:
<p>
,<a>
,<h1>
のように<
と>
で囲まれたもの。 - 要素: 開始タグ (
<p>
)、内容(テキストなど)、終了タグ (</p>
) から構成されます。 - 属性: タグに追加情報を提供します。
<a>
タグのhref
属性はリンク先のURLを、<img>
タグのsrc
属性は画像の場所を示します。 class
属性とid
属性: 要素を特定するための重要な目印です。id
はページ内で一意(ユニーク)でなければならず、class
は複数の要素に同じ名前を付けることができます。これらはスクレイピングで頻繁に利用します。
CSS (Cascading Style Sheets) と CSSセレクタ
CSSは、HTMLで定義された構造に見た目(スタイル)を適用するための言語です。例えば、「h1
タグの文字を赤くする」「class="item"
の背景を灰色にする」といった指定を行います。
スクレイピングにおいてCSSで最も重要な概念は、スタイルを適用する対象を指定するための記法である「CSSセレクタ」です。このCSSセレクタを使うことで、HTML文書内の特定の要素を非常に柔軟かつ強力に指定できます。
- タグ名セレクタ:
p
(すべての<p>
要素を選択) - クラスセレクタ:
.container
(class="container"
を持つ要素を選択) - IDセレクタ:
#main-content
(id="main-content"
を持つ要素を選択) - 子孫セレクタ:
div p
(<div>
要素の中にあるすべての子孫の<p>
要素を選択) - 子セレクタ:
ul > li
(<ul>
要素の直下にある<li>
要素のみを選択)
このCSSセレクタは、後の章でデータを抽出するための強力な武器となります。
3. スクレイピングの倫理と法律
技術的な話と同様に、あるいはそれ以上に重要なのが、スクレイピングを行う上での倫理観と法律遵守です。無思慮なスクレイピングは、サイト運営者に多大な迷惑をかけるだけでなく、法的なトラブルに発展する可能性もあります。以下の点を必ず守りましょう。
- サイトの利用規約を確認する: 多くのWebサイトでは、利用規約にスクレイピングやクローリングに関する記述があります。明確に禁止されている場合は、そのサイトのスクレイピングは行うべきではありません。
robots.txt
を確認する:robots.txt
は、サイトのルートディレクトリ(例:https://example.com/robots.txt
)に置かれているファイルで、検索エンジンのクローラーなどに対して、どのページをクロールして良いか/悪いかを伝えるためのものです。Disallow:
と書かれているディレクトリへのアクセスは、プログラムによる自動アクセスを想定していない可能性が高いため、原則として避けましょう。これは法的な強制力はありませんが、サイト運営者の意思を尊重する重要なマナーです。-
サーバーに過度な負荷をかけない: プログラムは人間と違って、超高速で連続的にリクエストを送信できます。しかし、これは相手のサーバーに大きな負荷をかけ、最悪の場合サーバーダウンを引き起こす可能性があります(DoS攻撃とみなされることも)。リクエストとリクエストの間には、
time.sleep()
を使って数秒間の待機時間を設けるのが基本です。
“`python
import timefor i in range(10):
# 処理
print(f”{i+1}回目のリクエスト”)
time.sleep(2) # 2秒待機
“`
4. 著作権を尊重する: スクレイピングで収集したデータ(文章、画像、動画など)には著作権が存在します。収集したデータを無断で複製して公開したり、販売したりする行為は著作権侵害にあたります。私的利用の範囲を逸脱しないよう、データの取り扱いには細心の注意を払いましょう。
5. 個人情報を不当に収集しない: 個人情報保護法により、個人情報の取り扱いには厳しい規制があります。氏名、住所、電話番号などの個人情報を本人の同意なく収集・利用することは絶対に避けてください。ログインが必要なサイトから他人の情報を取得するような行為は厳禁です。
「責任あるスクレイピング」を常に心がけ、技術を健全な目的のために利用しましょう。
第2章: 開発環境の準備
それでは、いよいよ実践に向けて開発環境を整えていきましょう。ここでは、Pythonのインストールから、スクレイピングに必須のライブラリをセットアップするまでの手順を解説します。
1. Pythonのインストール
すでにPythonがインストールされている場合は、このセクションはスキップしても構いません。まだの方は、以下の手順でインストールしましょう。
- 公式サイトにアクセス: Pythonの公式サイト ( https://www.python.org/ ) にアクセスします。
- ダウンロード: トップページの「Downloads」メニューから、お使いのOS(Windows, macOS)に合った最新の安定版インストーラをダウンロードします。2024年現在、Python 3.x系が主流です。
- インストール (Windowsの場合):
- ダウンロードしたインストーラを実行します。
- 非常に重要: インストーラ起動時の最初の画面で、「Add Python X.X to PATH」(または「Add python.exe to Path」)というチェックボックスに必ずチェックを入れてください。これにより、コマンドプロンプトやPowerShellから簡単にPythonを呼び出せるようになります。
- 「Install Now」をクリックしてインストールを進めます。
- インストール (macOSの場合):
- ダウンロードした
.pkg
ファイルを開き、画面の指示に従ってインストールを進めます。macOSの場合は通常、PATH設定は自動的に行われます。
- ダウンロードした
インストールが完了したら、ターミナル(WindowsではコマンドプロンプトまたはPowerShell、macOSではターミナル.app)を開き、以下のコマンドを実行してバージョンが表示されれば成功です。
“`bash
python –version
または
python3 –version
“`
2. 仮想環境の構築
プロジェクトごとにライブラリのバージョンを独立させるために、仮想環境を構築することをお勧めします。これにより、「プロジェクトAではライブラリのバージョン1.0が必要だけど、プロジェクトBでは2.0が必要」といった依存関係のコンフリクトを防ぐことができます。
- プロジェクト用フォルダの作成: まず、スクレイピングのプロジェクトファイルを保存するフォルダを作成し、ターミナルでそのフォルダに移動します。
bash
mkdir scraping-project
cd scraping-project - 仮想環境の作成:
venv
という標準モジュールを使って、myenv
という名前の仮想環境を作成します。
bash
python -m venv myenv
これにより、scraping-project
フォルダ内にmyenv
というサブフォルダが作成されます。 -
仮想環境のアクティベート: 作成した仮想環境を有効化(アクティベート)します。
- Windows (コマンドプロンプト):
bash
myenv\Scripts\activate - Windows (PowerShell):
bash
myenv\Scripts\Activate.ps1 - macOS / Linux:
bash
source myenv/bin/activate
アクティベートに成功すると、ターミナルのプロンプトの先頭に(myenv)
と表示されます。これ以降、pip
コマンドでインストールされるライブラリは、この仮想環境内にのみ保存されます。
- Windows (コマンドプロンプト):
-
仮想環境のディアクティベート: 作業が終わって仮想環境を無効化したい場合は、以下のコマンドを実行します。
bash
deactivate
3. 必要なライブラリのインストール
仮想環境をアクティベートした状態で、スクレイピングに必要なライブラリをpip
コマンドでインストールします。
- Requests: HTTPリクエストを簡単に行うためのライブラリです。
bash
pip install requests - BeautifulSoup4: HTMLやXMLをパースするためのライブラリです。
bash
pip install beautifulsoup4 - lxml: 非常に高速で高機能なHTML/XMLパーサーです。BeautifulSoupと組み合わせて使うことで、パフォーマンスが向上します。
bash
pip install lxml
インストールが完了したら、pip list
コマンドでインストールされたライブラリの一覧を確認できます。
4. 開発ツールの紹介
効率的にスクレイピングを行うために、以下のツールに慣れておきましょう。
- テキストエディタ / IDE:
- Visual Studio Code (VSCode): 無料で高機能、豊富な拡張機能が魅力。Python開発者に非常に人気があります。
- PyCharm: Python開発に特化したIDE。無料のCommunity版と有料のProfessional版があります。
- ブラウザの開発者ツール:
スクレイピングを行う上で最も重要な相棒です。Google ChromeやFirefoxなどのモダンブラウザに標準で搭載されています。- 開き方: Webページ上で右クリックし、「検証」または「調査」を選択するか、
F12
キー(macOSではCmd+Opt+I
)を押します。 - Elements (要素) タブ: 表示されているWebページのHTMLソースコードをツリー形式で確認できます。特定の要素にマウスカーソルを合わせると、ページ上の対応する部分がハイライトされ、目的の情報のHTMLタグや
class
,id
を特定するのに非常に役立ちます。 - Network (ネットワーク) タブ: ページ読み込み時にどのようなHTTPリクエスト/レスポンスが送受信されているかを確認できます。後述する動的サイトの解析に不可欠です。
- 開き方: Webページ上で右クリックし、「検証」または「調査」を選択するか、
これで開発環境の準備は万端です。次の章から、いよいよPythonコードを書いていきましょう!
第3章: RequestsとBeautifulSoupの基本
この章では、第2章でインストールしたrequests
とbeautifulsoup4
ライブラリを実際に使い、Webページから情報を取得する基本的な流れを学びます。
1. RequestsライブラリでWebページを取得する
最初のステップは、目的のWebページのHTMLコンテンツをプログラムで取得することです。これにはrequests
ライブラリのget()
関数を使います。
基本的な使い方
“`python
import requests
取得したいWebページのURL
url = ‘https://example.com/’
HTTP GETリクエストを送信
response = requests.get(url)
レスポンスオブジェクトの情報を確認
print(f”ステータスコード: {response.status_code}”)
print(f”HTMLコンテンツ:\n{response.text}”) # 長いので最初はコメントアウト
“`
requests.get(url)
: 指定したurl
に対してGETリクエストを送信し、サーバーからのレスポンスをresponse
オブジェクトとして返します。response.status_code
: レスポンスのHTTPステータスコードを返します。200
は「成功」を意味します。404
は「Not Found」、403
は「Forbidden」など、200
以外の場合はアクセスに問題があることを示します。response.text
: レスポンスのボディ部分をテキスト(文字列)として返します。これが私たちが欲しかったHTMLコンテンツです。
文字化け対策
サイトによっては、response.text
で取得したHTMLが文字化けすることがあります。これは、requests
が自動で判定した文字コードと、実際のサイトの文字コードが異なる場合に発生します。
requests
には、コンテンツの内容から文字コードを推測するapparent_encoding
という便利なプロパティがあります。文字化けが発生した場合は、以下のようにエンコーディングを明示的に設定することで解決できることが多いです。
“`python
response.textの前にエンコーディングを設定する
response.encoding = response.apparent_encoding
html_content = response.text
“`
User-Agentの設定
Webサーバーは、リクエスト元の情報(User-Agent)を見て、アクセスがブラウザからかプログラムからかを判断することがあります。requests
のデフォルトのUser-Agentはプログラムであることが明らかなため、サイトによってはアクセスをブロックされることがあります。
そこで、ブラウザからのアクセスであるかのように見せかけるために、リクエストヘッダにUser-Agent情報を追加するのが一般的です。
“`python
import requests
url = ‘取得したいページのURL’
一般的なブラウザのUser-Agent文字列
headers = {
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36’
}
headers引数に辞書を渡す
response = requests.get(url, headers=headers)
if response.status_code == 200:
print(“正常に取得できました。”)
else:
print(f”エラーが発生しました: {response.status_code}”)
“`
2. BeautifulSoupでHTMLをパースする
HTMLコンテンツを取得できたら、次はその中から目的の情報を探し出すために、BeautifulSoup
を使って解析(パース)します。
BeautifulSoupオブジェクトの作成
“`python
from bs4 import BeautifulSoup
… requestsでresponseを取得した後 …
BeautifulSoupオブジェクトを作成
第1引数: パースしたいHTMLコンテンツ
第2引数: 使用するパーサー(’lxml’が高速でおすすめ)
soup = BeautifulSoup(response.text, ‘lxml’)
整形されたHTMLを出力して確認
print(soup.prettify())
``
soup`オブジェクトは、元のHTMLを解析し、プログラムで簡単にアクセスできるツリー構造に変換したものです。
基本的な要素の検索
BeautifulSoupには、HTMLツリーの中から要素を検索するための便利なメソッドが用意されています。
find('タグ名', ...)
: 条件に一致する最初の1つの要素(タグオブジェクト)を返す。find_all('タグ名', ...)
: 条件に一致するすべての要素をリストで返す。
タグ名で検索する
“`python
最初のh1タグを取得
first_h1 = soup.find(‘h1’)
print(f”最初のh1タグ: {first_h1}”)
すべてのpタグを取得
all_p_tags = soup.find_all(‘p’)
print(f”見つかったpタグの数: {len(all_p_tags)}”)
“`
属性で検索する (class, idなど)
class
やid
といった属性を指定することで、より具体的に要素を絞り込むことができます。
“`python
class属性で検索
classはPythonの予約語なので、引数名は ‘class_’ のようにアンダースコアを付ける
content_div = soup.find(‘div’, class_=’content-area’)
id属性で検索
main_title = soup.find(‘h1′, id=’main-title’)
複数の属性を辞書で指定
external_link = soup.find(‘a’, {‘target’: ‘_blank’, ‘rel’: ‘noopener’})
“`
3. 抽出した要素から情報を抜き出す
find()
やfind_all()
で目的の要素(タグオブジェクト)を見つけたら、その中からテキストや属性値を抜き出します。
-
テキストの取得:
.text
または.get_text()
タグに囲まれたテキストコンテンツを取得します。
python
if first_h1: # 要素が見つかった場合のみ実行
print(f"h1のテキスト: {first_h1.text}") -
属性値の取得:
['属性名']
または.get('属性名')
href
やsrc
などの属性の値を取得します。
“`python
link_tag = soup.find(‘a’)
if link_tag:
# 辞書のようにアクセス
link_url = link_tag[‘href’]
print(f”リンク先のURL: {link_url}”)# .get()を使う方法(属性が存在しない場合にNoneを返すので安全) link_target = link_tag.get('target') print(f"リンクのtarget属性: {link_target}")
“`
4. 実践: ニュースサイトからタイトルとURLの一覧を取得する
ここまでの知識を総動員して、簡単な実践を行ってみましょう。
ここでは、架空のニュースサイトから記事のタイトルとリンク先URLをスクレイピングします。
対象のHTML(架空):
“`html
今日のヘッドライン
Pythonが人気言語ランキングで1位に
最新の調査でPythonが最も人気のあるプログラミング言語に選ばれました。
Webスクレイピングの市場が拡大
データ活用の需要増に伴い、スクレイピング技術の重要性が高まっています。
新しいAIモデルが発表される
驚異的な性能を持つ新しいAIモデルが、世界中の注目を集めています。
``
http://example-news.com` というURLで公開されていると仮定します。
※このHTMLが
スクレイピングコード:
“`python
import requests
from bs4 import BeautifulSoup
import time
— ステップ1: Webページの取得 —
実際のコードではここにURLを入れる
url = ‘http://example-news.com’
headers = {‘User-Agent’: ‘…’}
response = requests.get(url, headers=headers)
response.encoding = response.apparent_encoding
この例では、上記HTMLを直接文字列として使用します
html_doc = “””
今日のヘッドライン
Pythonが人気言語ランキングで1位に
最新の調査でPythonが最も人気のあるプログラミング言語に選ばれました。
Webスクレイピングの市場が拡大
データ活用の需要増に伴い、スクレイピング技術の重要性が高まっています。
新しいAIモデルが発表される
驚異的な性能を持つ新しいAIモデルが、世界中の注目を集めています。
“””
— ステップ2: BeautifulSoupでパース —
soup = BeautifulSoup(html_doc, ‘lxml’)
— ステップ3: データの抽出 —
各記事は
で囲まれているので、これを全て取得
articles = soup.find_all(‘div’, class_=’article’)
取得した情報を格納するためのリスト
news_data = []
各記事要素をループで処理
for article in articles:
# 記事の中からタイトル(h2タグ内のaタグ)を探す
title_tag = article.find(‘h2’).find(‘a’)
# aタグが見つかれば、テキストとhref属性を取得
if title_tag:
title = title_tag.text
# hrefが相対パス(/news/001)なので、ベースURLを結合する
# link = 'http://example-news.com' + title_tag['href']
link = title_tag['href'] # この例では相対パスのまま取得
news_data.append({'title': title, 'link': link})
— ステップ4: 結果の表示 —
for news in news_data:
print(f”タイトル: {news[‘title’]}”)
print(f”リンク: {news[‘link’]}”)
print(“-” * 20)
“`
このコードを実行すると、各記事のタイトルとリンクが抽出され、きれいに表示されるはずです。このように、find_all()
で大きな塊を取得し、ループ内でさらにfind()
を使って詳細な情報を抜き出していくのが、スクレイピングの基本的なパターンです。
第4章: CSSセレクタを使った高度なデータ抽出
前章ではfind()
とfind_all()
を使いましたが、HTMLの構造が複雑になってくると、これらのメソッドだけでは目的の要素を特定するのが難しくなることがあります。そこで登場するのが、より強力で直感的なCSSセレクタです。
1. なぜCSSセレクタが強力なのか?
find()
やfind_all()
を何度もネストさせる(soup.find(...).find(...).find(...)
のように繋げる)ことも可能ですが、コードが長くなり、HTML構造の変更に弱くなります。
CSSセレクタを使えば、「id="news-list"
のdiv
要素の中にある、class="article"
を持つ要素の、直下の子要素であるh2
タグ」といった複雑な階層関係を、一行の文字列で簡潔に表現できます。これにより、コードの可読性が向上し、メンテナンスも容易になります。
2. BeautifulSoupでのCSSセレクタの使い方
BeautifulSoupでは、CSSセレクタを使うための専用メソッドが用意されています。
select_one('CSSセレクタ')
: セレクタに一致する最初の1つの要素を返す。(find()
のセレクタ版)
select('CSSセレクタ')
: セレクタに一致するすべての要素をリストで返す。(find_all()
のセレクタ版)
3. よく使うCSSセレクタのパターン
スクレイピングで特によく使われるセレクタのパターンを覚えましょう。
パターン
セレクタの例
意味
タグ
h2
<h2>
タグ
クラス
.article
class="article"
を持つ要素
ID
#news-list
id="news-list"
を持つ要素
子孫
div .title
<div>
の中にある(階層は問わない).title
クラスを持つ要素
子
ul > li
<ul>
の直下にある <li>
要素
隣接兄弟
h2 + p
<h2>
のすぐ次にある兄弟要素の <p>
属性
a[href]
href
属性を持つ <a>
タグ
a[href^="https"]
href
属性が https
で始まる <a>
タグ
a[href$=".pdf"]
href
属性が .pdf
で終わる <a>
タグ
a[href*="search"]
href
属性に search
を含む <a>
タグ
n番目の要素
li:nth-of-type(3)
3番目の <li>
要素
これらのセレクタを組み合わせることで、HTML文書のどんな場所にある要素でも、ほぼピンポイントで指定できます。
4. 実践: ECサイトから商品情報をスクレイピングする
CSSセレクタの威力を体感するために、架空のECサイトの商品一覧ページから複数の情報を抜き出してみましょう。
対象のHTML(架空):
“`html
“`
取得したい情報:
* 商品名
* 価格
* レビュー数
* 商品画像URL
CSSセレクタを使ったスクレイピングコード:
“`python
import requests
from bs4 import BeautifulSoup
import csv
この例ではHTMLを直接文字列として使用します
html_doc_ec = “””
“””
soup = BeautifulSoup(html_doc_ec, ‘lxml’)
— データ抽出 —
CSSセレクタを使い、商品ごとのコンテナ要素(.product-item)を全て取得
product_items = soup.select(‘.product-item’)
products_data = []
for item in product_items:
# item (各商品コンテナ) の中から、さらにセレクタで情報を探す
# 商品名 ( .product-name クラスを持つ h3 タグの中の a タグのテキスト)
# .select_one() を使って安全に取得
name_tag = item.select_one('.product-name a')
name = name_tag.text.strip() if name_tag else 'N/A'
# 価格 ( .price クラスを持つ span タグのテキスト)
price_tag = item.select_one('.price')
price_text = price_tag.text.strip() if price_tag else 'N/A'
# 不要な文字(¥, ,)を削除して数値に変換することも可能
# price_num = int(price_text.replace('¥', '').replace(',', ''))
# レビュー数 ( .review-count クラスを持つ span タグのテキスト)
review_tag = item.select_one('.review-count')
review_count_text = review_tag.text.strip() if review_tag else 'N/A'
# カッコや数字以外の文字を削除
# review_count = int(review_count_text.strip('()'))
# 画像URL ( .product-image クラスを持つ img タグの src 属性)
image_tag = item.select_one('.product-image')
image_url = image_tag['src'] if image_tag else 'N/A'
products_data.append({
'name': name,
'price': price_text,
'review_count': review_count_text,
'image_url': image_url
})
— データの保存 (CSV) —
ファイル名
filename = ‘products.csv’
CSVファイルに書き込み
with open(filename, ‘w’, newline=”, encoding=’utf-8-sig’) as f:
# ヘッダーを指定
fieldnames = [‘name’, ‘price’, ‘review_count’, ‘image_url’]
writer = csv.DictWriter(f, fieldnames=fieldnames)
# ヘッダーを書き込む
writer.writeheader()
# データを書き込む
writer.writerows(products_data)
print(f”データが {filename} に保存されました。”)
print(products_data)
``
このコードでは、
soup.select(‘.product-item’)でまず商品ごとのブロックを全て取得し、ループ内で各ブロック(
item)に対して
item.select_one()`を実行しています。これにより、各商品の情報が混ざることなく、正確に対応付けて抽出できます。
また、if name_tag else 'N/A'
のような三項演算子を使うことで、要素が見つからなかった場合(None
が返された場合)でもエラーにならず、代替の文字列を代入できるため、より堅牢なコードになります。
最後に、取得したデータを標準ライブラリのcsv
モジュールを使ってCSVファイルに保存する方法も示しました。これで、スクレイピングした結果をExcelなどで簡単に分析できるようになります。
第5章: 応用テクニックと実践的プロジェクト
基本的なデータ抽出ができるようになったら、次はより実践的なシナリオに対応するための応用テクニックを学びましょう。
1. 複数ページにまたがるデータのスクレイピング(ページネーション)
多くのWebサイトでは、大量の検索結果や商品リストを一度に表示せず、複数のページに分割して表示します。これをページネーションと呼びます。2ページ目、3ページ目と自動で遷移しながらデータを収集する方法は、大きく分けて2つあります。
方法1: 「次へ」リンクを辿る
ページの下部にある「次へ」や「Next >」といったリンクを辿っていく方法です。
アプローチ:
1. 現在のページをスクレイピングする。
2. ページ内から「次へ」のリンクを持つ要素を探す。
3. そのリンク先のURLを取得する。
4. もしリンクが存在すれば、そのURLに対して新たにリクエストを送り、ステップ1に戻る。
5. リンクが存在しなければ(最終ページに到達したら)、ループを終了する。
コードのイメージ (whileループ):
“`python
import requests
from bs4 import BeautifulSoup
import time
base_url = ‘https://example-site.com’
next_page_url = ‘/list/page/1’ # 開始ページ
while next_page_url:
# 現在のページのURLを生成
current_url = base_url + next_page_url
print(f”Scraping: {current_url}”)
response = requests.get(current_url)
soup = BeautifulSoup(response.text, 'lxml')
# --- このページ内のデータ抽出処理 ---
# (例: 商品情報を取得するコード)
# --- 「次へ」のリンクを探す ---
next_link_tag = soup.select_one('a.next-page-link') # 例: class="next-page-link"のaタグ
if next_link_tag and 'href' in next_link_tag.attrs:
next_page_url = next_link_tag['href']
else:
# リンクが見つからなければループを終了
next_page_url = None
# サーバーへの負荷軽減
time.sleep(2)
print(“全てのページのスクレイピングが完了しました。”)
“`
方法2: URLのパターンを分析する
ページのURLに規則性がある場合、そのパターンを利用して直接URLを生成する方が効率的です。
例:
* https://example.com/search?q=python&page=1
* https://example.com/search?q=python&page=2
* https://example.com/search?q=python&page=3
この場合、page
パラメータの数字を1, 2, 3…と変えていくだけで、各ページにアクセスできます。
コードのイメージ (forループ):
“`python
import requests
from bs4 import BeautifulSoup
import time
1ページ目から5ページ目まで取得する場合
for page_num in range(1, 6):
# f-stringを使ってURLを動的に生成
url = f”https://example.com/search?q=python&page={page_num}”
print(f”Scraping: {url}”)
response = requests.get(url)
# 存在しないページにアクセスすると404が返る場合があるのでチェック
if response.status_code != 200:
print(f"ページ {page_num} が存在しないか、アクセスできませんでした。処理を中断します。")
break
soup = BeautifulSoup(response.text, 'lxml')
# --- このページ内のデータ抽出処理 ---
# (ここに処理を書く)
time.sleep(2)
print(“スクレイピングが完了しました。”)
“`
2. データの保存
取得したデータをプログラムの実行中だけでなく、後で利用できるようにファイルに保存する方法も重要です。
-
CSV (Comma-Separated Values):
第4章で紹介した通り、表形式のデータに最適で、ExcelやGoogleスプレッドシートで簡単に開けます。csv
モジュールが標準で利用できます。
-
JSON (JavaScript Object Notation):
Pythonの辞書やリストと非常に親和性が高く、Web APIなどでも広く使われるデータ形式です。階層構造を持つデータをそのままの形で保存するのに適しています。
“`python
import json
products_dataは辞書のリストとする
products_data = [
{‘name’: ‘イヤホン’, ‘price’: 12800},
{‘name’: ‘ウォッチ’, ‘price’: 19800}
]
with open(‘products.json’, ‘w’, encoding=’utf-8′) as f:
# json.dump()でファイルに書き込む
# ensure_ascii=False: 日本語をそのまま出力
# indent=4: 見やすいように4スペースでインデントする
json.dump(products_data, f, ensure_ascii=False, indent=4)
print(“データが products.json に保存されました。”)
“`
-
Pandasを使った保存:
データ分析ライブラリのPandas
を使うと、データの保存がさらに簡単になります。CSVやExcel、JSONなど多様なフォーマットに数行で書き出せます。
“`python
import pandas as pd
(products_dataは辞書のリスト)
辞書のリストからDataFrameを作成
df = pd.DataFrame(products_data)
CSVに保存 (インデックスは不要なことが多い)
df.to_csv(‘products_pandas.csv’, index=False, encoding=’utf-8-sig’)
Excelに保存 (openpyxlライブラリが別途必要 pip install openpyxl
)
df.to_excel(‘products_pandas.xlsx’, index=False)
“`
3. 動的サイトへの挑戦(イントロダクション)
ここまでの方法でスクレイピングできるのは、サーバーから返される最初のHTMLに全ての情報が含まれている「静的サイト」です。
しかし、現代のWebサイトの多くは「動的サイト」です。これらは、ページが読み込まれた後にJavaScriptが動作し、サーバーと非同期通信(Ajax/XHR)を行って追加のデータを取得し、ページの内容を動的に書き換えます。
動的サイトの特徴:
* requests.get()
で取得したHTML(ページのソースを表示)を見ても、ブラウザに表示されている情報の一部しか含まれていない。
* 無限スクロール(ページ下部まで行くと新しいコンテンツが読み込まれる)が実装されている。
requests
はJavaScriptを実行できないため、これらのサイトから情報を取得することはできません。そこで登場するのがSeleniumです。
Seleniumとは?
Seleniumは、本来はWebアプリケーションの自動テストツールですが、プログラムからWebブラウザ(Chrome, Firefoxなど)を直接操作できるため、高度なスクレイピングにも利用されます。
- 仕組み: Seleniumは実際にブラウザを起動し、ページを開き、ボタンをクリックし、テキストを入力するなど、人間と同じ操作を自動で行います。
- メリット: JavaScriptが完全に実行された後の、最終的に表示されている状態のHTMLを取得できます。
- デメリット: 実際にブラウザを動かすため、
requests
に比べて動作が非常に遅く、メモリ消費も大きくなります。
SeleniumとBeautifulSoupの連携:
Seleniumでブラウザを操作して目的のページ状態にした後、その時点でのHTMLソース(driver.page_source
)をBeautifulSoupに渡してパースする、という組み合わせが一般的です。
簡単なコード例:
“`python
from selenium import webdriver
from bs4 import BeautifulSoup
import time
Seleniumのセットアップ (WebDriverのインストールが必要)
driver = webdriver.Chrome()
動的サイトのURL
url = ‘https://example-dynamic-site.com’
ページを開く
driver.get(url)
JavaScriptがデータを読み込むのを待つ (ここでは単純に5秒待機)
time.sleep(5)
JavaScript実行後のHTMLを取得
html = driver.page_source
ブラウザを閉じる
driver.quit()
あとはBeautifulSoupでいつも通りパース
soup = BeautifulSoup(html, ‘lxml’)
— データ抽出処理 —
(例: soup.select(…)など)
``
Seleniumは強力ですが、セットアップや待機処理の調整など、
requestsよりも複雑になります。まずは
requests+
BeautifulSoup`で対応できるサイトから始め、必要になったらSeleniumの学習に進むのが良いでしょう。
4. エラーハンドリングと堅牢なコード
スクレイピングは、外部のWebサイトというコントロールできない要素に依存するため、予期せぬエラーが頻繁に発生します。
- サイトのHTML構造が突然変更される。
- ネットワークが不安定でリクエストに失敗する。
- 特定のページにだけ、探している要素が存在しない。
このような事態に対応するため、try-except
構文を使ったエラーハンドリングが不可欠です。
“`python
… ループ内 …
for item in product_items:
try:
# このブロック内でエラーが発生する可能性のある処理を書く
name = item.select_one(‘.product-name’).text
price = item.select_one(‘.price’).text
except AttributeError:
# select_oneがNoneを返し、その.textにアクセスしようとするとAttributeErrorが発生
print("一部の要素が見つかりませんでした。スキップします。")
# 代替値を設定したり、continueで次のループに進む
name = 'N/A'
price = 'N/A'
except requests.exceptions.RequestException as e:
# requestsに関するエラー全般をキャッチ
print(f"ネットワークエラーが発生しました: {e}")
break # ループを中断
# ...
“`
堅牢なスクレイピングプログラムは、一部のデータが取得できなくても全体が停止することなく、可能な限り処理を続けられるように設計されています。
第6章: まとめと今後の学習
本講座で学んだことの振り返り
この長い講座を通して、あなたはPythonを使ったWebスクレイピングの旅の第一歩を力強く踏み出しました。振り返ってみましょう。
- Webスクレイピングの原理: HTTP通信とHTML/CSSの基本を理解し、スクレイピングが「リクエスト」「レスポンス」「パース」「抽出」のステップで成り立っていることを学びました。
- 必須ツールの使い方:
requests
でWebページのコンテンツを取得し、BeautifulSoup
でそれを解析する方法をマスターしました。
- 強力な抽出テクニック:
find
/find_all
から、より柔軟で強力なselect
/select_one
とCSSセレクタの使い方までを習得しました。
- 実践的な応用スキル: ページネーションへの対応、取得したデータのCSVやJSONでの保存、そして動的サイトという次の課題とSeleniumという解決策について知りました。
- 最も重要なルール: サイト運営者への配慮、利用規約の遵守、法律の尊重といった「責任あるスクレイピング」の重要性を学びました。
これだけの知識があれば、世の中の多くの静的サイトから価値ある情報を引き出すことが可能です。
スクレイピングマスターへの道
スクレイピングは、実践すればするほどスキルが向上する分野です。ぜひ、興味のある様々なサイトに挑戦してみてください。壁にぶつかり、開発者ツールと格闘し、それを乗り越える経験が、あなたをより優れたプログラマへと成長させます。
今後の学習ステップ:
1. Seleniumの本格的な学習: 動的サイトのスクレイピングが避けられない場面は増えています。クリック、スクロール、フォーム入力といったブラウザ操作や、特定の要素が表示されるまで待機するWebDriverWait
といった高度なテクニックを学びましょう。
2. Scrapyフレームワーク: より大規模で高速なスクレイピングやクローリングを行いたい場合、Pythonの専用フレームワークであるScrapyが強力な選択肢となります。非同期処理をベースにしており、非常に効率的なデータ収集が可能です。
3. APIの活用: 多くのサービス(Twitter, Google Mapsなど)は、開発者向けにAPI (Application Programming Interface) を提供しています。APIは、スクレイピングよりもはるかに安定的かつ効率的に、定められたルールの中でデータを取得できる公式な手段です。スクレイピングを試みる前に、対象サイトがAPIを提供していないか確認する癖をつけましょう。
4. データベースへの保存: 収集したデータが大量になる場合、CSVやJSONファイルでは管理が煩雑になります。SQLite(小規模)、MySQLやPostgreSQL(大規模)といったデータベースにデータを保存するスキルを身につけると、より本格的なデータ活用への道が開けます。
最後に: 責任あるスクレイピングを
本講座で何度も強調しましたが、改めてお伝えします。技術は諸刃の剣です。Webスクレイピングは非常に強力なツールですが、その使い方を誤れば、他者に迷惑をかけ、あなた自身をトラブルに巻き込むことにもなりかねません。
常にサイト運営者への敬意と感謝の気持ちを忘れず、サーバーに負荷をかけないよう配慮し、定められたルールの中で技術を駆使してください。
あなたのデータ探索の旅が、実り多く、エキサイティングなものになることを心から願っています。Happy Scraping
articles = soup.find_all(‘div’, class_=’article’)
取得した情報を格納するためのリスト
news_data = []
各記事要素をループで処理
for article in articles:
# 記事の中からタイトル(h2タグ内のaタグ)を探す
title_tag = article.find(‘h2’).find(‘a’)
# aタグが見つかれば、テキストとhref属性を取得
if title_tag:
title = title_tag.text
# hrefが相対パス(/news/001)なので、ベースURLを結合する
# link = 'http://example-news.com' + title_tag['href']
link = title_tag['href'] # この例では相対パスのまま取得
news_data.append({'title': title, 'link': link})
— ステップ4: 結果の表示 —
for news in news_data:
print(f”タイトル: {news[‘title’]}”)
print(f”リンク: {news[‘link’]}”)
print(“-” * 20)
“`
このコードを実行すると、各記事のタイトルとリンクが抽出され、きれいに表示されるはずです。このように、find_all()
で大きな塊を取得し、ループ内でさらにfind()
を使って詳細な情報を抜き出していくのが、スクレイピングの基本的なパターンです。
第4章: CSSセレクタを使った高度なデータ抽出
前章ではfind()
とfind_all()
を使いましたが、HTMLの構造が複雑になってくると、これらのメソッドだけでは目的の要素を特定するのが難しくなることがあります。そこで登場するのが、より強力で直感的なCSSセレクタです。
1. なぜCSSセレクタが強力なのか?
find()
やfind_all()
を何度もネストさせる(soup.find(...).find(...).find(...)
のように繋げる)ことも可能ですが、コードが長くなり、HTML構造の変更に弱くなります。
CSSセレクタを使えば、「id="news-list"
のdiv
要素の中にある、class="article"
を持つ要素の、直下の子要素であるh2
タグ」といった複雑な階層関係を、一行の文字列で簡潔に表現できます。これにより、コードの可読性が向上し、メンテナンスも容易になります。
2. BeautifulSoupでのCSSセレクタの使い方
BeautifulSoupでは、CSSセレクタを使うための専用メソッドが用意されています。
select_one('CSSセレクタ')
: セレクタに一致する最初の1つの要素を返す。(find()
のセレクタ版)select('CSSセレクタ')
: セレクタに一致するすべての要素をリストで返す。(find_all()
のセレクタ版)
3. よく使うCSSセレクタのパターン
スクレイピングで特によく使われるセレクタのパターンを覚えましょう。
パターン | セレクタの例 | 意味 |
---|---|---|
タグ | h2 |
<h2> タグ |
クラス | .article |
class="article" を持つ要素 |
ID | #news-list |
id="news-list" を持つ要素 |
子孫 | div .title |
<div> の中にある(階層は問わない).title クラスを持つ要素 |
子 | ul > li |
<ul> の直下にある <li> 要素 |
隣接兄弟 | h2 + p |
<h2> のすぐ次にある兄弟要素の <p> |
属性 | a[href] |
href 属性を持つ <a> タグ |
a[href^="https"] |
href 属性が https で始まる <a> タグ |
|
a[href$=".pdf"] |
href 属性が .pdf で終わる <a> タグ |
|
a[href*="search"] |
href 属性に search を含む <a> タグ |
|
n番目の要素 | li:nth-of-type(3) |
3番目の <li> 要素 |
これらのセレクタを組み合わせることで、HTML文書のどんな場所にある要素でも、ほぼピンポイントで指定できます。
4. 実践: ECサイトから商品情報をスクレイピングする
CSSセレクタの威力を体感するために、架空のECサイトの商品一覧ページから複数の情報を抜き出してみましょう。
対象のHTML(架空):
“`html


“`
取得したい情報:
* 商品名
* 価格
* レビュー数
* 商品画像URL
CSSセレクタを使ったスクレイピングコード:
“`python
import requests
from bs4 import BeautifulSoup
import csv
この例ではHTMLを直接文字列として使用します
html_doc_ec = “””


“””
soup = BeautifulSoup(html_doc_ec, ‘lxml’)
— データ抽出 —
CSSセレクタを使い、商品ごとのコンテナ要素(.product-item)を全て取得
product_items = soup.select(‘.product-item’)
products_data = []
for item in product_items:
# item (各商品コンテナ) の中から、さらにセレクタで情報を探す
# 商品名 ( .product-name クラスを持つ h3 タグの中の a タグのテキスト)
# .select_one() を使って安全に取得
name_tag = item.select_one('.product-name a')
name = name_tag.text.strip() if name_tag else 'N/A'
# 価格 ( .price クラスを持つ span タグのテキスト)
price_tag = item.select_one('.price')
price_text = price_tag.text.strip() if price_tag else 'N/A'
# 不要な文字(¥, ,)を削除して数値に変換することも可能
# price_num = int(price_text.replace('¥', '').replace(',', ''))
# レビュー数 ( .review-count クラスを持つ span タグのテキスト)
review_tag = item.select_one('.review-count')
review_count_text = review_tag.text.strip() if review_tag else 'N/A'
# カッコや数字以外の文字を削除
# review_count = int(review_count_text.strip('()'))
# 画像URL ( .product-image クラスを持つ img タグの src 属性)
image_tag = item.select_one('.product-image')
image_url = image_tag['src'] if image_tag else 'N/A'
products_data.append({
'name': name,
'price': price_text,
'review_count': review_count_text,
'image_url': image_url
})
— データの保存 (CSV) —
ファイル名
filename = ‘products.csv’
CSVファイルに書き込み
with open(filename, ‘w’, newline=”, encoding=’utf-8-sig’) as f:
# ヘッダーを指定
fieldnames = [‘name’, ‘price’, ‘review_count’, ‘image_url’]
writer = csv.DictWriter(f, fieldnames=fieldnames)
# ヘッダーを書き込む
writer.writeheader()
# データを書き込む
writer.writerows(products_data)
print(f”データが {filename} に保存されました。”)
print(products_data)
``
soup.select(‘.product-item’)
このコードでは、でまず商品ごとのブロックを全て取得し、ループ内で各ブロック(
item)に対して
item.select_one()`を実行しています。これにより、各商品の情報が混ざることなく、正確に対応付けて抽出できます。
また、if name_tag else 'N/A'
のような三項演算子を使うことで、要素が見つからなかった場合(None
が返された場合)でもエラーにならず、代替の文字列を代入できるため、より堅牢なコードになります。
最後に、取得したデータを標準ライブラリのcsv
モジュールを使ってCSVファイルに保存する方法も示しました。これで、スクレイピングした結果をExcelなどで簡単に分析できるようになります。
第5章: 応用テクニックと実践的プロジェクト
基本的なデータ抽出ができるようになったら、次はより実践的なシナリオに対応するための応用テクニックを学びましょう。
1. 複数ページにまたがるデータのスクレイピング(ページネーション)
多くのWebサイトでは、大量の検索結果や商品リストを一度に表示せず、複数のページに分割して表示します。これをページネーションと呼びます。2ページ目、3ページ目と自動で遷移しながらデータを収集する方法は、大きく分けて2つあります。
方法1: 「次へ」リンクを辿る
ページの下部にある「次へ」や「Next >」といったリンクを辿っていく方法です。
アプローチ:
1. 現在のページをスクレイピングする。
2. ページ内から「次へ」のリンクを持つ要素を探す。
3. そのリンク先のURLを取得する。
4. もしリンクが存在すれば、そのURLに対して新たにリクエストを送り、ステップ1に戻る。
5. リンクが存在しなければ(最終ページに到達したら)、ループを終了する。
コードのイメージ (whileループ):
“`python
import requests
from bs4 import BeautifulSoup
import time
base_url = ‘https://example-site.com’
next_page_url = ‘/list/page/1’ # 開始ページ
while next_page_url:
# 現在のページのURLを生成
current_url = base_url + next_page_url
print(f”Scraping: {current_url}”)
response = requests.get(current_url)
soup = BeautifulSoup(response.text, 'lxml')
# --- このページ内のデータ抽出処理 ---
# (例: 商品情報を取得するコード)
# --- 「次へ」のリンクを探す ---
next_link_tag = soup.select_one('a.next-page-link') # 例: class="next-page-link"のaタグ
if next_link_tag and 'href' in next_link_tag.attrs:
next_page_url = next_link_tag['href']
else:
# リンクが見つからなければループを終了
next_page_url = None
# サーバーへの負荷軽減
time.sleep(2)
print(“全てのページのスクレイピングが完了しました。”)
“`
方法2: URLのパターンを分析する
ページのURLに規則性がある場合、そのパターンを利用して直接URLを生成する方が効率的です。
例:
* https://example.com/search?q=python&page=1
* https://example.com/search?q=python&page=2
* https://example.com/search?q=python&page=3
この場合、page
パラメータの数字を1, 2, 3…と変えていくだけで、各ページにアクセスできます。
コードのイメージ (forループ):
“`python
import requests
from bs4 import BeautifulSoup
import time
1ページ目から5ページ目まで取得する場合
for page_num in range(1, 6):
# f-stringを使ってURLを動的に生成
url = f”https://example.com/search?q=python&page={page_num}”
print(f”Scraping: {url}”)
response = requests.get(url)
# 存在しないページにアクセスすると404が返る場合があるのでチェック
if response.status_code != 200:
print(f"ページ {page_num} が存在しないか、アクセスできませんでした。処理を中断します。")
break
soup = BeautifulSoup(response.text, 'lxml')
# --- このページ内のデータ抽出処理 ---
# (ここに処理を書く)
time.sleep(2)
print(“スクレイピングが完了しました。”)
“`
2. データの保存
取得したデータをプログラムの実行中だけでなく、後で利用できるようにファイルに保存する方法も重要です。
-
CSV (Comma-Separated Values):
第4章で紹介した通り、表形式のデータに最適で、ExcelやGoogleスプレッドシートで簡単に開けます。csv
モジュールが標準で利用できます。 -
JSON (JavaScript Object Notation):
Pythonの辞書やリストと非常に親和性が高く、Web APIなどでも広く使われるデータ形式です。階層構造を持つデータをそのままの形で保存するのに適しています。
“`python
import jsonproducts_dataは辞書のリストとする
products_data = [
{‘name’: ‘イヤホン’, ‘price’: 12800},
{‘name’: ‘ウォッチ’, ‘price’: 19800}
]with open(‘products.json’, ‘w’, encoding=’utf-8′) as f:
# json.dump()でファイルに書き込む
# ensure_ascii=False: 日本語をそのまま出力
# indent=4: 見やすいように4スペースでインデントする
json.dump(products_data, f, ensure_ascii=False, indent=4)print(“データが products.json に保存されました。”)
“` -
Pandasを使った保存:
データ分析ライブラリのPandas
を使うと、データの保存がさらに簡単になります。CSVやExcel、JSONなど多様なフォーマットに数行で書き出せます。
“`python
import pandas as pd(products_dataは辞書のリスト)
辞書のリストからDataFrameを作成
df = pd.DataFrame(products_data)
CSVに保存 (インデックスは不要なことが多い)
df.to_csv(‘products_pandas.csv’, index=False, encoding=’utf-8-sig’)
Excelに保存 (openpyxlライブラリが別途必要
pip install openpyxl
)df.to_excel(‘products_pandas.xlsx’, index=False)
“`
3. 動的サイトへの挑戦(イントロダクション)
ここまでの方法でスクレイピングできるのは、サーバーから返される最初のHTMLに全ての情報が含まれている「静的サイト」です。
しかし、現代のWebサイトの多くは「動的サイト」です。これらは、ページが読み込まれた後にJavaScriptが動作し、サーバーと非同期通信(Ajax/XHR)を行って追加のデータを取得し、ページの内容を動的に書き換えます。
動的サイトの特徴:
* requests.get()
で取得したHTML(ページのソースを表示)を見ても、ブラウザに表示されている情報の一部しか含まれていない。
* 無限スクロール(ページ下部まで行くと新しいコンテンツが読み込まれる)が実装されている。
requests
はJavaScriptを実行できないため、これらのサイトから情報を取得することはできません。そこで登場するのがSeleniumです。
Seleniumとは?
Seleniumは、本来はWebアプリケーションの自動テストツールですが、プログラムからWebブラウザ(Chrome, Firefoxなど)を直接操作できるため、高度なスクレイピングにも利用されます。
- 仕組み: Seleniumは実際にブラウザを起動し、ページを開き、ボタンをクリックし、テキストを入力するなど、人間と同じ操作を自動で行います。
- メリット: JavaScriptが完全に実行された後の、最終的に表示されている状態のHTMLを取得できます。
- デメリット: 実際にブラウザを動かすため、
requests
に比べて動作が非常に遅く、メモリ消費も大きくなります。
SeleniumとBeautifulSoupの連携:
Seleniumでブラウザを操作して目的のページ状態にした後、その時点でのHTMLソース(driver.page_source
)をBeautifulSoupに渡してパースする、という組み合わせが一般的です。
簡単なコード例:
“`python
from selenium import webdriver
from bs4 import BeautifulSoup
import time
Seleniumのセットアップ (WebDriverのインストールが必要)
driver = webdriver.Chrome()
動的サイトのURL
url = ‘https://example-dynamic-site.com’
ページを開く
driver.get(url)
JavaScriptがデータを読み込むのを待つ (ここでは単純に5秒待機)
time.sleep(5)
JavaScript実行後のHTMLを取得
html = driver.page_source
ブラウザを閉じる
driver.quit()
あとはBeautifulSoupでいつも通りパース
soup = BeautifulSoup(html, ‘lxml’)
— データ抽出処理 —
(例: soup.select(…)など)
``
requests
Seleniumは強力ですが、セットアップや待機処理の調整など、よりも複雑になります。まずは
requests+
BeautifulSoup`で対応できるサイトから始め、必要になったらSeleniumの学習に進むのが良いでしょう。
4. エラーハンドリングと堅牢なコード
スクレイピングは、外部のWebサイトというコントロールできない要素に依存するため、予期せぬエラーが頻繁に発生します。
- サイトのHTML構造が突然変更される。
- ネットワークが不安定でリクエストに失敗する。
- 特定のページにだけ、探している要素が存在しない。
このような事態に対応するため、try-except
構文を使ったエラーハンドリングが不可欠です。
“`python
… ループ内 …
for item in product_items:
try:
# このブロック内でエラーが発生する可能性のある処理を書く
name = item.select_one(‘.product-name’).text
price = item.select_one(‘.price’).text
except AttributeError:
# select_oneがNoneを返し、その.textにアクセスしようとするとAttributeErrorが発生
print("一部の要素が見つかりませんでした。スキップします。")
# 代替値を設定したり、continueで次のループに進む
name = 'N/A'
price = 'N/A'
except requests.exceptions.RequestException as e:
# requestsに関するエラー全般をキャッチ
print(f"ネットワークエラーが発生しました: {e}")
break # ループを中断
# ...
“`
堅牢なスクレイピングプログラムは、一部のデータが取得できなくても全体が停止することなく、可能な限り処理を続けられるように設計されています。
第6章: まとめと今後の学習
本講座で学んだことの振り返り
この長い講座を通して、あなたはPythonを使ったWebスクレイピングの旅の第一歩を力強く踏み出しました。振り返ってみましょう。
- Webスクレイピングの原理: HTTP通信とHTML/CSSの基本を理解し、スクレイピングが「リクエスト」「レスポンス」「パース」「抽出」のステップで成り立っていることを学びました。
- 必須ツールの使い方:
requests
でWebページのコンテンツを取得し、BeautifulSoup
でそれを解析する方法をマスターしました。 - 強力な抽出テクニック:
find
/find_all
から、より柔軟で強力なselect
/select_one
とCSSセレクタの使い方までを習得しました。 - 実践的な応用スキル: ページネーションへの対応、取得したデータのCSVやJSONでの保存、そして動的サイトという次の課題とSeleniumという解決策について知りました。
- 最も重要なルール: サイト運営者への配慮、利用規約の遵守、法律の尊重といった「責任あるスクレイピング」の重要性を学びました。
これだけの知識があれば、世の中の多くの静的サイトから価値ある情報を引き出すことが可能です。
スクレイピングマスターへの道
スクレイピングは、実践すればするほどスキルが向上する分野です。ぜひ、興味のある様々なサイトに挑戦してみてください。壁にぶつかり、開発者ツールと格闘し、それを乗り越える経験が、あなたをより優れたプログラマへと成長させます。
今後の学習ステップ:
1. Seleniumの本格的な学習: 動的サイトのスクレイピングが避けられない場面は増えています。クリック、スクロール、フォーム入力といったブラウザ操作や、特定の要素が表示されるまで待機するWebDriverWait
といった高度なテクニックを学びましょう。
2. Scrapyフレームワーク: より大規模で高速なスクレイピングやクローリングを行いたい場合、Pythonの専用フレームワークであるScrapyが強力な選択肢となります。非同期処理をベースにしており、非常に効率的なデータ収集が可能です。
3. APIの活用: 多くのサービス(Twitter, Google Mapsなど)は、開発者向けにAPI (Application Programming Interface) を提供しています。APIは、スクレイピングよりもはるかに安定的かつ効率的に、定められたルールの中でデータを取得できる公式な手段です。スクレイピングを試みる前に、対象サイトがAPIを提供していないか確認する癖をつけましょう。
4. データベースへの保存: 収集したデータが大量になる場合、CSVやJSONファイルでは管理が煩雑になります。SQLite(小規模)、MySQLやPostgreSQL(大規模)といったデータベースにデータを保存するスキルを身につけると、より本格的なデータ活用への道が開けます。
最後に: 責任あるスクレイピングを
本講座で何度も強調しましたが、改めてお伝えします。技術は諸刃の剣です。Webスクレイピングは非常に強力なツールですが、その使い方を誤れば、他者に迷惑をかけ、あなた自身をトラブルに巻き込むことにもなりかねません。
常にサイト運営者への敬意と感謝の気持ちを忘れず、サーバーに負荷をかけないよう配慮し、定められたルールの中で技術を駆使してください。
あなたのデータ探索の旅が、実り多く、エキサイティングなものになることを心から願っています。Happy Scraping