CodeGym /コース /Python SELF JA /Webスクレイピングのエラー処理

Webスクレイピングのエラー処理

Python SELF JA
レベル 32 , レッスン 4
使用可能

この講義にたどり着いたということは、すでにWebスクレイピングがどう動くか、そしてBeautifulSoupを使ってHTMLから必要なデータを抽出する方法をよく理解しているということだね。でも、Webスクレイピングの世界は教科書通りにいかないことが多い。時にはデータ収集の夢がエラーとの戦いに変わることもある。だからこそ、落とし穴を避けつつスクレイパーを強固にする方法について話そう。

1. Webスクレイピングでよくあるエラー

404エラーや他のHTTPエラー

定番の問題:ページを取得しようとしたら、中身の代わりに誇らしげな「404 Not Found」が返ってくる。これはページが削除または移動された場合に起こる。他にもよくあるHTTPエラーには403 (Forbidden)、500 (Internal Server Error)、503 (Service Unavailable)があるね。

HTML構造の変更

データを抽出するコードを書くのにたくさん時間を費やしたのに、翌日にはサイトが少し見栄えを良くしようとしてHTML構造を変更。ああ、また全部書き直しだ!

リクエスト数の制限

あるサイトをずっとスクレイピングしていると、怪しまれることがある。最良の場合、しばらくブロックされるだけだけど、最悪の場合は永久にアクセス禁止になる。

待機時間とタイムアウト

時にはページの読み込みが遅く、タイムアウトの制限時間を超えたらスクリプトが落ちてしまうこともある。

2. エラー処理の方法

try-exceptを使う

スクリプトはどんな予期せぬ事態でも落ちるべきではない。try-exceptブロックを追加すると、エラーをキャッチして、スクレイパーが落ちることなく動作を続けるようにできるよ。

Python

    import requests
    from bs4 import BeautifulSoup
    
    url = 'http://example.com/some-nonexistent-page'
    
    try:
        response = requests.get(url)
        response.raise_for_status()  # 不正な応答に対してHTTPErrorを発生させる
    except requests.exceptions.HTTPError as errh:
        print("HTTPエラー:", errh)
    except requests.exceptions.ConnectionError as errc:
        print("接続エラー:", errc)
    except requests.exceptions.Timeout as errt:
        print("タイムアウトエラー:", errt)
    except requests.exceptions.RequestException as err:
        print("何か他のエラーが発生:", err)
        

良いスクリプトは単に例外をキャッチするだけでなく、エラーの種類ごとに対応策を持っている。例えば、IPがバンされたら次のプロキシに切り替えたり、サイトが落ちたら他のサイトのパースを行ったりできる。ページ上に存在すべき要素が見つからない場合は、スクリプトのアップデートが必要だと通知してメールを送ることも可能。

ログ記録

「ログなんて何のため?」って思う?実は、ログは第二の目なんだよ。何が問題だったのかを特定して迅速に修正する助けになるよ。

Python

import logging

logging.basicConfig(filename='scraper.log', level=logging.INFO)

try:
    # スクレイピングのコード
    pass
except Exception as e:
    logging.error("例外が発生しました", exc_info=True)
    

タイムアウトとリトライの使用

時には少し待ってもう一度試すだけでうまくいくこともある。このためにはタイムアウトとリトライが役立つよ。

Python

try:
    response = requests.get(url, timeout=5)
    response.raise_for_status()
except requests.exceptions.Timeout:
    print("タイムアウトが発生しました。リトライ中...")
    # リクエストを再試行するか、別のアクションを実行
    

3. 強固なスクレイピングの例

エラー処理付きのシンプルなスクレイパー

いくつかの一般的なエラーを処理できる、小さいけれど信頼性のあるスクレイパーを作ろう。

Python

import requests
from bs4 import BeautifulSoup
import time
import logging

logging.basicConfig(filename='scraper.log', level=logging.INFO)

url = 'http://example.com/some-nonexistent-page'

def fetch_html(url):
    try:
        response = requests.get(url, timeout=5)
        response.raise_for_status()
        return response.text
    except requests.exceptions.HTTPError as errh:
        logging.error("HTTPエラー: %s", errh)
    except requests.exceptions.ConnectionError as errc:
        logging.error("接続エラー: %s", errc)
    except requests.exceptions.Timeout as errt:
        logging.warning("タイムアウトが発生しました。リトライ中...")
        time.sleep(1)  # 少し待って再試行
        return fetch_html(url)
    except requests.exceptions.RequestException as err:
        logging.error("何か他のエラーが発生しました %s", err)
    return None

html_content = fetch_html(url)
if html_content:
    soup = BeautifulSoup(html_content, 'html.parser')
    # データ抽出のコード
else:
    print("ページの内容を取得できませんでした。")
    

部分的なデータ保存

途中で障害が起きても既に抽出されたデータを失わないように、データを部分的に保存しておこう。例えば、一連のページから情報を取得して進むごとに結果を保存することで、データ損失のリスクを最小限に抑えることができる。

Python

import csv

def save_to_csv(data, filename='data.csv'):
    with open(filename, mode='a', newline='') as file:
        writer = csv.writer(file)
        writer.writerow(data)
    

この方法なら、スクリプトが途中で落ちても、全てのデータを失うことなく、最後に保存した状態から再開できるよ。

パースしているページが部分的に変わった場合でも、データの大部分はまだ利用可能。少しのデータが欠けているからといってパースをキャンセルして貴重なデータを失うのはもったいないよね。

1
Опрос
データ抽出,  32 уровень,  4 лекция
недоступен
データ抽出
データ抽出
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION