こんにちは、小澤です。
前回は、取得したデータをCSVやExcelとして保存する方法を紹介しました。スクレイピングで取り出した情報は、画面に表示して終わりではなく、あとから見返せる形で保存しておくことで、分析や共有に使えるデータになります。pandasを使えば、取得した一覧データをDataFrameにまとめ、CSVやExcelに出力できることも確認しました。
今回は、その処理をさらに一歩進めて、スクレイピングを定期的に実行する方法について解説します。毎朝ニュースを取得する、毎時価格を確認する、1日1回だけ更新情報を保存する、といった処理は、人が手で実行するよりも、決まった時刻に自動で動かすほうが実務では扱いやすくなります。
スクレイピングは「取得する」だけでなく、「保存する」「整形する」「自動化する」「活用する」までを含めて考えると、業務で使える仕組みに近づきます。今回は、自動化の入口として、cronやWindowsタスクスケジューラ、ログ出力、エラー時の考え方を整理していきましょう。
定期実行とは何か
定期実行とは、あらかじめ決めた時刻や間隔でプログラムを自動的に実行することです。たとえば、毎日午前9時にスクリプトを起動する、1時間に1回だけデータを取得する、毎週月曜日に集計処理を行う、といった使い方があります。
スクレイピングでは、データが時間とともに変化することが多いため、定期実行との相性がよいです。ニュース記事、商品価格、在庫状況、イベント情報などは、変化を追いかけることで価値が出てきます。
ただし、定期実行にしたからといって、やみくもに何度もアクセスしてよいわけではありません。取得するデータの性質に合わせて、1時間に1回で十分なのか、1日1回でよいのかを最初に考えます。
cronとWindowsタスクスケジューラ
MacやLinuxでは、定期実行の代表的な仕組みとしてcronがあります。cronは、指定したスケジュールに従ってコマンドを実行するための仕組みです。
たとえば、毎日午前9時にPythonスクリプトを実行したい場合、cronでは次のような設定になります。
| 0 9 * * * /usr/bin/python3 /path/to/scraping.py |
左側の「0 9 * * *」が実行タイミングを表しています。これは「毎日9時0分」という意味です。その後ろに、実行したいコマンドを書きます。実際に使う場合は、Pythonのパスやスクリプトのパスを、自分の環境に合わせて指定します。
Windowsでは、タスクスケジューラを使うのが一般的です。GUIから「いつ」「何を実行するか」を設定し、実行するプログラムとしてPythonを選び、引数としてスクリプトのパスを渡します。
cronもタスクスケジューラも、考え方は同じです。手でコマンドを打つ代わりに、OSに実行タイミングを覚えさせる仕組みだと理解するとよいでしょう。
定期実行しやすいスクリプトにする
定期実行するスクリプトは、「実行したら最後まで自動で完了する」形にしておきます。途中で入力を求めたり、結果を画面で確認しないと進まなかったりすると、定期実行には向きません。
ここでは、これまで扱ってきたrequests、BeautifulSoup、pandasを使って、架空サイトから記事一覧を取得し、CSVに保存する例を考えます。
| import logging import pandas as pd import requests from bs4 import BeautifulSoup logging.basicConfig( filename=”scraping.log”, level=logging.INFO ) def main(): url = “https://example.com” response = requests.get(url, timeout=10) response.raise_for_status() soup = BeautifulSoup(response.text, “html.parser”) rows = [] for item in soup.find_all(“article”): title_tag = item.find(“h2”) link_tag = item.find(“a”) title = title_tag.text.strip() if title_tag else “” link = link_tag.get(“href”) if link_tag else “” rows.append({ “タイトル”: title, “URL”: link }) df = pd.DataFrame(rows) df.to_csv( “articles.csv”, index=False, encoding=”utf-8-sig” ) logging.info(“取得件数: %s”, len(df)) try: main() except Exception as e: logging.exception( “エラーが発生しました: %s”, e ) |
このコードでは、取得したデータをCSVに保存するだけでなく、ログも出力しています。定期実行では、プログラムが人の見ていないところで動くため、「いつ動いたのか」「何件取得できたのか」「エラーが起きたのか」を記録しておくことが重要です。
ログを残す意味
ログは、定期実行を運用するうえで欠かせません。手動実行であればエラーにすぐ気づけますが、cronやタスクスケジューラで実行している場合、失敗しても画面には何も表示されません。
そこで、loggingを使って実行結果をファイルに残します。正常に取得できた件数、処理を開始した時刻、エラーの内容などを記録しておけば、あとから原因を確認できます。
実務では、ログを読むだけで「プログラムが動いていない」のか、「Webサイトにアクセスできなかった」のか、「HTML構造が変わって取得できなくなった」のかを切り分けられるようにしておくと便利です。
エラー時の対処を考えておく
スクレイピングでは、エラーが起きることを前提にしておく必要があります。ネットワークが一時的に不安定になることもありますし、対象ページの構造が変わることもあります。
そのため、requests.get()にはtimeoutを指定しておくとよいです。いつまでも応答を待ち続けると、定期実行の処理が詰まってしまう可能性があります。また、response.raise_for_status()を使うと、404や500などのHTTPエラーを検出しやすくなります。
さらに、tryとexceptで全体を囲み、エラー内容をログに残しておきます。エラーを完全になくすことは難しいですが、起きたときに原因を調べられるようにしておくことが大切です。
毎日・毎時データを取得する考え方
毎日または毎時データを取得する場合、保存方法にも注意が必要です。同じCSVに上書きするのか、日付ごとにファイルを分けるのか、過去データを追記していくのかで、あとからできる分析が変わります。
価格変動を追いたいなら、取得日時と価格を毎回追記します。一方、最新の一覧だけを見たい場合は、毎回上書きでも十分です。目的が「最新状態の確認」なのか「変化の履歴を分析する」なのかを決めておくと、保存形式を選びやすくなります。
定期実行では、同じデータを何度も保存して重複が増えることもあります。URLやIDなど、一意に識別できる項目がある場合は、それを使って重複を取り除く処理を入れると実用的です。
アクセス間隔とマナー
スクレイピングを自動化するときに、最も注意したいのがアクセス負荷です。プログラムで短時間に大量に実行すると、相手のサーバーに負担をかけてしまいます。
実在サイトを対象にする場合は、必ず利用規約やrobots.txtを確認し、スクレイピングが禁止されていないか、アクセス頻度に制限がないかを確認しましょう。公開されているページであっても、自由に大量取得してよいとは限りません。
また、ページネーションで複数ページを巡回する場合は、time.sleep()で待機時間を入れる、必要なページ数だけ取得する、といった配慮が必要です。定期実行は便利ですが、便利だからこそ、控えめに使う姿勢が重要です。
今回のまとめ
今回は、スクレイピングを定期実行して自動化する考え方を紹介しました。ポイントは次のとおりです。
- 定期実行を使うと、毎日・毎時のデータ取得を自動化できる
- MacやLinuxではcron、Windowsではタスクスケジューラを使う
- 定期実行するスクリプトは、入力なしで最後まで動く形にしておく
- ログを残すことで、実行状況やエラー原因をあとから確認できる
- timeoutや例外処理を入れ、失敗する前提で設計する
- アクセス間隔、利用規約、robots.txtを確認し、相手サイトへの負荷に配慮する
スクレイピングは、コードを書いて1回実行できれば終わりというものではありません。保存し、整形し、定期的に取得し、必要な人が使える形にすることで、業務の中で役に立つ仕組みになります。
次回は、JavaScriptで動的に生成されるページの扱いについて紹介します。requestsとBeautifulSoupだけでは取得できないページがなぜ存在するのかを確認しながら、Seleniumなどのブラウザ操作ツールを使う考え方につなげていきましょう。次回もお楽しみに。
