帳票・PDF生成と社内回付の自動化

保守性の高いWebスクレイピング自動化コード実装アプローチ

約10分で読めます
文字サイズ:
保守性の高いWebスクレイピング自動化コード実装アプローチ
目次

この記事の要点

  • 帳票・PDF生成から社内回付、押印、保管までの一連の業務を自動化する戦略
  • Webスクレイピングによるデータ収集の効率化と法的・技術的リスク回避
  • AI-OCRと連携したドキュメント処理の自動化と例外処理の最適化

マーケティングの現場において、競合他社の価格調査や企業リストの抽出、トレンドキーワードの収集など、Web上のデータを定期的に取得する業務は多岐にわたります。
手作業でのコピペ作業に限界を感じ、Pythonを用いたデータ収集の自動化に挑戦した経験はないでしょうか。
しかし、見よう見まねで書いたコードは、サイトのわずかな変更で途端に動かなくなるという課題が珍しくありません。

一時的なデータ取得ではなく、実務の運用に耐えうる「保守性の高い(壊れにくい)」スクレイピングコードの実装アプローチを考察していきます。

なぜ「とりあえず動く」スクレイピングでは実務に耐えられないのか

インターネット上の情報は常に変化しており、Webサイトのデザインや構造も頻繁にアップデートされます。そのため、自動化の仕組みには、変化に対する「適応力」と「堅牢性」が求められます。

サイト構造の変化に弱いコードの共通点

多くの初心者が陥りがちなのが、特定のHTML構造に過度に依存したコードを書いてしまうことです。
例えば、ECサイトで価格を取得する際、要素の指定に「上から3番目のdivタグの中にあるpタグ」といった絶対パスを使用していると仮定してみてください。サイトに広告バナーが1つ追加されただけで要素の位置がずれ、エラーが発生してしまいます。

また、クラス名で指定する場合でも、セール期間中にクラス名が price-normal から price-sale-red に変わっただけで、データが取得できなくなるケースが頻発します。
さらに、ページの読み込みを待つために「常に5秒待機する」といった固定の待機時間を設定しているケースも多く見受けられます。ネットワークの状況が悪く読み込みに6秒かかった瞬間にプログラムは強制終了してしまいます。このように「例外的な事象を想定していない設計」が、コードの脆弱性を生み出す大きな要因です。

マーケティング実務で求められる『データの正確性』と『継続性』

自動化の本当の費用対効果は、プログラムを作るまでの時間ではなく、運用時のメンテナンスにかかる時間で決まります。
マーケティング戦略の意思決定に用いるデータは、正確であり、かつ定点観測によって継続的に取得できていることが重要です。一度だけデータを抽出できれば良い単発の作業とは異なり、毎週・毎月といったサイクルで安定して稼働する仕組みが求められます。

途中でプログラムが停止し、一部のデータが欠損した状態では、前週との正確な比較ができません。実務における自動化のゴールは、「データを取得すること」ではなく「運用コストを最小化し、安定したデータパイプラインを構築すること」にあります。

準備:マーケターが最短で構築できるPython実行環境

プログラミングの最初の壁となるのが、手元のPCへの開発環境の構築です。OSの違いやバージョンの競合によって、コードを書く前に挫折してしまうケースが報告されています。

Google Colabを活用した環境構築不要のセットアップ

この課題を解決する有効な手段が、クラウド上でPythonを実行できる「Google Colaboratory(Google Colab)」の活用です。Googleアカウントがあればブラウザ上で即座にコードを実行でき、ローカル環境の差異を気にすることなく学習や実装を進めることができます。チーム内でコードを共有する際も、URLを共有するだけで済むため、属人化を防ぐ効果も期待できます。

必要なライブラリ(Selenium, BeautifulSoup)のインストール

ブラウザを自動操作してデータを取得するためには、主に「Selenium(ブラウザ操作)」と「BeautifulSoup(HTML解析)」というライブラリを使用します。Google Colab上でこれらを動かすためには、バックグラウンドで動作するブラウザ(ヘッドレスブラウザ)のインストールが必要です。

以下のコードは、Google Colab上で最新のSelenium環境をセットアップするための基本モジュールです。最新の仕様やインストール手順の詳細は、Seleniumの公式ドキュメントも併せて確認することをおすすめします。

# 必要なパッケージのインストール(Colab環境用)
!apt-get update
!apt-get install -y chromium-chromedriver
!pip install selenium

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options

# ヘッドレスモード(画面を表示しない設定)のオプション
options = Options()
options.add_argument('--headless=new')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')

# ブラウザの起動
service = Service('/usr/bin/chromedriver')
driver = webdriver.Chrome(service=service, options=options)

# テストとして特定のURLにアクセス
driver.get("https://www.example.com")
print("現在のタイトル:", driver.title)

このコードを実行することで、画面上にはブラウザが表示されなくても、裏側で確実にブラウザが立ち上がり、指定したURLにアクセスしていることが確認できます。ヘッドレスモードは、サーバーのメモリ消費を抑え、高速に処理を行うための標準的な設定です。

【基本実装】要素取得を安定させる「明示的待機」パターン

準備:マーケターが最短で構築できるPython実行環境 - Section Image

データ取得が失敗する最大の原因は、「ページが完全に読み込まれる前に、プログラムがデータを取得しようとして空振りする」ことです。これを防ぐための高度な待機処理を実装します。

『要素が見つからない』エラーを防ぐWebDriverWaitの使い方

固定秒数で待機する処理(time.sleep)は非効率であり、エラーの温床となります。Seleniumの公式ドキュメントでも、要素の読み込みを待つ際は「WebDriverWait(明示的待機)」の使用が推奨されています。

これは、レストランでの注文に例えると分かりやすいでしょう。固定秒数の待機は「料理が3分で運ばれてきても、必ず10分経つまで食べ始めない」という非効率な状態です。一方、明示的待機は「料理が運ばれてきたらすぐに食べ始めるが、もし10分経っても来なければ店員を呼ぶ(タイムアウトを出す)」というスマートな挙動をします。

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 最大10秒間待機する設定
wait = WebDriverWait(driver, 10)

try:
    # idが"product-list"の要素が画面に読み込まれるまで待機
    product_list = wait.until(
        EC.presence_of_element_located((By.ID, "product-list"))
    )
    print("要素の読み込みが完了しました。")
except Exception as e:
    print("時間内に要素が読み込まれませんでした。")

この処理により、ネットワークが速い時は即座に次の処理へ進み、遅い時だけじっと待つという、非常に安定したコードが実現します。

CSSセレクタとXPathの使い分け基準

取得したい要素を指定する方法には、主に「CSSセレクタ」と「XPath」があります。保守性の観点からは、以下のような使い分けが目安になります。

CSSセレクタは、クラス名やIDが付与されている場合に使用します。記述が短く直感的で、デザイン変更の影響を受けにくいのが特徴です。
一方のXPathは、「特定のテキストを含むボタン」など、テキストベースで要素を探したい場合や、複雑な階層を遡る必要がある場合に使用します。状況に応じて使い分けることで、壊れにくい指定が可能になります。

【応用実装】ページ遷移と無限スクロールへの対応手法

【基本実装】要素取得を安定させる「明示的待機」パターン - Section Image

一覧ページからデータを取得する際、1ページ目だけでなく、2ページ目、3ページ目と順番にデータを取得していく処理が必要です。

「次へ」ボタンを自動クリックし続けるループ処理

複数ページにまたがるデータを取得する場合、「次へ」ボタンがクリック可能になるまで待機し、クリックを実行するループ処理を構築します。

import time

while True:
    try:
        # 現在のページのデータを取得する処理をここに記述
        # ...
        
        # 「次へ」ボタンがクリック可能になるまで待機
        next_button = wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, ".next-page-btn"))
        )
        next_button.click()
        
        # サーバーへの負荷を下げるための最低限の待機
        time.sleep(2)
        
    except Exception:
        # 「次へ」ボタンが見つからなくなった(最終ページに到達した)場合、ループを抜ける
        print("全ページの取得が完了しました。")
        break

このループ構造により、ページ数が変動しても自動的に最終ページまで処理を完遂させることができます。

JavaScriptによるスクロール連動型サイトのデータ取得

最近のECサイトやSNSでは、画面を下へスクロールするたびに新しいデータが読み込まれる「無限スクロール」が採用されているケースが多々あります。また、画面遷移なしでコンテンツが動的に書き換わるサイトも増えています。
これらの場合、SeleniumからJavaScriptを実行して、ブラウザを強制的に一番下までスクロールさせるテクニックが有効です。

# 画面の最下部までスクロールするJavaScriptを実行
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

これをループの中に組み込み、ページの高さが変化しなくなるまでスクロールを繰り返すことで、動的に読み込まれるコンテンツをすべて展開させることが可能です。

エラーハンドリング:途中で止まらない「リトライ・ロジック」の組み込み

大量のデータを取得する際、1,000件中の1件のデータ構造がイレギュラーだったために、プログラム全体がエラーで停止してしまうのは最悪のシナリオです。

Try-Except構文による例外の受け流しとログ記録

保守性の高いコードには、必ず「例外処理(エラーハンドリング)」が組み込まれています。エラーが発生してもプログラムを停止させず、その要素だけをスキップして「何件目でどんなエラーが起きたか」を記録する仕組みです。

results = []
items = driver.find_elements(By.CSS_SELECTOR, ".item-card")

for index, item in enumerate(items):
    try:
        # 商品名と価格の取得を試みる
        name = item.find_element(By.CSS_SELECTOR, ".item-name").text
        price = item.find_element(By.CSS_SELECTOR, ".item-price").text
        results.append({"name": name, "price": price})
        
    except Exception as e:
        # エラーが起きてもスキップし、ログだけを残す
        print(f"{index + 1}件目のデータ取得に失敗しました。詳細: {e}")
        results.append({"name": "取得エラー", "price": "-"})
        continue

この実装により、一部のデータに欠損があっても、業務全体がストップする事態を回避できます。後からログを確認し、失敗した箇所だけを手動で補完するか、コードを修正すれば済むからです。

ネットワーク遮断時に自動で再開する仕組み

クラウド環境や不安定な通信環境では、一時的なネットワークエラーが起こり得ます。一度のエラーで諦めるのではなく、「エラーが起きたら数秒待ってからもう一度試す」といったリトライ・ロジックを組み込むことで、自動化の安定性は飛躍的に向上します。

法的・倫理的リスクを回避する「紳士的なスクレイピング」の作法

技術的な堅牢性と同じくらい重要なのが、法令遵守と倫理的な配慮です。スクレイピングは、対象となるWebサイトのサーバーリソースを利用して行う行為であるため、マナーを守らない運用はトラブルに発展するリスクがあります。

robots.txtの確認方法とアクセス間隔の設計

自動化を実装する前に、必ず対象サイトの利用規約を確認し、データ収集が禁止されていないかをチェックする必要があります。また、サイトのルートディレクトリにある robots.txt(例:https://example.com/robots.txt)を確認し、クローラーのアクセスが許可されているディレクトリかどうかをプログラム設計の段階で把握しておくことが不可欠です。
日本の著作権法においては「情報解析のための複製」が一定の条件下で認められていますが、これはあくまで著作権に関する規定であり、サーバーに過度な負荷をかける行為や、利用規約違反を正当化するものではない点に留意が必要です。

サーバー負荷を考慮した『秒間1アクセス』の徹底

プログラムによるアクセスは、人間がブラウザを操作するよりも圧倒的に高速です。連続して大量のアクセスを行うと、相手のサーバーに過度な負荷をかけ、最悪の場合はアクセス制限を受ける可能性があります。
これを防ぐための鉄則が「アクセスとアクセスの間に必ずスリープ(休止時間)を入れる」ことです。

import time

for url in url_list:
    driver.get(url)
    # データ取得処理
    # ...
    
    # 相手サーバーへの配慮として、必ず1〜2秒の待機を入れる
    time.sleep(1.5)

待機処理に関する解説で「固定秒数の待機は非効率」と述べましたが、相手サーバーへのアクセス間隔を空けるための待機は必須の作法です。自分の処理を待つ時は明示的待機を使い、相手への配慮としては固定秒数の待機を使う、という使い分けがプロフェッショナルな実装アプローチと言えます。

まとめ

最大10秒間待機する設定 - Section Image 3

Web上のデータ収集の自動化は、マーケティング業務の効率を劇的に引き上げる強力な武器となります。単に「データを取得するだけのコード」では、サイトの変更や予期せぬエラーによってすぐに運用が破綻してしまいます。

明示的待機、エラーハンドリングの組み込み、そして倫理的なアクセス間隔の設計を取り入れることで、実務に耐えうる保守性の高いデータパイプラインを構築することが可能です。

自動化技術やツールのトレンドは日々進化しています。最新のライブラリの仕様変更や、より効率的なデータ収集のアーキテクチャを継続的にキャッチアップしていくためには、専門的な知見を定期的にインプットする環境を整えることが重要です。最新動向やより実践的なユースケースを深く学ぶには、ニュースレター等のメールマガジンによる継続的な情報収集も有効な手段となります。自社の業務プロセスを一段階引き上げるために、ぜひ実践的な学習を続けてみてください。

保守性の高いWebスクレイピング自動化コード実装アプローチ - Conclusion Image

参考文献

  1. https://qiita.com/ishisaka/items/26771ec905fc9a03f985
  2. https://docs.databricks.com/gcp/ja/repos/get-access-tokens-from-git-provider
  3. https://docs.cloud.google.com/dataform/docs/connect-repository?hl=ja
  4. https://notepm.jp/blog/25434
  5. https://qiita.com/ishisaka/items/6e50d0ee5585f2820c9f
  6. https://www.itreview.jp/categories/ci-cd
  7. https://learn.microsoft.com/ja-jp/azure/data-factory/source-control
  8. https://www.trendmicro.com/ja_jp/research/26/d/weaponizing-trust-claude-code-lures-and-github-release-payloads.html
  9. https://generative-ai.sejuku.net/blog/16943/

コメント

コメントは1週間で消えます
コメントを読み込み中...