google-maps-scraper について
ローカルの Google Maps Scraper エンジンを操作し、店舗情報を収集して営業リードを整えるスキルです。ジョブの作成、結果の取得、連絡先フィールドの選別を案内します。
主な機能
- 01非同期スクレイピングジョブの作成と監視
- 021つのジョブで複数キーワードを検索
- 03店舗サイトからメールアドレスを抽出
- 04任意でソーシャルプロフィールを収集
- 05選択した項目を CSV または JSON に出力
活用シーン
- 01地域の店舗リード一覧の作成
- 02営業連絡先の収集
- 03グリッド検索による市内調査
- 04任意のソーシャルプロフィール取得
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mahanaicoach/ google-maps-scraper-kit --skill google-maps-scraperインストール後、Claude Code で/google-maps-scraperを入力して読み込まれたか確認します。
詳細
Google Maps Scraper
地域のビジネスタイプを指定すると、ローカルエンジンのジョブ API を使って、見込み客の情報を整理された行データに変換します。
基本的な仕組み
エンジン(gosom/google-maps-scraper)は、REST API(http://localhost:8080)を備えたローカルの Docker コンテナーとして実行されます。認証機能はないため、localhost にバインドしたままにしてください。スクレイピングは非同期ジョブとして実行されます。ジョブを作成し、完了するまでポーリングしてから、CSV をダウンロードします。1 つのジョブで複数のキーワードを処理できます。各結果には、最大 34 個の生データフィールドが含まれます。
ステップ 0:エンジンが実行中か確認する
curl -s http://localhost:8080/api/v1/jobs >/dev/null 2>&1 && echo UP || echo DOWN
DOWN の場合は、キットのルートから docker compose up -d を実行し、約 10 秒待ってから再試行します。Docker がインストールされていない場合は、ユーザーに SETUP.md を案内してください。
ステップ 1:ジョブを作成する(POST /api/v1/jobs)
必須フィールド。指定しないと、API は 422 を返します:
keywords:検索文字列の配列です。各キーワードに地域を含めてください。例:"plumbers in Denver CO"。lat、lon:都市の座標を表す文字列です。例:"39.7392"、"-104.9903"。max_time:ジョブの制限時間を秒単位で指定する整数です。例:300。API 内部ではナノ秒として保存されますが、必ず秒単位で指定してください。
推奨フィールド:
depth(デフォルトは 10):スクロールする量、つまりキーワードごとのおおよその掲載件数です。まずは5から始めてください。lang"en"、zoom15(都市レベル)、radius10000(メートル)、fast_modefalse。emailtrue:キットではデフォルトで有効です。 メールアドレスは見込み客の情報の中でも特に価値があります。エンジンはメールアドレスを探すために各ビジネスのウェブサイトを確認するため、処理に少し時間がかかります。メールアドレスを取得せず、意図的に高速で実行する場合に限り、falseに設定してください。
curl -s -X POST http://localhost:8080/api/v1/jobs \
-H "Content-Type: application/json" \
-d '{"name":"job","keywords":["coffee shops in Austin TX"],"lang":"en","zoom":15,
"lat":"30.2672","lon":"-97.7431","fast_mode":false,"radius":10000,
"depth":5,"email":true,"max_time":300}'
# → {"id":"<uuid>"} (HTTP 201; note: lowercase "id")
スクレイピングのたびに、次の 2 点に対応してください:
- メールアドレスはデフォルトで有効(
email:true)にします。ユーザーが高速実行を希望する場合に限り、無効にしてください。- ソーシャルプロフィールについては、事前に確認してください。 ジョブを作成する前に、Instagram、Facebook、LinkedIn のプロフィールも必要かどうかをユーザーに一度確認します(下記の「ソーシャルプロフィール」を参照)。確認を省略してはいけません。
ステップ 2:完了するまでポーリングする(GET /api/v1/jobs/{id})
レスポンスのフィールドは "Status"(S は大文字)です。ステータスは working から ok(成功)または failed に変わります。
ハーネスのルール: Bash ツールでは、フォアグラウンドの
sleepが処理をブロックします。ポーリングループは Bash コマンドをバックグラウンドで実行し(run_in_background: true)、通知が届いたら出力ファイルを読み取ってください。フォアグラウンドのsleepを使ってポーリングしてはいけません。
バックグラウンドで実行するポーリング用スニペットです。値は安全に解析され、$ を基準にせず、閉じる引用符までを照合します。
ID="<uuid>"
for i in $(seq 1 40); do
S=$(curl -s "http://localhost:8080/api/v1/jobs/$ID" | grep -oE '"Status":"[^"]*"' | head -1 | cut -d'"' -f4)
echo "status=$S"
[ "$S" = ok ] && { echo DONE; break; }
[ "$S" = failed ] && { echo FAILED; break; }
sleep 15
done
ステップ 3:ダウンロードして解析する(GET /api/v1/jobs/{id}/download)
curl -s "http://localhost:8080/api/v1/jobs/$ID/download" -o results.csv
CSV の列(34 個):input_id, link, title, category, address, open_hours, popular_times, website, phone, plus_code, review_count, review_rating, reviews_per_rating, latitude, longitude, cid, status, descriptions, reviews_link, thumbnail, timezone, price_range, data_id, place_id, images, reservations, order_online, menu, owner, complete_address, about, user_reviews, user_reviews_extended, emails
デフォルトでは、見込み客の情報として 8 個のフィールドだけを返す
生の CSV には 34 列あり、その大半は営業活動には不要です。デフォルトでは、見込み客への連絡や評価に使う 8 個のフィールドだけを返し、それ以外は除外してください:
title(名前)、phone、emails、website、category、address、review_rating、review_count
デフォルトでは除外します。 ユーザーから明示的に求められた場合に限り、次のフィールドを表示してください:latitude/longitude(営業活動には使いません)、link、plus_code、cid、data_id、place_id、open_hours、popular_times、reviews_per_rating、reviews_link、thumbnail、images、timezone、price_range、status、input_id、complete_address、reservations、order_online、menu、owner、about、descriptions、user_reviews、user_reviews_extended。
scripts/scrape.py は、見込み客の情報として 8 個のフィールドだけを返します。すべての列を保持するには --full を、任意の列を選択するには --fields "a,b,c" を使用してください。デフォルトでは CSV ファイル(results-<id>.csv)を保存します。JSON を出力するには --json を指定してください。API を直接呼び出す場合は、表示する前に必ず見込み客の情報に該当するフィールドだけに絞り込んでください。34 列すべてを含む行をユーザーにそのまま出力してはいけません。
ソーシャルプロフィール:必ずユーザーに確認する(Instagram、Facebook、LinkedIn)
Google Maps にはソーシャルリンクがないため、ソーシャル情報の取得は追加の拡充作業です。各ビジネスの website にアクセスし、正規表現で Instagram、Facebook、LinkedIn の URL を抽出します。**スクレイピングを始める前に、ユーザーがすでに希望を伝えていない限り、ソーシャル情報も必要か一度確認してください。**希望する場合は、スクリプトを使ってください: python3 scripts/scrape.py … --socials。
- **トークンコスト。ソーシャル情報を求められたら、次のように伝えてください:**抽出処理自体にかかる LLM トークンは 0 です。スクリプト内で通常の HTTP と正規表現を使っているためです。取得結果をチャットに読み込む場合に限り、ビジネス 1 件あたり 約 40~50 トークンがあなたのコンテキストに追加されます。たとえば、見込み客 50 件で約 2,000 トークン増えます。ファイルをディスクに保存してサンプルを見せるなら、わずかな量です。ファイルを保存し、数行を表示してください。
- **各ウェブサイトに WebFetch で個別にアクセスしてソーシャル情報を探さないでください。**すべてのページをコンテキストに読み込むことになり、数千トークンかかります。スクリプトなら無料で処理できるため、常に
--socialsを優先してください。 - ソーシャル情報の取得はオプトインで、時間がかかります(ビジネスごとに HTTP リクエストを 1 回実行します)。網羅率は部分的です(約 40~70%)。サイト上でソーシャルアカウントへのリンクを掲載しているビジネスのみ対象となり、ウェブサイトがなければソーシャル情報もありません。ユーザーが 100%の網羅率を期待している場合は、その旨を伝えてください。
ショートカット。よくあるケースでは、こちらを優先してください:
- キーワード 1 つの場合:
scripts/scrape.sh "<keyword>" <lat> <lon> [depth](bash)を使うと、ジョブの作成、ポーリング、ダウンロードを一括で行えます。 - 自動ジオコーディング(座標なし):
python3 scripts/scrape.py "<keyword>" --city "<City, ST>" [--depth N]で、OpenStreetMap Nominatim を使って緯度・経度を取得します。都市を自分でジオコーディングし、座標を渡すこともできます。 メールアドレスはデフォルトで取得されます(--no-emailを指定するとスキップします)。ユーザーがソーシャル情報を求めた場合は、--socialsを追加してください。 - 一括処理(多数のキーワードを 1 つのジョブで処理):
python3 scripts/scrape.py --keywords-file <file> --city "<City, ST>"。 API はkeywords配列を受け取るため、多数のジョブを実行するのではなく、すべての語句を 1 つのジョブにまとめてください。proxiesの設定など、カスタムのジョブ本文が必要な場合に限り、手動の curl フローを使ってください。
**都市全体の検索:**ユーザーが都市の「すべて」「全件」「全域」を求めている場合、または検索結果が約 120 行(Google の検索ごとの上限)になった場合は、python3 scripts/scrape.py "<keyword>" --city "<City, ST>" --grid 3 を使ってください。
都市を 3 x 3 のタイル(9 ジョブ)に分割し、place_id で重複を排除します。タイルは一度に 1 つずつ処理するため、グリッド検索は時間がかかり、レート制限に達しやすくなります。警告は一度伝えてください。処理を止める必要はありません。
**メールアドレスの詳細取得:**メールアドレスの取得が有効な場合、デフォルトで実行されます。ウェブサイトはあるもののメールアドレスがない行について、連絡先ページと会社概要ページを確認し、スクリプトは見つかった割合を表示します。--no-deep-emails を指定するとスキップします。
その他のエンドポイント
GET /api/v1/jobsでジョブ一覧を取得します。DELETE /api/v1/jobs/{id}でジョブを削除し、ディスク容量を解放します。- ブラウザー UI と OpenAPI ドキュメント:
http://localhost:8080およびhttp://localhost:8080/api/docs。
ベストプラクティス(上流ドキュメントより)
- 深度:
depthを大きくすると取得件数は増えますが、処理に時間がかかり、ブロックされやすくなります。まずは 5 から始め、必要に応じて増やしてください。 - ローカルでは一度に 1 つのジョブを実行してください。プロキシを使わずに多数のジョブを同時実行すると、Google によるスロットリングが発生します。
- メールアドレスの抽出(
email:true)では各ビジネスのウェブサイトにアクセスするため、処理に時間がかかります。メールアドレスは見込み客の主要な項目であるため、デフォルトで有効になっています。高速に処理するには、--no-email(スクリプト)またはemail:false(生 API)を指定してください。 fast_mode:trueではデータを絞り込み、クエリあたり最大約 21 件の結果をより高速に返します。簡単な検索に使ってください。- **プロキシ:**大規模なジョブや繰り返し実行するジョブでは、
"proxies"(socks5://、http://、https://の URL の配列。認証にも対応)を設定してください。エンジンがプロキシを切り替えて使用します。これはレート制限への主な対策です。 zoomとradiusは、lat/lonの周辺に設定する検索範囲を指定します。結果が少なすぎる場合はradiusを広げてください。- 拡張レビューも利用できますが、負荷が高くなります。ユーザーがレビュー本文を求めた場合に限り、有効にしてください。
レート制限、ブロック、プロキシ(大規模なジョブを実行する前にお読みください)
エンジンは Google Maps に実際のリクエストを送信します。上流プロジェクトが公式に記載しているのは、次の免責事項のみです。
"このスクレイパーは、適用される法律および規制に従い、責任を持ってご利用ください。許可のないスクレイピングは、利用規約に違反する場合があります。"
ブロックに関する公表済みの明確な基準値はありません。そのため、慎重に利用してください。
- スクレイピングの速度が速すぎたり、量が多すぎたりすると、Google によってIP が一時的にレート制限される場合があります。数分から数時間で解除され、ユーザーの Google アカウントには影響しませんが、その間はジョブが失敗します。
- ブロックの兆候: ジョブが
failedを返す、結果が空または異常に少ない、同一条件の前回実行と比べて行数が急に減る、といった場合です。兆候が見られたら、ペースを落とし(一時停止する、深度を下げる)、またはプロキシを追加してください。 - 並列実行とブロック(上流プロジェクトより):"並列度を上げると、特にプロキシなしの場合、ブロックや失敗が増える可能性があります。初回はデフォルト設定から始めてください。"
参考スループットは
-c 8 -depth 1で約 120 件/分です。ローカルでは、一度に1つのジョブのみを実行し、depth 5から始めてください。
プロキシを追加するタイミング(上流プロジェクトより:"大規模なスクレイピングジョブでは、プロキシがレート制限の回避に役立ちます"): 大規模なジョブ、多数のキーワード、繰り返しまたは定期的な実行、あるいはブロックの兆候が見られた場合です。
- ジョブ本文の
"proxies"配列を設定します。種類:socks5、socks5h、http、https。 - 形式:
protocol://user:pass@host:port(認証は任意)、例:"proxies": ["socks5://user:pass@host:port", "http://host2:port2"]。エンジンが自動的にローテーションします。
安全性とガードレール
- 警告はしますが、ブロックはしません。 リクエストの規模が大きい場合(
depthが大きい、多数のキーワード、繰り返し実行、グリッド、またはemail:true)、そのまま実行しますが、まず IP の一時的なレート制限について簡潔に1回だけ警告し、プロキシの利用を提案してください。通常のスクレイピング規模が大きいという理由で、実行を制限したり、強制停止したり、確認を要求したりしないでください。明らかに悪質または違法な用途(個人の監視、スパム、嫌がらせ)の場合に限り、全面的に拒否してください。 - 認証プロキシなしで API を
localhostの外部に決して公開しないでください。API キーが存在する場合は、決して表示しないでください。 - 個人データ: スクレイピングで取得したメールアドレスや電話番号は個人データです。ユーザーがこれらを保存または連絡に利用する場合は、GDPR、CCPA、CAN-SPAM(適法な根拠、配信停止、抑止リスト)を遵守するよう伝えてください。スパムや嫌がらせには協力しないでください。
- Google の利用規約: Google Maps のスクレイピングは規約違反です。取得量を控えめにし、出力は確認が必要な見込み顧客の情報として扱い、生の Google データを再販売しないでください。個人の監視を目的とする利用は拒否してください。
- 出力の扱い: 大きな CSV をチャットに貼り付けないでください。ファイルをディスクに保存し、件数を要約して、サンプル行を数件示してください。保存前に
place_id/cidで重複を除去してください。 - ディスク: 結果は Docker ボリュームに蓄積されます。古いジョブをときどき
DELETEするよう提案してください。
トラブルシューティング
422 missing max time:max_time(秒)を追加してください。422 missing geo coordinates:文字列のlat/lonを追加してください。workingのまま進まない:depthを下げる、max_timeを増やす、または IP がスロットリングされている可能性があります(プロキシを追加するか、しばらく待ってください)。- CSV が空:キーワードの範囲が狭すぎるか、座標が正しくありません。
radiusを広げるか、座標を修正してください。 - 接続が拒否される:コンテナーが停止しています。
docker compose up -dを実行してください。