bulk-url-checker について
bulk-url-checkerは、大量のURLチェックをBulk URL Checker APIに送信するPythonクライアントとコマンドラインツールです。ステータスコード、リダイレクト、リンク切れの結果を返し、長時間のジョブ管理や安全な再試行にも対応します。
主な機能
- 01URLの一括チェックとステータスコード取得
- 02リダイレクトチェーンとリンク切れの確認
- 03ジョブの送信、ポーリング、ページ取得
- 04冪等性を備えた再試行と署名付きWebhook
- 05CSV、JSON、JSONL形式のCLI出力
活用シーン
- 01大量のURLリストからリンク切れを確認
- 02長時間のチェックを再開または監視
- 03チェック結果をレポートとして出力
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://mcp.bulkurlchecker.com/mcpclaude mcp add --transport http carlosofscience-bulk-url-checker https://mcp.bulkurlchecker.com/mcp{"mcpServers":{"carlosofscience-bulk-url-checker":{"type":"http","url":"https://mcp.bulkurlchecker.com/mcp"}}}Cursor で開く{"servers":{"carlosofscience-bulk-url-checker":{"type":"http","url":"https://mcp.bulkurlchecker.com/mcp"}}}VS Code で開く{"mcpServers":{"carlosofscience-bulk-url-checker":{"type":"http","url":"https://mcp.bulkurlchecker.com/mcp"}}}{"mcpServers":{"carlosofscience-bulk-url-checker":{"serverUrl":"https://mcp.bulkurlchecker.com/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
5| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| urls | array | はい | チェックする URL。各 URL には http:// または https:// スキームを含めてください。 |
詳細
bulkurlchecker
Bulk URL Checker API 用の Python クライアントです。
通常なら構築に2週間かかるプロキシローテーション、レート制限、ソフト404検出、再試行分類器を省けます。 数千件の URL を送信すると、ステータスコード、リダイレクトチェーン、リンク切れの検出結果が Python オブジェクトとして返されます。住宅用プロキシとドメインごとのスロットリングを備えた、マネージドクラウドサービスを利用しています。
インストール
pip install bulkurlchecker
5行の例
from bulkurlchecker import Client
client = Client(api_key="uck_live_...")
results = client.check_urls(["https://example.com", "https://example.org"])
for r in results.results:
print(r.url, r.status_code, "BROKEN" if r.is_broken else "ok")
API キーは https://app.bulkurlchecker.com/dashboard/api-keys で取得できます。最初の300件の URL は無料で、カード情報も不要です。
取得できるデータ
results = client.check_urls(urls)
results.status # 'completed' | 'paused' | 'failed' | 'cancelled'
results.timed_out # True if the wait deadline passed (job still running)
results.total_urls # how many URLs the engine accepted
results.completed_urls # how many it finished checking
results.duplicates_removed
results.invalid_urls_rejected
for r in results.results:
r.url # the original URL you submitted
r.final_url # after redirects
r.status_code # 200, 301, 404, 429, 500, ...
r.redirect_chain # list of intermediate URLs
r.is_broken # True if the engine flagged this as broken
r.is_soft_404 # True if 200 OK but page content says "not found"
r.response_time_ms
# Convenience properties:
results.broken # list of URLResult where is_broken == True
results.soft_404s # list where is_soft_404 == True
コマンドラインの使用方法
bulkurlchecker コマンドを使うには、[cli] エクストラを指定してインストールします。
pip install 'bulkurlchecker[cli]'
export BULKURLCHECKER_API_KEY=uck_live_...
# One URL per line in urls.txt → CSV on stdout
bulkurlchecker check urls.txt > report.csv
# Pipe from anywhere
sitemap-extractor mydomain.com | bulkurlchecker check - --output jsonl > report.jsonl
# Only show broken URLs, ad-hoc input
bulkurlchecker check --urls "https://example.com,https://example.org" --only-broken
# Two-step (submit, then poll & fetch later)
JOB=$(bulkurlchecker submit urls.txt)
bulkurlchecker status "$JOB"
bulkurlchecker results "$JOB" --output csv > report.csv
出力形式は csv(デフォルト)、json、jsonl です。すべてのフラグについては bulkurlchecker check --help を実行してください。
大規模なジョブ:送信してポーリングする
check_urls() はサーバー側で最大15分間ブロックします。待機がタイムアウトするようなリストには、次の2段階の方法を使ってください。
job = client.submit(my_500k_urls)
print(f"Submitted {job.job_id}, {job.total_urls} URLs queued")
# Poll explicitly, or use the convenience method
done = client.wait_until_done(job.job_id, timeout=3600)
# Stream results in pages
for batch in client.iter_results(job.job_id, page_size=1000):
for r in batch:
if r.is_broken:
print(r.url, r.status_code)
idempotency_key による安全な再試行
ネットワーク障害時の再試行を安全にするには、submit() または check_urls() に冪等性キーを渡します。サーバーはレスポンスを24時間キャッシュします。同じキーと同じ本文で再試行すると、重複したジョブを作成せず、元の結果が返されます。
import uuid
key = str(uuid.uuid4()) # generate once per logical request
# First call: creates a new job.
job = client.submit(urls, idempotency_key=key)
# Network blip, no clean response received? Just retry with the same
# key -- you'll get the SAME job summary back, no duplicate submission.
same_job = client.submit(urls, idempotency_key=key)
# job.job_id == same_job.job_id
同じ idempotency_key に異なる urls を指定すると、409 Conflict(ValidationError として発生)が返されます。キーを新しいペイロードに使い回すクライアントのバグを、誤ったキャッシュ結果にひそかに対応付けるのではなく、明確に検出できます。
Webhook の受信
ジョブが完了すると、署名付きペイロードを登録済みのエンドポイントに POST します。本文を信頼する前に署名を検証してください。そうしないと、エンドポイント URL を知っている人なら誰でも偽のイベントを送信できます。
from flask import Flask, request
from bulkurlchecker import verify_signature, InvalidSignatureError
SECRET = os.environ["MY_WEBHOOK_SECRET"] # the signing_secret we showed once
app = Flask(__name__)
@app.route("/webhook/bulkurlchecker", methods=["POST"])
def webhook():
try:
verify_signature(
request.get_data(), # RAW bytes — not request.get_json()
request.headers.get("Bulkurlchecker-Signature", ""),
SECRET,
)
except InvalidSignatureError:
return "", 401
event = request.get_json()
if event["type"] == "job.completed":
job_id = event["data"]["job_id"]
# ... fetch results, update your DB, ping Slack, etc ...
return "", 200
エンドポイントの登録とシークレットの取得は https://app.bulkurlchecker.com/dashboard/webhooks(または POST /api/v2/webhooks/endpoints)から行えます。
verify_signature() はリプレイ攻撃を防ぐため、デフォルトで5分のタイムスタンプ許容範囲を適用します。tolerance_seconds= で調整できます。
エラー処理
すべてのエラーは BulkURLCheckerError を継承します。失敗の種類に応じて処理を分岐する場合は、具体的なサブクラスを捕捉してください。
from bulkurlchecker import (
Client,
BulkURLCheckerError,
AuthenticationError,
RateLimitError,
QuotaError,
ValidationError,
)
try:
results = client.check_urls(urls)
except QuotaError as e:
print(f"Out of credits. Top up at https://app.bulkurlchecker.com/billing")
except RateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after}s.")
except AuthenticationError:
print("API key rejected — check it's not revoked.")
except ValidationError as e:
print(f"Bad request: {e}") # bad URLs, too many URLs, etc.
except BulkURLCheckerError as e:
print(f"Other error: {e} (request_id={e.request_id})")
各エラーには status_code、code(サーバーの機械可読な文字列)、request_id(サポートへの問い合わせ用)、および details(サーバーから提供される場合)が含まれます。
httpx + asyncio で独自のチェッカーを書く代わりに、これを使う理由
正直に言うと、500件以下の URL なら必要ありません。標準の requests/httpx ツールチェーンで十分に対応できます。
規模が大きくなると、次のような問題に直面します。
| 問題 | 自作する場合 | この SDK |
|---|---|---|
| 並行処理 | asyncio + 慎重なセマフォ管理 | 対応済み |
| 住宅用 IP 間のプロキシローテーション | Webshare / Bright Data の月額90ドル以上のサブスクリプション + 独自コード | 対応済み |
| ドメインごとのレート制限(1つのホストに負荷をかけないため) | 自分で実装 | 対応済み |
| 本物の403と「ブロックされた」403の見分け | 推測して試す | 対応済み |
| ソフト404(200 OK + 「見つかりません」という本文)の検出 | テンプレートごとに正規表現/ヒューリスティックを用意 | 対応済み |
| 再試行の分類(一時的か永続的か) | 何週間もかけて調整 | 対応済み |
| 長時間実行するジョブの状態管理(クラッシュ後の再開) | Redis + キュー + ワーカーのインフラ | 対応済み |
| エンジニアの作業時間、1〜4週目 | $$$ | 不要。今日からリリース可能 |
httpx + プロキシローテーションに週末を費やしたことがあるなら、言いたいことはおわかりでしょう。
料金プラン
- 最初の1か月は無料です: Starterプランでは、クレジットカード不要でURLチェックを15,000件ご利用いただけます。 APIまたはSDKの連携が初めて正常に実行されると、トライアルはProプランの1か月分に拡張されます:URLチェック50,000件。アカウントごとに1回限りです。
- その後: すべてのアカウントに、毎月URLチェック300件が含まれます。
- Starter: 月額$9または年額$90、月間URL数15,000件
- Pro: 月額$29または年額$290、月間URL数50,000件
- Agency: 月額$99または年額$990、月間URL数200,000件
メール、Slack、Webhookによるアラート付きの定期チェックは、すべてのプランに含まれます。買い切りのクレジットパックは3,000件分が$5からご利用いただけます。パックのクレジットは繰り越されます。現在の料金:https://bulkurlchecker.com/#pricing
リンク
安定性
SDKはセマンティックバージョニングに従います。バージョンが0.xの間は、マイナーリリースで破壊的変更が入る場合があります(変更は必ずCHANGELOG.mdに記載します)。バージョン1.0以降は、メジャーバージョンを固定して安心してご利用いただけます。
ライセンス
MITです。LICENSEをご覧ください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。