スクレイピングの「やってはいけない」を学ぶ意義
Webスクレイピングは強力なデータ収集手段ですが、実装が雑だとサーバーに迷惑をかけたり、自社のIPがブロックされたり、最悪の場合は法的リスクを生じさせることもあります。弊社はEC情報収集・競合分析などでスクレイピングを多数実装してきた経験から、よくある失敗パターンとその解決策をまとめます。
アンチパターン1:インターバルなしで連続リクエスト
最もよくある失敗です。ループで次々とリクエストを送ると、対象サーバーに過大な負荷をかけます。
// NG:何の待機もなくリクエストを連打
for (const url of urls) {
const data = await fetch(url);
// ...
}
// OK:ランダムな待機時間を入れる
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
for (const url of urls) {
const data = await fetch(url);
// ...
const wait = 1000 + Math.random() * 2000; // 1〜3秒
await sleep(wait);
}
人間がブラウザを操作するときのリズムを模倣することが、サーバーへの配慮であり、ブロック回避の基本でもあります。
アンチパターン2:エラーハンドリングを省略する
1件のリクエストが失敗しただけでスクリプト全体がクラッシュするのは実用上困ります。
// NG:エラーが起きると全体が止まる
for (const url of urls) {
const response = await fetch(url);
const data = await response.json();
results.push(data);
}
// OK:失敗URLをリストに記録して後から再試行
const failedUrls = [];
for (const url of urls) {
try {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
results.push(await response.json());
} catch (err) {
console.error(`Failed: ${url}`, err.message);
failedUrls.push(url);
}
}
// 失敗分を再試行
for (const url of failedUrls) {
// ...
}
アンチパターン3:User-Agentを設定しない
デフォルトの node-fetch や requests ライブラリのUser-AgentはBot判定されやすいです。
# NG:デフォルトUser-Agentのまま
import requests
response = requests.get(url)
# OK:実際のブラウザのUser-Agentを設定
headers = {
'User-Agent': (
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/124.0.0.0 Safari/537.36'
),
'Accept-Language': 'ja-JP,ja;q=0.9,en-US;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Referer': 'https://www.google.com/',
}
response = requests.get(url, headers=headers, timeout=15)
アンチパターン4:セッションを使い回さない
ログインが必要なサイトで毎回ログイン処理をするのは無駄であり、不審なアクセスパターンとして検知されることもあります。
# OK:セッションを使い回す
session = requests.Session()
session.headers.update(headers)
# 一度ログインしてCookieを維持
session.post('https://example.com/login', data={
'email': os.environ['EMAIL'],
'password': os.environ['PASSWORD'],
})
# 以降のリクエストでCookieが自動送信される
page1 = session.get('https://example.com/data/1')
page2 = session.get('https://example.com/data/2')
アンチパターン5:robots.txtを無視する
robots.txt はWebクローラーへの指示書です。法的拘束力はないケースが多いですが、ビジネス上のマナーとして守ることが重要です。
from urllib.robotparser import RobotFileParser
def can_scrape(base_url: str, target_url: str) -> bool:
rp = RobotFileParser()
rp.set_url(f"{base_url}/robots.txt")
rp.read()
return rp.can_fetch('*', target_url)
if can_scrape('https://example.com', url):
# スクレイピング実行
pass
else:
print(f"robots.txtにより禁止: {url}")
アンチパターン6:個人情報・著作物を無断で収集・利用する
スクレイピングで取得したデータを商用利用する場合、利用規約・著作権・個人情報保護法への配慮が必要です。
- 利用規約の確認:スクレイピングを禁止しているサービスへのアクセスは利用規約違反になります
- 個人情報の扱い:氏名・メールアドレスなど個人を識別できる情報は収集・保持しないこと
- 著作物の扱い:文章・画像など著作物をそのまま転載することは著作権侵害になる可能性があります
弊社のスクレイピング実装方針
弊社では以下の方針でスクレイピングを実装しています。
- リクエスト間隔:最低1秒、推奨2〜3秒のランダムウェイト
- robots.txt遵守:事前にチェックして禁止パスには触れない
- User-Agent設定:実際のブラウザに準拠したヘッダーを設定
- エラーハンドリング:失敗URLのリスト管理と段階的再試行
- 対象サイトの利用規約確認:収集前に必ず確認
- 収集データの適正管理:個人情報は収集せず、収集データの目的外利用をしない
まとめ
スクレイピングは適切に実装すれば強力なデータ収集ツールですが、マナーと技術的配慮を怠ると様々な問題が生じます。弊社ではEC価格監視・競合分析などのスクレイピングシステムを倫理的かつ安定的に開発・運用しています。
データ収集・自動化ツールの開発についてはお気軽にご相談ください。