Dokumentacja do scrapowania Map Google. Od zapytania do eksportu.

Od pierwszego wyszukiwania do powtarzalnego procesu pracy agenta. Instrukcje, granice i kontrakty API znajdziesz tutaj.

Na tej stronie
  1. Zainstaluj rozpakowane rozszerzenie
  2. Zacznij od jednego, konkretnego zadania
  3. Zapisz wzbogacenie z powrotem na zapisanej liście
  4. Przeprowadź inspekcję strony głównej firmy
  5. REST API
  6. Utwórz zadanie ograniczone
  7. Typowe błędy
  8. Sprawdź odpowiedź wyszukiwania AI
  9. Przeszukaj obszar i pobierz więcej stron
  10. Planowanie badań wewnątrz wielokąta
  11. Eksportuj zachowany łańcuch stron
  12. Analizuj tematy opinii z cytowanymi dowodami
  13. Przygotuj i udostępnij raport klienta
  14. Wygeneruj zachowany plik PDF
  15. Odbieranie podpisanych potwierdzeń zadań
  16. Wysyłaj wyniki do Arkuszy Google, Zapier, Make lub n8n
  17. Ważne ograniczenia

Zainstaluj rozpakowane rozszerzenie

Rozszerzenie Google Maps scraper łączy się z API obszaru roboczego. Dystrybucja w sklepach Chrome i Edge nie jest zatwierdzona.

  1. Pobierz i rozpakuj pakiet rozszerzenia.
  2. W Chrome otwórz chrome://extensions. W Edge otwórz edge://extensions. Włącz tryb programisty, wybierz opcję Załaduj rozpakowane i wybierz rozpakowany folder.
  3. Otwórz rozszerzenie i wybierz „Połącz przez MapsScraper.dev”. Zaloguj się na otwartej stronie, gdzie właściciel lub administrator obszaru roboczego zatwierdza połączenie; rozszerzenie otrzymuje wtedy własny klucz na tę sesję przeglądarki. Możesz też wkleić klucz API obszaru roboczego z dostępem „Odczyt i uruchamianie zadań ograniczonych” z API i klucze.
  4. Wybierz język, użyj bieżącego wyszukiwania w Maps, ustaw limity rekordów i jednostek, a potem uruchom. Wyszukiwanie zostanie wysłane tylko wtedy, gdy wycena mieści się w limicie jednostek.
  5. Użyj opcji „Odzyskaj oryginalne zgłoszenie w przypadku utraty odpowiedzi”. Jeśli sesja się zakończyła, sprawdź historię zadań przed ponownym wysłaniem.
Pobierz rozpakowane rozszerzenie ZIP
Kontrakt OpenAPI 3.1 Dokumentuje wszystkie wdrożone trasy w przestrzeni roboczej, paginację, jawne budżety i schematy odpowiedzi. Poznaj katalog funkcji dla każdej strony obszaru roboczego.

Zacznij od jednego, konkretnego zadania

  1. Utwórz obszar roboczy i otwórz Eksploruj firmy.
  2. Wprowadź zapytanie z jego lokalizacją, na przykład „Dentyści w Austin, Teksas”.
  3. Wybierz limit rekordów i opcjonalne filtry. Filtry są stosowane po pobraniu danych.
  4. Sprawdź maksymalne wykorzystanie jednostek. Wzbogacanie zwiększa limit rezerwacji.
  5. Uruchom, sprawdź źródła, wybierz firmy i zapisz na liście lub wyeksportuj plik CSV.

Zapisz wzbogacenie z powrotem na zapisanej liście

W sekcji „Zapisane listy” wybierz rekordy, które mają identyfikator źródła, i autoryzuj „Wzbogać wybrane” z maksymalnym budżetem jednostek. „Przejrzyj zbiorcze zapisy” otwiera nową partię; oczekujące zadania pozostają pominięte do późniejszego podglądu. Możesz również wybrać istniejącą partię szczegółów lub wzbogacenia z paska narzędzi listy.

Wyświetl podgląd dokładnie żądanych identyfikatorów i rozwiń każde porównanie przed/po. Funkcja „Wypełnij puste pola” zachowuje istniejące wartości; funkcja „Zastąp wybrane pola” kopiuje tylko wybrane niepuste pola źródłowe. Przejrzyj zduplikowane, niedopasowane, wygasłe lub zatrzymane zadania na liście pominiętych. Przed zastosowaniem sprawdź wyświetlaną liczbę zmienionych rekordów i pominiętych zadań. Zmieniony rekord, źródło lub konfiguracja wymagają ponownego podglądu.

Wszystkie kwalifikujące się aktualizacje są zatwierdzane razem. Etapy, notatki, tagi, przypisania i pola niestandardowe pozostają nienaruszone. Historia zapisu wsadowego pokazuje wartości oryginalne i cofanie zmian dla każdego rekordu; późniejsze edycje blokują przywracanie. Ustawienia obszaru roboczego kontrolują włączanie i limity rekordów. Zapis zachowanych wyników nie wykorzystuje jednostek badawczych i nie wywołuje źródła danych. Nierozwiązane importy nadal korzystają z indywidualnej funkcji „Dopasuj i scal”.

Agenci używają preview_batch_merge, apply_reviewed_batch_merge i read_batch_merge_receipt z tymi samymi wymaganiami dotyczącymi skrótu przeglądu, zakresu i idempotentności. Nigdy nie wnioskuj o autoryzacji zapisu na podstawie rekordów źródłowych.

Przeprowadź inspekcję strony głównej firmy

Otwórz Audyty witrynlub wybierz opcję Przeprowadź inspekcję tej witryny z zapisanego rekordu. Przejrzyj znormalizowaną stronę główną, oszacuj i autoryzuj jedną jednostkę. Przeprowadź inspekcję ukończonej obserwacji HTTP/HTML, wyeksportuj ją, utwórz raport lub ustaw cykliczny monitor. Badania zbiorcze akceptują również jedną witrynę w wierszu.

Sprawdzenie strony głównej nie korzysta ze źródła danych Map na żywo. Odczytuje maksymalnie 256 KiB, śledzi do pięciu bezpiecznych przekierowań i zatrzymuje się po 15 sekundach. Nie uruchamia JavaScript ani nie oblicza wyniku rankingowego. Obserwacja zablokowana lub przerwana po przekroczeniu limitu czasu nadal zużywa jedną jednostkę.

{"kind":"website_audit","url":"https://example.com/","limit":1}

REST API

GET      /api/health
GET      /api/me
GET      /api/v1/usage
POST     /api/v1/estimate
POST     /api/v1/jobs
GET      /api/v1/jobs/{id}
GET      /api/v1/jobs/{id}/results
POST     /api/v1/jobs/{id}/cancel
GET      /api/v1/jobs/{id}/export
GET/POST /api/v1/lists
GET/POST /api/v1/lists/{id}/items
PATCH    /api/v1/lists/{id}/items/{business_id}
GET/POST /api/monitors
PATCH    /api/monitors/{id}
POST     /mcp

Utwórz zadanie ograniczone

curl -X POST https://mapsscraper.dev/api/v1/jobs \
  -H "Authorization: Bearer $MAPSSCRAPER_API_KEY" \
  -H "Idempotency-Key: dentists-austin-tx-001" \
  -H "X-Max-Units: 1" \
  -H "Content-Type: application/json" \
  -d '{"kind":"search","query":"Dentists in Austin, TX","limit":20,"region":"us"}'

HTTP/1.1 202 Accepted
{"id":"6f1c2b3a-0000-4000-8000-000000000000","status":"queued","reserved":1}

Ponów tę samą operację z tym samym kluczem idempotencji. Zmienione żądanie z tym kluczem zwraca 409. Zadania przechodzą przez stany: w kolejce, w toku, ukończone, częściowe, nieudane, anulowane lub niepewne. Niepewne żądanie do źródła danych wymaga uzgodnienia zamiast automatycznego płatnego powtórzenia.

Większość zadań zużywa jedną jednostkę. Wzbogacenie kontaktów przy wyszukiwaniu lub migawce pozycji rezerwuje jedną dodatkową jednostkę na każdy żądany rekord i nalicza tylko dostarczone rekordy. Szczegóły firmy zużywają jedną jednostkę, a z kontaktami dwie; wzbogacanie zużywa dwie. Ustaw X-Max-Units co najmniej na wartość wyceny.

W języku Python oszacuj zadanie, utwórz zlecenie za pomocą biblioteki requests, poczekaj na status końcowy i odczytaj zachowane wyniki:

import os
import time
import uuid

import requests

API = "https://mapsscraper.dev/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['MAPSSCRAPER_API_KEY']}"}
task = {"kind": "search", "query": "Dentists in Austin, TX", "limit": 20, "region": "us"}

# An estimate reserves nothing.
units = requests.post(f"{API}/estimate", json=task, headers=HEADERS, timeout=30).json()["units"]

# Keep the key: a retry of the same task must send it again.
key = str(uuid.uuid4())
job = requests.post(
    f"{API}/jobs",
    json=task,
    headers={**HEADERS, "Idempotency-Key": key, "X-Max-Units": str(units)},
    timeout=30,
)
job.raise_for_status()
job_id = job.json()["id"]

while True:
    status = requests.get(f"{API}/jobs/{job_id}", headers=HEADERS, timeout=30).json()["status"]
    if status not in ("queued", "running"):
        break
    time.sleep(5)

if status in ("completed", "partial"):
    page = requests.get(
        f"{API}/jobs/{job_id}/results",
        params={"offset": 0, "limit": 100},
        headers=HEADERS,
        timeout=30,
    ).json()
    for business in page["items"]:  # follow page["next_offset"] for more
        print(business.get("name"), business.get("phone_number"), business.get("website"))

Typowe błędy

Każda odpowiedź o błędzie to JSON ze stałym kodem, a niektóre zawierają szczegóły. Rozgałęziaj logikę według kodu; kilka kodów może mieć ten sam status HTTP.

{"error":{"code":"TASK_BUDGET_TOO_LOW","details":{"needed":11,"max_units":5}}}
Status HTTPKod błęduSzczegóły
400VALIDATION_ERRORINVALID_JSONINVALID_TASKIDEMPOTENCY_KEY_REQUIREDBrakuje treści, nagłówka lub parametru albo są one nieprawidłowe. Popraw żądanie przed ponowną próbą.
400TASK_BUDGET_REQUIREDBrak X-Max-Units albo wartość nie jest liczbą całkowitą od 1 do 10000.
401UNAUTHORIZEDZaloguj się lub użyj prawidłowego klucza.
403INSUFFICIENT_SCOPEWORKSPACE_ACCESS_REVOKEDTwój klucz lub członkostwo nie zezwalają na tę akcję.
404NOT_FOUNDTen zasób nie istnieje w tym obszarze roboczym.
405METHOD_NOT_ALLOWEDMCP przyjmuje tylko żądania POST. GET i DELETE zwracają ten kod z nagłówkiem Allow: POST.
409IDEMPOTENCY_CONFLICTKlucz idempotentności został ponownie użyty w zmienionym żądaniu.
409JOB_NOT_CANCELLABLEZadanie zostało już wysłane do źródła danych lub zakończone, więc nie można go anulować.
details.status
410RESULT_EXPIREDZachowany wynik wygasł. Uruchom nowe zadanie, aby pobrać go ponownie.
410WORKSPACE_UNAVAILABLEObszar roboczy jest usuwany. Żądania do niego są odrzucane.
422TASK_BUDGET_TOO_LOWWycena przekracza budżet X-Max-Units.
details.needed, details.max_units
422INSUFFICIENT_BALANCEDostępne jednostki są poniżej maksimum zadania.
details.needed, details.available
422DAILY_BUDGET_EXCEEDEDZadanie przekroczyłoby dzienny limit jednostek obszaru roboczego.
details.needed, details.daily_limit, details.used_today
422PENDING_LIMIT_REACHEDZbyt wiele zadań jest już w kolejce lub w toku.
details.pending, details.max_pending
422WORKSPACE_LIMIT_OR_BALANCE_EXCEEDEDDostępne jednostki lub limit zadań obszaru roboczego są niewystarczające.
423, 409WORKSPACE_DELETION_PENDINGObszar roboczy jest w okresie karencji przed usunięciem. Zmiany są odrzucane z kodem 423, a odczyt, eksport, działania na koncie i narzędzia MCP tylko do odczytu nadal działają. Odpowiedź 409 z tym kodem lub WORKSPACE_NOT_ACTIVE pojawia się tylko wtedy, gdy usuwanie rozpocznie się podczas przyjmowania zadania.
429RATE_LIMITEDOsiągnięto limit częstotliwości. Odczekaj liczbę sekund podaną w Retry-After, a potem ponów próbę.
429RESEARCH_DAILY_LIMIT_REACHEDDzisiejsza pula badań na żywo została wykorzystana. Odczekaj liczbę sekund podaną w Retry-After, do następnego dnia UTC. Nic nie jest rezerwowane.
500INTERNAL_ERRORWystąpił nieoczekiwany błąd. Ponów później z tym samym kluczem idempotencji.
503PROVIDER_NOT_CONFIGUREDBadania na żywo nie są otwarte dla tego obszaru roboczego albo źródło danych zadania nie jest skonfigurowane.

Sprawdź odpowiedź wyszukiwania AI

Widoczność wyszukiwania AI zachowuje jedną obserwację Google AI Overview: pytanie, kraj, język, opcjonalne odchylenie od miasta, tekst odpowiedzi i linki do bezpiecznych cytowań. Dodaj maksymalnie pięć nazw marek i domen, sprawdź maksymalnie jedną jednostkę, a następnie wyraźnie autoryzuj zadanie. Administrator musi włączyć obszar roboczy i połączyć licencjonowane źródło.

Przejrzyj historię lub wyeksportuj dowody bez ponownego wywołania źródła danych. Porównuj linie bazowe tylko wtedy, gdy zapytanie, ustawienia regionalne i cele są zgodne. Brak przeglądu oznacza nieznaną widoczność; kolejność cytowań nie jest rankingiem wyszukiwania. Niekompletne dowody nie mogą ustalić negatywnego dopasowania. Śledzenie wielu wyszukiwarek nie jest dostępne.

Aby śledzić stały zestaw pytań, zweryfikowany właściciel lub administrator może zaplanować cykliczną serię: do 10 promptów, co 24 do 720 godzin, maksymalnie 30 obserwacji w ciągu 90 dni. Sprawdź maksymalną liczbę jednostek dla całej serii i potwierdź ją wprost. Seria wstrzymuje się, gdy zmieni się jej autoryzacja lub konfiguracja albo gdy obserwacja się nie powiedzie lub jest niepewna; wznowienie wymaga nowego podglądu.

Otwórz widoczność wyszukiwania AI

Przeszukaj obszar i pobierz więcej stron

W sekcji Eksploruj wybierz lokalizację tekstu, odchylenie punktu, promień lub prostokąt ograniczający. Odchylenie punktu nie jest granicą. Wyniki promienia i prostokąta wykluczają współrzędne zewnętrzne lub nieużyteczne i zachowują liczbę wykluczeń. Ustawienia obszaru roboczego kontrolują promień i rozmiar pola. Podziel pole przecinające antymerydian; ograniczona próbka nie dowodzi pełnego pokrycia.

Opinie i metadane zdjęć pozwalają na maksymalnie 100 rekordów na stronę źródła. Po zakończeniu wyniku otwórz Strony wyników w sekcji Eksploruj lub Historia zadań. Sprawdź dokładne opcje źródła, zaznacz pole wyboru autoryzacji i ustaw budżet, aby pobrać kolejną stronę. Sortowanie, język, tłumaczenie i filtry pozostają niezmienne dla łańcucha. Brakujące lub powtarzające się kursory, wygaśnięcie, skonfigurowane limity i niepewne wyniki zatrzymują kontynuację.

Odczytanie następnej strony zapisanego rekordu i wyeksportowanie istniejącej strony nie powoduje wywołania źródła danych. Pobranie nowej strony źródła jest oddzielną, płatną operacją. W przypadku zestawu SDK i agentów przeczytaj podgląd kontynuacji, a następnie prześlij dokładne zadanie ze stabilnym kluczem idempotentności i jawnym budżetem. Nie planuj ani nie twórz wsadowych kontynuacji kursorów.

Planowanie badań wewnątrz wielokąta

Wybierz granicę wielokąta w sekcji Eksploruj, aby uzyskać żądanie jednego ograniczonego prostokąta z dokładnym filtrowaniem wielokątów. W sekcji Badania zbiorcze wybierz granicę wielokąta, aby zaimportować lub wkleić wielokąt GeoJSON, sprawdzić jego kształt i wybrać wiersze, kolumny i rekordy dla każdej komórki. Schemat przedstawia współrzędne i planowane komórki; nie jest to mapa ulic.

Pozycje używają [długość geograficzna, szerokość geograficzna]. Zamknij każdy pierścień, powtarzając jego pierwszą pozycję; pierwszy pierścień to zewnętrzna krawędź, a maksymalnie cztery dodatkowe pierścienie to wykluczone otwory. Przecięcia własne, stykające się lub nakładające się otwory oraz przecięcia antymerydyczne są odrzucane. Użyj oddzielnych wielokątów na linii zmiany daty. Ustawienia obszaru roboczego: ograniczone pozycje, rozpiętość i planowane komórki.

„Przejrzyj komórki i Całkowity budżet” nie wywołuje źródła danych. Sprawdź każdą zachowaną komórkę, ustaw maksymalną liczbę jednostek i wyraźnie potwierdź przed uruchomieniem. Wszystkie zadania są rezerwowane razem lub żadne nie jest akceptowane. Potwierdzenia zachowują oryginalną wersję planu i konfiguracji. Wynik źródłowy jest filtrowany zarówno według wielokąta, jak i komórki; wspólne krawędzie mogą generować duplikaty firm. Żądana liczba rekordów to pułap, a nie spis.

Agenci używają preview_polygon_plan, a następnie create_reviewed_polygon_batch z dokładnie takim samym planem kompaktowym, skrótem podglądu, potwierdzeniem, kluczem stabilnym i budżetem zbiorczym. Użyj istniejącej historii partii, anulowania i kontroli wyników/eksportu dla każdego zadania. Niepewne wyniki nigdy nie są automatycznie ponownie skanowane.

Eksportuj zachowany łańcuch stron

W sekcji Strony wyników otwórz Eksportowanie wielu stron i wybierz Eksport całego łańcucha recenzji. Przejrzyj strony w ramach wybranego zadania, wybierz, czy zachować pierwszy rekord dla każdego dokładnego identyfikatora, czy zachować wszystkie rekordy, a następnie potwierdź prywatny eksport. Nie powoduje to pobrania nowych danych ani użycia jednostek badawczych. Eksporty pojawiają się również w kontrolkach danych z potwierdzeniami postępu, anulowania i integralności.

Pobierz pliki JSONL, JSON, CSV lub Excel po zakończeniu. Zduplikowane identyfikatory ze zmienioną zawartością są liczone jako konflikty; pierwszy rekord jest zachowywany. Rekordy bez identyfikatorów pozostają oddzielne. Każda strona źródłowa ma własną zweryfikowaną część JSONL, dzięki czemu nieudany transfer może być kontynuowany po części. Excel obsługuje do 5 MB przechowywanych części; większe eksporty korzystają z formatów strumieniowych. Plik CSV zachowuje dodatkowe kolumny w extra_fields_json.

Właściciele i administratorzy konfigurują codzienne żądania, oczekujące eksporty, limity bajtów stron i źródeł oraz retencję w Ustawieniach. Obowiązuje zawsze najwcześniejszy termin wygaśnięcia źródła. Zachowaj znacznik „complete” podczas korzystania z JSON lub JSONL i weryfikuj pobrane części pod kątem ich potwierdzeń SHA-256. Zamrożony łańcuch to zachowana próbka, a nie dowód pełnego pokrycia rynku.

Analizuj tematy opinii z cytowanymi dowodami

Zacznij od raportu statystyk opinii w Raportach. Właściciel lub administrator włącza analizę opinii AI w Ustawieniach i użyciu oraz ustawia dzienne próby, oczekujące zadania, liczbę fragmentów i czas życia kolejki. Domyślnie ta opcja jest wyłączona.

Wybierz „Przejrzyj dane wejściowe analizy”, aby sprawdzić dokładne fragmenty i model przed autoryzacją jednego generowania. W kolejności raportu wybieranych jest maksymalnie 40 odrębnych fragmentów i 10 KB tekstu fragmentów. Generowanie ma własne limity analizy AI i nie korzysta z jednostek portfela Map. Nieudane lub anulowane próby nadal się liczą.

Każdy zapisany motyw zawiera sprawdzone cytaty i odniesienia do źródeł. Liczby są obliczane na podstawie odrębnych cytowanych fragmentów, tematy mogą się nakładać, a interpretacje AI mogą być błędne. Wynik otwiera się jako osobny raport: należy go przejrzeć w sekcji Raporty, a następnie wybrać, co udostępnić lub wyeksportować do pliku PDF. Ukrycie kolumny „Fragment opinii” powoduje również ukrycie analizy AI.

Fragmenty, które nie zawierają obsługiwanego doświadczenia klienta, mogą zwrócić paragon z powodu braku wystarczających dowodów bez raportu. Próba nadal wlicza się do limitów. Przed autoryzacją innej analizy należy sprawdzić dane wejściowe. Aktualizacja funkcji zatrzymuje starsze zatwierdzenia w kolejce przed wnioskowaniem; należy przejrzeć nowy podgląd. Istniejące raporty zachowują swój oryginalny model i wersję monitu.

Paragony pokazują wyniki w kolejce, w trakcie realizacji, ukończone, nieudane, niepewne, anulowane lub wygasłe. Anulowanie uniemożliwia utworzenie raportu, chociaż wysłana analiza nadal wlicza się do limitów. Niepewne wywołania nigdy nie są odtwarzane automatycznie. API, SDK i MCP używają tego samego skrótu podglądu, wyraźnego potwierdzenia i klucza idempotentności.

Przygotuj i udostępnij raport klienta

Utwórz raport z ukończonych badań w Raportach. Edytuj jego tytuł, markę, kolejność sekcji i kolumny dowodów, a następnie zapisz prezentację. Ustawienia obszaru roboczego zapewniają domyślne kolory marki, logo w formacie PNG, stronę internetową wydawcy i stopkę. Istniejące zapisane prezentacje zmieniają się tylko po ich edycji lub zastosowaniu domyślnych ustawień obszaru roboczego.

Udostępniony sprawdzony raport pokazuje dokładną prognozę publiczną. Niezaznaczone pola dowodów i ukryte sekcje są wykluczone z zapisanej migawki. Zapytania źródłowe są domyślnie prywatne; metodologia pozostaje widoczna. Wybierz dowolną osobę z linkiem lub maksymalnie 25 zweryfikowanych kont e-mail, ustaw wygaśnięcie i wyraźnie potwierdź treść i odbiorców. Możesz również wymagać hasła do udostępniania; wyślij je oddzielnie od linku. Zasady obszaru roboczego mogą wymagać haseł przy każdym udostępnianiu wyników/raportu. Nie jest wysyłane żadne zaproszenie ani wiadomość e-mail.

Skopiuj cały link raz. Sekret pozostaje w swoim fragmencie i nie jest przechowywany w pamięci przeglądarki. Odbiorca z ograniczonym dostępem loguje się przy użyciu zatwierdzonego konta, a następnie otwiera oryginalny link i wprowadza hasło do udziału na żądanie. Haseł nie można odzyskać; należy je unieważnić i utworzyć nowy link w przypadku utraty. Wygaśnięcie jest ograniczone przez retencję źródła. Kontrola danych może unieważnić przyszły dostęp; usunięte raporty, wygasłe źródła i wstrzymane obszary robocze uniemożliwiają nowe odczyty. Pobranych kopii nie można przywrócić. JSON i przeglądarka Drukuj/Zapisz PDF korzystają z wyświetlanej prezentacji. Generuj zapisany PDF tworzy prywatny plik z zapisanej wersji, na papierze A4 lub Letter i w orientacji pionowej lub poziomej. Ukończone pliki można dołączyć do pasującego, sprawdzonego udziału i odziedziczyć jego reguły dostępu.

Agenci używają preview_report_delivery, update_report_presentation, create_reviewed_report_share, list_report_shares i revoke_report_share. Publikacja wymaga wersji recenzowanej, skrótu migawki, stabilnego klucza idempotentności oraz jawnej autoryzacji udostępniania. Zewnętrzny tekst badawczy nie może udzielić takiej autoryzacji.

Wygeneruj zachowany plik PDF

Zapisz prezentację, wybierz papier i orientację w eksportach PDF, a następnie wygeneruj. Historia pokazuje żądania oczekujące w kolejce, renderowane, ukończone i zatrzymane z opcjami pobierania lub anulowania. Ustawienia obszaru roboczego kontrolują włączanie, żądania dzienne, żądania oczekujące i retencję. Pliki wygasają wraz ze swoimi źródłami lub skonfigurowanym okresem retencji, w zależności od tego, co nastąpi wcześniej. Renderowanie nie zużywa jednostek badawczych. Nieudane lub niepewne renderowanie wymaga nowego, jawnego żądania; nie jest automatycznie ponawiane.

Agenci używają generate_report_pdf z recenzowaną wersją, skrótem migawki, confirmed_render i kluczem idempotentności. list_report_pdfs i get_report_pdf sprawdzają potwierdzenia; cancel_report_pdf zatrzymuje się w oczekiwaniu na publikację. Generowanie nie tworzy udziału ani nie wysyła wiadomości. Prywatne trasy pobierania i dołączania odbiorców znajdują się w OpenAPI.

Odbieranie podpisanych potwierdzeń zadań

W Integracjach dodaj publicznego odbiorcę HTTPS. Zapisz bezpiecznie jednorazowy klucz podpisu, włącz dostarczanie w Ustawieniach i użytkowaniu, a następnie jawnie włącz miejsce docelowe. Wybierz zdarzenia ukończone, częściowe, nieudane, niepewne lub anulowane. Testy wysyłają tylko flagę testu i metadane.

Każde doręczenie zawiera dwa schematy podpisu. W Standard Webhooks webhook-signature to v1, a po nim HMAC-SHA256 w base64 z webhook-id, webhook-timestamp i dokładnej surowej treści żądania, połączonych kropkami. Kluczem jest zdekodowany z base64 tekst po whsec_.

Pierwotny schemat się nie zmienia: X-LocalOS-Signature to v1=, a po nim szesnastkowy HMAC-SHA256 z X-LocalOS-Timestamp, kropki i surowej treści, z całym sekretem whsec_ jako tekstem w roli klucza. Wybierz sekret na podstawie X-LocalOS-Key-ID.

W obu schematach wymagaj znacznika czasu nie starszego niż pięć minut i porównuj podpisy w stałym czasie. Identyfikator zdarzenia w webhook-id i X-LocalOS-Event-ID jest taki sam przy ponowieniach: zapisz go jako unikalny przed zastosowaniem zmian i potwierdzaj duplikaty odpowiedzią 2xx.

Weryfikacja podpisu Standard Webhooks w Node.js:

// Verifies a webhook delivery with Web Crypto only, so it runs on
// Node.js 20+, Deno, Bun and Cloudflare Workers without dependencies.
//   const event = await verifyWebhook({ secret, headers, body });
// secret: "whsec_..." or, while rotating, ["whsec_new", "whsec_old"].
// headers: a Headers object or a plain map such as req.headers.
// body: the raw body as text or bytes, before any JSON parsing.
// Returns the parsed event. Otherwise throws an error whose code says
// why the delivery must not be trusted.
export class WebhookVerificationError extends Error {
  constructor(code) {
    super(code);
    this.name = "WebhookVerificationError";
    this.code = code;
  }
}

const encoder = new TextEncoder();

function header(headers, name) {
  if (typeof headers.get === "function") {
    return headers.get(name) ?? undefined;
  }
  for (const [key, value] of Object.entries(headers)) {
    if (key.toLowerCase() === name) {
      return Array.isArray(value) ? value[0] : value;
    }
  }
  return undefined;
}

function base64(value) {
  if (!/^[A-Za-z0-9+/]+={0,2}$/.test(value) || value.length % 4) {
    return null;
  }
  try {
    return Uint8Array.from(atob(value), (c) => c.charCodeAt(0));
  } catch {
    return null;
  }
}

// Checks every byte, so the time taken does not reveal a mismatch.
function sameBytes(a, b) {
  if (a.length !== b.length) return false;
  let difference = 0;
  for (let i = 0; i < a.length; i++) difference |= a[i] ^ b[i];
  return difference === 0;
}

export async function verifyWebhook({
  secret,
  headers,
  body,
  toleranceSeconds = 300,
}) {
  if (!Number.isFinite(toleranceSeconds) || toleranceSeconds < 0) {
    throw new RangeError("toleranceSeconds must be 0 or more");
  }
  const fail = (code) => new WebhookVerificationError(code);
  const keys = [secret]
    .flat()
    .map((value) =>
      typeof value === "string" ? base64(value.replace(/^whsec_/, "")) : null,
    );
  if (!keys.length || keys.some((key) => !key?.length)) {
    throw fail("WEBHOOK_SECRET_INVALID");
  }
  const id = header(headers, "webhook-id");
  const timestamp = header(headers, "webhook-timestamp");
  const signatures = header(headers, "webhook-signature");
  if (!id || !timestamp || !signatures) {
    throw fail("WEBHOOK_HEADER_MISSING");
  }
  if (!/^\d{1,12}$/.test(timestamp)) {
    throw fail("WEBHOOK_TIMESTAMP_INVALID");
  }
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > toleranceSeconds) {
    throw fail("WEBHOOK_TIMESTAMP_OUT_OF_RANGE");
  }
  const subtle = globalThis.crypto?.subtle;
  if (!subtle) throw fail("WEBHOOK_CRYPTO_UNAVAILABLE");
  const raw =
    typeof body === "string" ? encoder.encode(body) : new Uint8Array(body);
  const prefix = encoder.encode(`${id}.${timestamp}.`);
  const signed = new Uint8Array(prefix.length + raw.length);
  signed.set(prefix);
  signed.set(raw, prefix.length);
  const expected = await Promise.all(
    keys.map(async (key) => {
      const hmac = await subtle.importKey(
        "raw",
        key,
        { name: "HMAC", hash: "SHA-256" },
        false,
        ["sign"],
      );
      return new Uint8Array(await subtle.sign("HMAC", hmac, signed));
    }),
  );
  // Any listed v1 signature may match; at most 16 are checked.
  const verified = signatures
    .split(" ")
    .filter(Boolean)
    .slice(0, 16)
    .some((entry) => {
      const [version, value] = entry.split(",", 2);
      const given = version === "v1" && value ? base64(value) : null;
      return given !== null && expected.some((d) => sameBytes(given, d));
    });
  if (!verified) throw fail("WEBHOOK_SIGNATURE_INVALID");
  try {
    return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(raw));
  } catch {
    throw fail("WEBHOOK_PAYLOAD_INVALID");
  }
}

Doręczenie następuje co najmniej raz. Błędy sieci, przekroczenia czasu i każda odpowiedź spoza 2xx są ponawiane, w tym przekierowania, za którymi nigdy się nie podąża. Do ośmiu prób rozkłada się na około 28 godzin: po 5 sekundach, 5 minutach, 30 minutach, 2 godzinach, 5 godzinach, a potem dwa razy po 10 godzinach, albo później, gdy odbiorca wyśle Retry-After (do jednego dnia). Odpowiedź 410 Gone wstrzymuje miejsce docelowe i anuluje oczekujące doręczenia, dopóki go nie wznowisz. Próby i błędy są widoczne w Integracjach. Wstrzymanie lub usunięcie miejsca docelowego anuluje oczekujące potwierdzenia; już przyjęte żądania mogą zakończyć się w ciągu dziesięciu sekund. Zapisane potwierdzenia doręczeń nie zawierają rekordów firm, wyszukiwanych fraz, danych logowania do kont ani treści odpowiedzi odbiorcy.

Wysyłaj wyniki do Arkuszy Google, Zapier, Make lub n8n

Poniższe przepisy korzystają wyłącznie z opisanych wyżej podpisanych webhooków i REST API. Dostarczenie zawiera ID zadania, status, naliczone jednostki i liczbę wyników, ale nie wiersze wyników. Traktuj je jako sygnał: weź z niego data.job_id, a potem odczytaj zadanie i jego wiersze przez API kluczem tylko do odczytu. Te żądania są uwierzytelnione, więc wiersze zawsze pochodzą z Twojego obszaru roboczego, nawet jeśli ktoś sfałszuje dostarczenie.

Utwórz ten klucz w sekcji API i klucze z dostępem Odczyt istniejących wyników. Może on odczytywać zadania i eksporty, ale nie może uruchamiać płatnych badań. Każdy przepis korzysta z ogólnych funkcji webhooków, kodu i żądań HTTP danego narzędzia; MapsScraper.dev nie ma w tych narzędziach własnej aplikacji.

Każdy przepis wysyła dwa żądania GET z kluczem w postaci Authorization: Bearer <key>: najpierw GET /api/v1/jobs/{job_id}, a tylko gdy jego status to completed lub partial, następnie GET /api/v1/jobs/{job_id}/export po wiersze.

Jak działa dostarczanie

  • Odpowiedz dowolnym statusem 2xx w ciągu 10 sekund, a wolniejszą pracę wykonaj później.
  • Ponowienia używają tego samego nagłówka webhook-id, więc zapisz go i pomijaj dostarczenia, które już przetworzono.
  • Nieudane dostarczenie jest ponawiane, maksymalnie 8 prób w ciągu około 28 godzin, lub później, jeśli odbiorca wyśle Retry-After. Przekierowania nie są obsługiwane.
  • Odpowiedź 410 Gone wstrzymuje miejsce docelowe i anuluje oczekujące dostarczenia. Napraw odbiorcę, a następnie włącz je ponownie.

n8n

Użyj Webhook node ustawionego na natychmiastową odpowiedź, HTTP Request node dla każdego żądania z kluczem w poświadczeniu Header Auth oraz IF node między nimi, który sprawdza status. Ten przepis nie sprawdza podpisu; zamiast tego opiera się na uwierzytelnionych żądaniach.

Zapier

Wyzwalacz Catch Raw Hook w Zapier przekazuje nieprzetworzoną treść wraz z nagłówkami, więc ten przepis sprawdza też podpis. Dodaj krok Code by Zapier uruchamiający JavaScript i ustaw jego Input Data: body na surową treść, id, timestamp i signature na nagłówki webhook-id, webhook-timestamp i webhook-signature, a secret na sekret podpisu. Każdy, kto może edytować Zap, widzi ten sekret.

const crypto = require("crypto");
const { body, id, timestamp, signature, secret } = inputData;
const fresh =
  /^\d+$/.test(timestamp || "") &&
  Math.abs(Date.now() / 1000 - Number(timestamp)) <= 300;
const key = Buffer.from(
  String(secret).replace(/^whsec_/, ""),
  "base64",
);
const expected = crypto
  .createHmac("sha256", key)
  .update(`${id}.${timestamp}.${body}`)
  .digest();
const signed = String(signature || "")
  .split(" ")
  .some((entry) => {
    const [version, value = ""] = entry.split(",");
    const given = Buffer.from(value, "base64");
    return (
      version === "v1" &&
      given.length === expected.length &&
      crypto.timingSafeEqual(given, expected)
    );
  });
const valid = Boolean(id) && fresh && signed;
if (!valid) return { valid };
return { valid, job_id: JSON.parse(body).data.job_id };

Dodaj krok filtra, który przepuszcza dalej tylko wtedy, gdy valid ma wartość true, a następnie wyślij oba żądania krokami żądania GET. Zapier odpowiada na dostarczenie kodem 200 niezależnie od wyniku sprawdzenia, więc dostarczenie, które go nie przejdzie, zatrzymuje filtr, a nie odpowiedź.

Make

Użyj modułu Custom webhook, który zamienia treść JSON na pola, modułu HTTP dla każdego żądania oraz filtra między nimi, który sprawdza status. Make sam odpowiada na dostarczenie kodem 200. Podobnie jak przepis dla n8n, ten nie sprawdza podpisu i zamiast tego opiera się na uwierzytelnionych żądaniach.

Google Sheets

Google Sheets samo pobiera wiersze, zamiast odbierać wysyłane do niego dane. W arkuszu otwórz Extensions, a potem Apps Script, i wklej ten skrypt. W Project Settings dodaj właściwość skryptu o nazwie MAPSSCRAPER_API_KEY z kluczem API tylko do odczytu, aby klucz nie trafił do komórek ani do kodu.

const API = "https://mapsscraper.dev/api/v1";

function getJson(path) {
  const key = PropertiesService.getScriptProperties()
    .getProperty("MAPSSCRAPER_API_KEY");
  if (!key) throw new Error("Add the MAPSSCRAPER_API_KEY script property.");
  const response = UrlFetchApp.fetch(API + path, {
    headers: { Authorization: "Bearer " + key },
    muteHttpExceptions: true,
  });
  const status = response.getResponseCode();
  const text = response.getContentText();
  if (status !== 200) {
    throw new Error("HTTP " + status + ": " + text.slice(0, 200));
  }
  return JSON.parse(text);
}

// Text that starts with =, +, - or @ gets an apostrophe,
// so Sheets keeps it as text instead of running a formula.
function cell(value) {
  if (value === null || value === undefined) return "";
  if (typeof value === "object") value = JSON.stringify(value);
  const formula = typeof value === "string" && /^[=+\-@]/.test(value);
  return formula ? "'" + value : value;
}

function importLatestSearch() {
  const jobs = getJson("/jobs?page_size=25&kind=search").items;
  const job = jobs.find(
    (item) => item.status === "completed" || item.status === "partial",
  );
  if (!job) return;
  const path = "/jobs/" + job.id + "/export?format=json";
  const rows = getJson(path).items || [];
  if (!rows.length) return;
  const columns = [];
  rows.forEach((row) => Object.keys(row).forEach((name) => {
    if (!columns.includes(name)) columns.push(name);
  }));
  const values = [columns].concat(
    rows.map((row) => columns.map((name) => cell(row[name]))),
  );
  const book = SpreadsheetApp.getActive();
  const sheet =
    book.getSheetByName("MapsScraper") || book.insertSheet("MapsScraper");
  sheet.clearContents();
  sheet.getRange(1, 1, values.length, columns.length).setValues(values);
}

Uruchom funkcję importLatestSearch, aby skopiować najnowsze ukończone wyszukiwanie do arkusza o nazwie MapsScraper. Aby odświeżać je według harmonogramu, dodaj w Triggers wyzwalacz czasowy dla importLatestSearch. Apps Script przerywa uruchomienie po 6 minutach i nie może pobrać odpowiedzi większej niż 50 MB, więc większe zadania odczytuj strona po stronie przez GET /api/v1/jobs/{job_id}/results.

Ważne ograniczenia

Brak witryny oznacza, że źródło danych jej nie dostarczyło. Nie dowodzi to braku witryny firmy. Migawki rankingowe to uporządkowanie wyników jednego źródła danych, a nie pełna lokalna siatka SEO. Zbieranie opinii nie jest raportem sentymentu generowanym przez sztuczną inteligencję. Zdjęcia to metadane, a nie licencjonowane pobieranie obrazów. Cykliczne wyszukiwania zachowują migawki, porównują stabilne tożsamości i tworzą powiadomienia w skrzynce odbiorczej obszaru roboczego. Podpisane potwierdzenia webhook są opcjonalne i zawierają tylko metadane zadań; synchronizacja pól specyficzna dla CRM pozostaje oddzielna.