GM Lead Scraper
Inne scrapery dają Ci listę adresów. Ten mówi, które trafią do właściciela.
Oficjalne Places API, 7 źródeł na firmę, walidacja MX, deduplikacja i scoring — zero telemetrii, wszystko w Twojej bazie.
Dlaczego to nie jest zwykły scraper
Zwykły scraper bierze stronę główną, wyciąga regexem i wypluwa 30% śmieci. GM Lead Scraper jest zbudowany odwrotnie – od sita, nie od łyżki.
| Zwykły scraper | GM Lead Scraper |
|---|---|
| 1 źródło: strona główna | 7 źródeł / firmę: home + /kontakt, /contact, /o-nas, /impressum, /cennik, /menu + kaskada przerywana gdy znajdzie adres w domenie. Mniej requestów, więcej trafień. |
| Ginie na fanpage’u | Moduł Facebooka: skanuje linki wychodzące z fanpage’a, pomija 14 domen (facebook, instagram, youtube, tiktok, linkedin…), bierze pierwszy prawdziwy link jako domenę firmy i przestawia podstrony. |
/[a-z@.]+/ i koniec | Deobfuskacja PRO: podwójne dekodowanie encji HTML (biuro@), 9 wzorców [at], (at), {at}, [małpa], (małpa), [dot], (dot), [kropka], (kropka) z tolerancją spacji, 3 metody: treść + data-email/data-mail + mailto:, obcinanie .,;:()"' |
| Wypluwa noreply@, *.png, example.com | 40 filtrów śmieci + 11 rozszerzeń + HEX ID: systemowe (noreply, postmaster, abuse), techniczne WP, przykładowe (example.com, twojadomena), narzędzia (sentry, shopify, cloudflare) + odrzut *.png, *.jpg, *.css, *.js, *.woff2 + ID szesnastkowe >16 znaków. Zanim sprawdzi DNS. |
| Wysyła na nieistniejące skrzynki | Walidacja DNS MX → A → AAAA + cache 12h: 3 stany (ma pocztę / ma tylko stronę / nie odpowiada), fallback gethostbyname, cache pod hashem domeny. Nie zgaduje. |
| Jedna lista, wszystko do wysyłki | Scoring 100/80/70/40/20/10 + 66 freemail + 31 ról + literówki z bezpiecznikiem: ok_self (100) = domena firmy + MX, typo_fixed (80) tylko gdy oryginał bez MX i poprawiony ma MX, ok (70), freemail (40) – 66 domen PL/INT/DE/FR/IT/CZ/NL/BE/RU, nomx (20), invalid (10). Przy remisie wygrywa ROLA (biuro, kontakt, info, sekretariat…). Reszta w polu pomocniczym. |
| Duplikaty: Jan Kowalski i Jan KOWALSKI = 2 firmy | Deduplikacja twarda: telefon sprowadzony do cyfr (różne formaty = 1 numer) + domena lower bez www, wyłączalne switchem. Lista wykluczeń (numery i domeny) sprawdzana 2x – przy zbieraniu i przy eksporcie, normalizacja przy dodawaniu, przeżywa czyszczenie bazy. |
| Eksport CSV z ID, bez polskich znaków | 4 eksporty respektujące filtry: CSV z telefonami, CSV z adresami (tylko wysyłalne), Tylko własna domena (ok_self + typo_fixed), Thunderbird (split local/domain). UTF-8 + BOM (Excel PL), średnik, 12 kolumn, nazwa pliku typ+data, prepared statements nawet przy 5000 wykluczeń. |
| Dane idą przez serwer sprzedawcy, limit fraz, brak testów | Zero telemetrii, 100% offline, 1748 linii PHP, 72 testy: własny klucz Google, darmowy limit + licznik + dzienny limit, 14 endpointów AJAX nonce + cap admin, $wpdb->prepare, createElement nie innerHTML, 30s abort, wykrywanie timeout PHP / 403 / fatal error. Licencja lokalna. |
Instalacja i baza danych
Zero zależności. Czysty JS, style WP. Dwie tabele, zero śmieci w options. Dane zostają u Ciebie.
2 tabele • 18 kolumn • 6 indeksów
- firmy: id, place_id, nazwa, email, wszystkie_emails, status, is_role, strona, domena, adres, telefon, telefon_norm, kategoria, miasto, query, ocena, opinie, data
- wykluczenia: unique para typ + wartość + powód + data
- Indeksy: unique place_id + status, miasto, kategoria, telefon_norm, domena
- dbDelta z wersjonowaniem — aktualizacje dokładają kolumny bez utraty danych
Dlaczego to wyjątkowe?
- Check schematu tylko przy zmianie wersji, nie przy każdym wejściu
- uninstall.php czyści opcje i cache DNS, ale ZOSTAWIA firmy — kasowanie wymaga odkomentowania 2 linii
- Daty wg strefy WP, nie serwera — licznik API zeruje się o północy WP
Zbieranie firm z Google
Oficjalne Places API v1 — places:searchText. Nie scrap HTML. Frazy x obszary = iloczyn. Jednym przebiegiem całe miasto.
- Filtry wstępne: min/max opinii i oceny — auto-off gdy oceny OFF + info w UI
- Etykiety miasta/kategorii + query źródłowe do eksportu
- Check place_id — nigdy 2x. Liczniki: duplikaty / wykluczenia / filtry
- Firmy bez strony też do bazy (BRAK) — zostaje telefon
- Timeout 20s na request Google
Silnik wyszukiwania adresów
7 źródeł na firmę. Kaskada przerywa się gdy znajdzie adres w domenie firmy — na łatwych nie pobiera podstron w ogóle.
7 źródeł
- Strona główna
- /kontakt, /contact, /o-nas, /impressum, /cennik, /menu
- Timeout 8s / stronę, max 3 redirecty, header GM-Lead-Scraper/vX
- HTTP 400+ pomijane, <400 bajtów = pusta (odsiew zaślepek hostingu)
- Max 5 unikalnych / firmę, deduplikacja w obrębie strony
Deobfuskacja i parsing
- Podwójne dekodowanie encji HTML: biuro@firma.pl → działa
- 9 wzorców: [at] (at) {at} [małpa] (małpa) [dot] (dot) [kropka] (kropka) — spacje i case tolerowane
- 3 metody: regex w treści + data-email/data-mail + mailto:
- Obcinanie .,;:()”’ z końca, lowercasing, walidacja składni
Moduł Facebooka
Gdy Google zwraca fanpage — sam odnajduje prawdziwą domenę firmy.
1. Skanuje wszystkie linki wychodzące z fanpage’a
2. Pomija 14 domen: facebook, instagram, fb.com, fbcdn, whatsapp, messenger, youtube, twitter, x, tiktok, google, apple, linkedin, pinterest
3. Pierwszy link poza listą = prawdziwa strona → pobiera i dokłada do materiału
4. Jeśli domena nieznana — ustala ją i przestawia bazę dla 6 podstron (nie sprawdza /kontakt na facebook.com)
Odsiew śmieci
40 wzorców blacklist
- Systemowe: noreply, no-reply, donotreply, nie-odpowiadaj, postmaster, abuse, hostmaster, mailer-daemon
- Techniczne WP + przykładowe: example.com, domain.com, yourdomain, twojadomena, adres@, nazwa@, imie@, test@test, admin@admin
- Domeny narzędzi w kodzie: sentry, wixpress, shopify, squarespace, godaddy, cloudflare, gravatar, jquery, bootstrapcdn, schema.org
Fałszywe maile
- 11 rozszerzeń: png, jpg, jpeg, gif, svg, webp, css, js, woff, woff2, ico
- HEX ID: część nazwy >16 znaków tylko [0-9a-f] = odrzut
Walidacja DNS
Statusy i ranking
10 stanów. Ranking punktowy wybiera najlepszy z 5. Reszta w polu pomocniczym jako adres + status.
| Status | Znaczenie | Punkty |
|---|---|---|
| ok_self | Adres w tej samej domenie co firma, MX potwierdzony | 100 |
| typo_fixed | Poprawiona literówka z MX | 80 |
| ok | Inna domena firmowa, nie freemail | 70 |
| freemail | Gmail, WP, O2, Onet itd. | 40 |
| nomx | Domena ma stronę, brak poczty | 20 |
| invalid | Domena nie istnieje | 10 |
| found / to_process / bounced / no_email | found = bez walidacji, bounced = ręcznie po odbiciu | – |
Przy remisie wygrywa adres roli — bo to skrzynka faktycznie czytana.
Freemail — 66 domen
Oddziela pośredników od właścicieli. Kluczowe dla eksportu „Tylko własna domena”.
PL, INT, DE, FR, IT, CZ, NL, BE, RU — pełna lista w kodzie.
Adresy roli — 31 nazw
Dopasowanie dokładne lub z myślnikiem/kropką: biuro.gdynia@ i sales-eu@ też łapie. Flaga niezależna od statusu, nie obniża oceny. Etykieta ROLA w tabeli i eksporcie.
Poprawianie literówek — 37 wpisów + 6 reguł
Mapa
- Gmail: gamil, gmial, gmai, gmil, gmaill, gmail.con/.cm/.co/.pl
- WP: wp.ol, wp.p, wp.pll, wp.lp + O2, Onet, Interia, Gazeta…
- Reguły: .con→.com, .comm/.cim/.ocm→.com, .pl.pl→.pl, .ol→.pl
Bezpiecznik
Korekta tylko gdy oryginał nie ma MX i poprawiona ma MX. Bez tego nie zgaduje.
Deduplikacja i wykluczenia
- Po telefon_norm (same cyfry) — różne formaty = jeden numer. Po domenie: lower + bez www. Wyłączalne jednym switchem.
- Lista wykluczeń: numery i domeny, sprawdzana przy zbieraniu i eksporcie
- Dodawanie pojedyncze + import masowy z auto-rozpoznaniem numer vs domena
- Normalizacja przy dodawaniu, odporność na duplikaty, widok do 5000 z kasowaniem
- Wykluczenia przeżywają czyszczenie bazy firm
Przebieg pracy
Praca z wynikami
- Filtr miasto i kategoria — listy z bazy, nie z configu. Filtr status (9 wartości) + min/max opinii
- Wyszukiwanie live debounce 400ms po: nazwie, telefonie, domenie, emailu
- 50/100/200 wierszy, sortowanie po opinii malejąco — największe na górze
- 9 liczników nad tabelą z paskiem koloru: łącznie, z telefonem, z adresem, własna domena, inna domena, freemail, bez poczty, do przetworzenia — respektują filtry
- ROLA etykieta, link do strony nowa karta + noopener, BOUNCE (oznacza i dodaje domenę do wykluczeń 1 klikiem) + usuń z confirmem
Eksport
4 przyciski, każdy respektuje filtry i wykluczenia. Bez reloadu.
Zakresy
- CSV z telefonami: wszystkie z numerem
- CSV z adresami: ok_self, ok, typo_fixed, freemail, found
- Tylko własna domena: ok_self + typo_fixed — najwęższa, najpewniejsza
- Thunderbird: jak wyżej + split local/domain do książki
Format
- UTF-8 + BOM — polskie znaki w Excelu
- Separator średnik, 12 kolumn: nazwa, telefon, adres, status, rola, strona, domena, miasto, kategoria, query, opinie, ocena
- Nazwa pliku: typ + data. Wykluczenia przez prepared statements
Narzędzia
- Przeliczenie statusów wg obecnych reguł, partie 20, z progresem, zero zapytań Google. Odbudowuje kandydatów — może wybrać lepszy niż poprzednio
- Naprawa danych: uzupełnia brakujące domeny i telefon_norm + mapowanie statusów ze starszych wersji
- Zerowanie licznika API + czyszczenie bazy firm z zachowaniem wykluczeń + confirm + warning nieodwracalności
Klucz Google i błędy
Konfiguracja
- Pole password + podgląd + placeholder początku klucza
- 4 linki prosto do Google Cloud: projekt, włączenie Places API, limit, klucz — ponumerowane
- Walidacja formatu przed requestem — literówka nie zjada limitu
- Test połączenia zwraca liczbę wyników
6 tłumaczonych błędów Google
- Usługa niewłączona / brak płatności / klucz ograniczony / nieprawidłowy / limit / brak uprawnień
- + składnia zapytania i awaria Google
- Każdy z przyciskiem gdzie naprawić + podpowiedzią
- Oryginalna odpowiedź Google zawsze po rozwinięciu
- Dzienny limit w panelu, zerowany o północy WP
100% offline
- Sprawdzanie lokalne, zero połączeń poza Google
- Data RRRR-MM-DD lub bez limitu / unlimited / puste = bez limitu
- Ważna do końca ostatniego dnia, licznik dni po datach (nie sekundach)
- Przypomnienie 30 dni przed + notice WP, osobny komunikat w dniu wygaśnięcia
Co po wygaśnięciu?
- Blokowany tylko Start — napis wprost na przycisku
- Baza, filtry, wyszukiwanie, narzędzia, 4 eksporty — działają
- 4 odznaki: zielona bez limitu, zielona z datą, pomarańczowa dni, czerwona po terminie
- Zakładka licencji mówi wprost: brak telemetrii, brak wysyłki info
Bezpieczeństwo
- 14 endpointów AJAX — każdy nonce + cap admin. Panel osobno cap i die()
- Formularz ustawień osobny nonce, wszystkie zapytania przez $wpdb->prepare
- Input sanitized, output escaped, tabela przez createElement nie innerHTML, href jako property
- Brak obniżania weryfikacji certyfikatu + komunikat jak naprawić
- Klucz API nigdy nie wypisywany jawnie w DOM
Odporność interfejsu
- Żadne zapytanie nie wisi — po 30s abort z komunikatem
- Wykrywanie pustej odpowiedzi (timeout PHP), nie-JSON z kodem HTTP, 403 jako możliwa blokada przez security plugin, fatal error PHP
- Surowa odpowiedź po rozwinięciu, obcięta do rozsądnej długości
- Przyciski blokowane na czas requestu, błędy nigdy jako [object Object]