なぜGoogleマップのデータをScrapeするのですか?
Googleマップは、世界のローカルビジネスの最も包括的なデータベースが含まれています。 リストされている200万人以上の企業では、名前、住所、電話番号、ウェブサイト、評価、レビュー、営業時間、写真を含むすべての構造と検索が可能です。
このデータをプログラム的に抽出することで、貴重なビジネスアプリケーションが可能になります。
- リード生成: 業界や拠点で事業のターゲットリストを作成
- 競争分析: 競合他社の位置、評価、およびレビューをマップ
- 市場調査: 地域別ビジネス密度、価格設定パターン、サービスカバレッジを把握
- ローカルSEO監査: あなたのビジネスリストを確認し、競合他社と比較
- データ強化: 新鮮なビジネス情報でCRMデータを補完する
このガイドでは、プロキシを使用してGoogleマップデータを抽出するための技術的なアプローチについて説明します。 より広範なSERPスクレイピング戦略については、弊社をご覧ください。 プロキシガイドによる完全なSERPスクレイピング. .
GoogleはAPIとスクレイピングを置きます
スクレーパーを作成する前に、公式の Google Places API がニーズを満たしているかどうかを検討してください。
| ファクター | 配置 API | スクレイピング |
|---|---|---|
| コスト | $17 / 1,000リクエスト(無料ティア後) | プロキシ帯域幅のみ(1,000ページあたり0.10-0.50ドル) |
| データフィールド | 構造 JSON、20以上のフィールド | レビューテキストを含むすべての可視データ |
| レート制限 | 秒単位および日単位の限界 | プロキシプールサイズ限定 |
| テキストレビュー | 最大5件の関連レビュー | すべてのレビュー(ペジネーション付き) |
| 信頼性 | 公式、安定したエンドポイント | パーザーの維持を要求して下さい |
| サービス利用規約 | 完全準拠 | ToSと現地の規制をチェック |
| スケール | スケールで安価 | 高容量で費用効果が大きい |
Places APIは、小規模な生産クリティカルなアプリケーションに最適です。 大規模なデータセット、フルレビューテキスト、またはAPIコストが禁止される場合、スクレイピングは費用対効果が大きいです。
GoogleマップのURL構造
GoogleマップのURLパターンを理解することは、スクレーパーの構築に不可欠です。 エントリーポイントは2つあります。
検索結果
Googleマップの検索結果は、次の方法でアクセスできます。
# Browser URL format
https://www.google.com/maps/search/restaurants+near+new+york
# URL parameters for search
https://www.google.com/maps/search/{query}/@{lat},{lng},{zoom}z場所の細部
個々のビジネスページはこのパターンに従う:
# Place detail URL
https://www.google.com/maps/place/{business+name}/@{lat},{lng},{zoom}z/data=!{place_id}Googleマップスクレーパーの構築
Googleマップは、JavaScript-heavyアプリケーションです。 通常のGoogle検索とは異なり、単純なHTTPリクエストは不完全なデータを返すことが多いです。 ページソースから埋め込まれたJSONデータを解析したり、ヘッドレスブラウザを使用する2つのアプローチがあります。
アプローチ1:組込みJSON(ファスター)の解析
Googleマップのページには、HTMLソースに埋め込まれた構造化されたデータが含まれています。 これを抽出する方法は次のとおりです。
import requests
import json
import re
import time
import random
PROXY_URL = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
def search_google_maps(query, location="us"):
"""Search Google Maps and extract business listings."""
proxies = {"http": PROXY_URL, "https": PROXY_URL}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
"Accept": "text/html,application/xhtml+xml",
}
# Use the search URL format
search_url = f"https://www.google.com/maps/search/{query.replace(' ', '+')}"
response = requests.get(
search_url,
headers=headers,
proxies=proxies,
timeout=20,
)
response.raise_for_status()
# Extract embedded JSON data from the page
# Google Maps embeds data in a specific pattern
businesses = []
# Look for business data patterns in the response
# The data is typically in a JavaScript variable
patterns = re.findall(r'\["([^"]+)",null,null,null,null,null,null,null,"([^"]*)"', response.text)
# Alternative: parse the structured search results
# Google Maps returns data in protobuf-like JSON arrays
json_matches = re.findall(r'null,\["([^"]{5,80})"[^]]*?"([^"]*?(?:St|Ave|Rd|Blvd|Dr|Ln)[^"]*?)"', response.text)
for match in json_matches[:20]:
businesses.append({
"name": match[0],
"address": match[1] if len(match) > 1 else "",
})
return businesses
results = search_google_maps("restaurants near Times Square New York")
for b in results:
print(f"{b['name']} - {b['address']}")アプローチ2:ヘッドレスブラウザ(より信頼できる)
より信頼できる抽出のために、JavaScriptをレンダリングするヘッドレスブラウザを使用します。
from playwright.sync_api import sync_playwright
import json
import time
PROXY_URL = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
def scrape_maps_with_browser(query):
"""Use Playwright to scrape Google Maps with full JS rendering."""
with sync_playwright() as p:
browser = p.chromium.launch(
headless=True,
proxy={
"server": "http://gate.proxyhat.com:8080",
"username": "USERNAME",
"password": "PASSWORD",
},
)
page = browser.new_page()
page.set_extra_http_headers({
"Accept-Language": "en-US,en;q=0.9",
})
# Navigate to Google Maps search
search_url = f"https://www.google.com/maps/search/{query.replace(' ', '+')}"
page.goto(search_url, wait_until="networkidle", timeout=30000)
# Wait for results to load
page.wait_for_selector('div[role="feed"]', timeout=10000)
# Scroll to load more results
feed = page.query_selector('div[role="feed"]')
for _ in range(5):
feed.evaluate("el => el.scrollBy(0, 1000)")
time.sleep(1.5)
# Extract business data from the results
businesses = []
items = page.query_selector_all('div[role="feed"] > div > div > a')
for item in items:
name = item.get_attribute("aria-label")
href = item.get_attribute("href")
if name and href:
businesses.append({
"name": name,
"url": href,
})
browser.close()
return businesses
results = scrape_maps_with_browser("coffee shops in San Francisco")
for b in results:
print(f"{b['name']}")
print(f" {b['url'][:80]}...")
print()業務内容の抽出
ビジネス URL のリストがある場合、各リストから詳細情報を抽出します。
import requests
import re
import json
PROXY_URL = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
def extract_business_details(maps_url):
"""Extract detailed business info from a Google Maps place page."""
proxies = {"http": PROXY_URL, "https": PROXY_URL}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
}
response = requests.get(maps_url, headers=headers, proxies=proxies, timeout=20)
text = response.text
business = {}
# Extract business name
name_match = re.search(r'Googleマップのプロキシ戦略
Googleマップには、独自のアンチボット保護機能が搭載されています。
なぜ住宅のプロキシが必要なのか
Googleマップは、データセンターIPをブロックする際の特に攻撃的です。 アプリケーションは複数の API 呼び出しを介してデータをロードし、Google はこれらのすべてのリクエスト間で IP をクロスリファレンスします。 住宅のプロキシから プロキシハート 重要な理由:
- Maps API 呼び出しが強制する IP の評判チェックを渡します
- 位置固有の検索のための都市レベルのジオターゲティングをサポート
- Maps が期待する一貫したセッション動作を維持
セッション管理
リクエストごとにIPを回転させる定期的なSERPスクレイピングとは異なり、Googleマップは粘着性のあるセッションでより良い機能します。
# For Google Maps, use sticky sessions (same IP for a business detail page)
# ProxyHat supports session-based rotation via the proxy URL
# See docs.proxyhat.com for session configuration
# Rotating IP (for search listings)
ROTATING_PROXY = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
# Sticky session (for individual place pages)
# Same session ID = same IP for the session duration
STICKY_PROXY = "http://USERNAME-session-maps123:PASSWORD@gate.proxyhat.com:8080"レート制限
Googleマップは、通常のGoogle検索よりも迅速なリクエストに敏感です。 これらのガイドラインに従う:
- 検索結果ページから5〜10秒間待つ
- 個々の場所のページの負荷間の3-5秒待って下さい
- 破裂パターンを避けるために同時リクエストを制限
- レビューのペジネーション(ページ間の8〜15秒)の長い遅延を使用する
Node.js 実装
const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');
const agent = new HttpsProxyAgent('http://USERNAME:PASSWORD@gate.proxyhat.com:8080');
async function searchGoogleMaps(query) {
const searchUrl = `https://www.google.com/maps/search/${encodeURIComponent(query)}`;
const { data } = await axios.get(searchUrl, {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept-Language': 'en-US,en;q=0.9',
},
httpsAgent: agent,
timeout: 20000,
});
// Extract business names from the response
const businesses = [];
const namePattern = /\["([^"]{3,80})",null,null,null,null,null,null,null/g;
let match;
while ((match = namePattern.exec(data)) !== null) {
businesses.push({ name: match[1] });
}
return businesses;
}
async function main() {
const results = await searchGoogleMaps('plumbers in Chicago');
console.log(`Found ${results.length} businesses:`);
results.forEach((b, i) => console.log(`${i + 1}. ${b.name}`));
}
main().catch(console.error);スケールでのレビューを抽出する
Googleマップのレビューは、最も貴重なデータポイントです。 各レビューには、査読者の名前、評価、テキスト、日付、および時々写真が含まれます。
import requests
import re
import json
import time
import random
PROXY_URL = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
def extract_reviews(place_id, num_reviews=50):
"""Extract reviews for a Google Maps place using the internal API."""
proxies = {"http": PROXY_URL, "https": PROXY_URL}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Accept-Language": "en-US,en;q=0.9",
}
reviews = []
# Google Maps loads reviews via AJAX with pagination tokens
# The first page is loaded with the place page
maps_url = f"https://www.google.com/maps/place/?q=place_id:{place_id}"
response = requests.get(maps_url, headers=headers, proxies=proxies, timeout=20)
# Extract review data from embedded JSON
# Reviews are typically in arrays with rating, text, and author
review_pattern = re.findall(
r'"(\d)","([^"]{10,500})"[^]]*?"([^"]{2,50})"',
response.text
)
for match in review_pattern[:num_reviews]:
reviews.append({
"rating": int(match[0]),
"text": match[1],
"author": match[2],
})
return reviews
# Example: extract reviews
reviews = extract_reviews("ChIJN1t_tDeuEmsRUsoyG83frY4") # Example place ID
for r in reviews[:5]:
print(f"{'*' * r['rating']} by {r['author']}")
print(f" {r['text'][:100]}...")
print()データ構造とストレージ
スクラップされたGoogleマップデータを分析するための構造化された形式に整理する:
import json
import csv
from datetime import datetime
def save_businesses(businesses, output_format="json"):
"""Save scraped business data in structured format."""
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
if output_format == "json":
filename = f"maps_data_{timestamp}.json"
with open(filename, "w") as f:
json.dump(businesses, f, indent=2, ensure_ascii=False)
elif output_format == "csv":
filename = f"maps_data_{timestamp}.csv"
if businesses:
keys = businesses[0].keys()
with open(filename, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=keys)
writer.writeheader()
writer.writerows(businesses)
print(f"Saved {len(businesses)} businesses to {filename}")
return filename法的および倫理的考慮事項
Googleマップのデータスクレイピングは、重要な法的および倫理的な質問を上げます:
- Google利用規約: GoogleのToSは自動スクレイピングを禁止します。 生産用途向け公式プレイスAPIの利用を検討
- データ保護: 電話番号やアドレスなどのビジネスデータは、一部の管轄区域におけるデータ保護規則の対象となる場合があります。
- レート制限: プロキシも、Googleのインフラに敬意を表しています。 過剰なスクレイピングは、サービスの品質に影響を与えます
- データ鮮度: 常にデータをタイムスタンプし、定期的に更新し、ビジネス情報が頻繁に変化する
ミッションクリティカルなアプリケーションでは、公式のプレースAPIをコアデータと組み合わせることを検討し、レビューテキストなどの補足フィールドのスクレイピングを標的としています。 データの完全性を順守するハイブリッドアプローチ。
ウェブスクレイピングのベストプラクティスの詳細については、 ウェブスクレイピングプロキシの完全なガイドブロックの回避について学びます アンチブロックガイド. 相談して下さい ProxyHat ドキュメント プロキシ構成の詳細。






