Crawlery i logi

Czytanie access logu w 30 minut: co roboty AI naprawdę robią na witrynie

Nieregularne pomarańczowe pionowe pasy, niektóre jakby przerwane lub przesunięte, przecinają nasycone niebieskozielone tło z rastrem i wyraźnym ziarnem, obrazując sekwencję przeanalizowanych żądań naznaczonych anomaliami w logu.

Żaden panel nie powie wydawcy, czy ChatGPT, Claude albo Perplexity czytają jego strony. Search Console obejmuje wyłącznie Google, a silniki generatywne nie dostarczają niczego. Jedynym istniejącym źródłem jest dziennik żądań serwera, access log, który wytwarza każdy hosting i którego prawie nikt nie otwiera. W pół godziny, narzędziami obecnymi na dowolnym serwerze z Linuksem, można z niego wyczytać, kto przychodzi, po co i co serwer mu odpowiedział. Oto metoda, którą stosujemy, krok po kroku, wraz z poleceniami. Jak dzieli się to pół godziny: pięć minut na wyodrębnienie, pięć na liczenie według robota, dziesięć na weryfikację adresów, pięć na kody odpowiedzi, pięć na ścieżki i kadencję.

Wszystkie poniższe polecenia zakładają log w formacie combined i uruchamia się je na pliku wyodrębnionym w kroku 1. Korzystają wyłącznie z grep, awk, sort i uniq.

Co zawiera jeden wiersz

Access log w formacie combined, domyślnym dla Apache i nginx, zawiera jeden wiersz na żądanie. Każdy wiersz podaje, w tej kolejności: adres IP klienta, datę i godzinę, metodę i żądaną ścieżkę, kod odpowiedzi, rozmiar wysłanych danych, referer i user-agent. Do analizy robotów liczą się cztery pola:

PoleCo pozwala ustalić
Adres IPCzy robot jest tym, za kogo się podaje
ŚcieżkaKtóre strony są czytane, a których nie czyta nikt
Kod odpowiedziCzy robot dostał stronę, przekierowanie, błąd czy odmowę
User-agentRodzinę i rolę robota

Pierwsza weryfikacja, przed jakąkolwiek analizą: czy zapisany adres IP należy do odwiedzającego, czy do pośrednika? Za siecią CDN albo za proxy serwer widzi adres pośrednika, chyba że jest skonfigurowany do odczytu nagłówka przenoszącego adres pierwotny. Jeśli wszystkie żądania zdają się przychodzić z kilkudziesięciu adresów, opisany niżej etap weryfikacji nie będzie możliwy i trzeba poprawić konfigurację, zanim pójdzie się dalej. Tę pułapkę opisaliśmy w tekście „Co zapora ukrywa przed logami”.

Duża siatka białych kropek na granatowym tle zagęszcza się w kilku miejscach, a potem gwałtownie urywa w nieregularne luki z pomarańczowym akcentem, obrazując analizę przepływu i wykrywanie anomalii w regularnej sekwencji.

Krok 1: wyodrębnić okres i roboty AI

Pracuje się na pełnym okresie, co najmniej siedmiodniowym, bo roboty AI nie przychodzą codziennie, a wnioski wyciągnięte z dwudziestu czterech godzin są prawie zawsze fałszywe. Następnie wyciąga się wiersze, których user-agent zawiera jeden z tokenów opublikowanych przez dostawców: GPTBot, ChatGPT-User, OAI-SearchBot dla OpenAI; ClaudeBot, Claude-User, Claude-SearchBot dla Anthropic; PerplexityBot i Perplexity-User dla Perplexity; Google-Extended w logach się nie pojawia, bo jest tokenem robots.txt, a nie robotem. Listy referencyjne prowadzą OpenAI, Anthropic i Perplexity.

Wystarczy filtr grep na tych tokenach, skierowany do pliku roboczego. W serwisie medialnym średniej wielkości daje to od kilkuset do kilku tysięcy wierszy tygodniowo.

zcat -f access.log* \
  | grep -E 'GPTBot|ChatGPT-User|OAI-SearchBot|ClaudeBot|Claude-User|Claude-SearchBot|PerplexityBot|Perplexity-User' \
  > ia.log

Krok 2: policzyć według robota i według roli

Każdy dostawca utrzymuje kilka robotów, które robią co innego, i jest to najużyteczniejsze rozróżnienie w całej analizie. Robot trenowania zbiera strony na potrzeby przyszłych modeli. Robot wyszukiwania buduje indeks, z którego powstają odpowiedzi. Robot na żądanie idzie po stronę dla osoby, która właśnie zadała pytanie asystentowi. Role i tokeny opisaliśmy szczegółowo w tekście „robots.txt i AI”.

Liczy się więc wiersze według user-agent i grupuje w trzy kolumny: trenowanie, wyszukiwanie, agent użytkownika. Wynik czyta się tak:

  • Same żądania trenowania znaczą, że witryna jest zbierana, ale nic nie mówi o tym, że jest cytowana.
  • Żądania wyszukiwania wskazują, że witryna jest zindeksowana przez silnik generatywny, co jest warunkiem koniecznym cytowania.
  • Żądania agenta użytkownika są sygnałem najcenniejszym: każde odpowiada pytaniu użytkownika, dla którego asystent poszedł po tę właśnie stronę.
grep -oE 'GPTBot|ChatGPT-User|OAI-SearchBot|ClaudeBot|Claude-User|Claude-SearchBot|PerplexityBot|Perplexity-User' ia.log \
  | sort | uniq -c | sort -rn

Krok 3: sprawdzić, czy roboty są autentyczne

User-agent deklaruje się dowolnie. Każdy skrypt może przedstawić się jako GPTBot. Zanim zacznie się liczyć, sprawdza się, czy adresy IP należą do zakresów publikowanych przez poszczególnych dostawców: OpenAI, Anthropic i Perplexity publikują pliki z zakresami, a Google dokumentuje weryfikację swoich robotów przez reverse DNS. Wyciąga się odrębne adresy dla każdego user-agent, porównuje z zakresami i odrzuca to, czego w nich nie ma. Pełna metoda, wraz z pułapkami, jest w tekście „Czy robot jest naprawdę tym, za kogo się podaje?”.

Na większości audytowanych przez nas witryn je znajdujemy: żądania podające się za Googlebot albo GPTBot z adresów nienależących ani do Google, ani do OpenAI. Nie mamy do tego wolumenu, który dałoby się opublikować; sam test kosztuje jedno polecenie. Liczenie bez weryfikacji grozi mierzeniem przebranych scraperów.

# odrębne adresy jednego robota, do zestawienia z opublikowanymi zakresami
awk '/GPTBot/ {print $1}' ia.log | sort -u

Krok 4: przeczytać kody odpowiedzi

Dla każdego autentycznego robota rozbija się kody odpowiedzi. Zestawienie oczekiwane na zdrowej witrynie to niemal same kody 200, z kilkoma 304, jeśli serwer obsługuje żądania warunkowe, i kilkoma 404 na wycofanych adresach URL. Trzy anomalie zasługują na działanie:

ObserwacjaPrawdopodobna przyczynaDziałanie
Dużo kodów 301 lub 302Robot idzie za starymi adresami URL albo sitemap deklaruje adresy niekanonicznePoprawić plik sitemap, deklarować wyłącznie adresy docelowe
Kody 403 lub 429 dla autentycznego robotaOdrzuca go reguła zapory albo ograniczenie przepustowościPrzeczytać regułę ponownie: odrzuca się robota, po którym oczekuje się cytowania witryny
Kod 200 na robots.txt i nic więcejRobot czyta robots.txt i nie znajduje w nim adresów do odwiedzenia albo wszystko jest tam zabronioneSprawdzić robots.txt token po tokenie

Przypomnienie o odmowach: kod 403 zwrócony przez serwer źródłowy pojawia się w logu. Kod 403 zwrócony przez CDN już nie, bo żądanie nigdy nie dotarło. Log bez ani jednego błędu nie dowodzi więc, że żadne żądanie nie zostało odrzucone.

Poziome równoległe pasy, równomiernie rozmieszczone na tle w kolorze nocnego błękitu, są w kilku miejscach przerwane, sugerując nieregularności lub anomalie w ustrukturyzowanym przepływie.
# kod odpowiedzi to 9. pole formatu combined
awk '/GPTBot/ {print $9}' ia.log | sort | uniq -c | sort -rn

Krok 5: zobaczyć, które strony są czytane

Wielu wydawców zatrzymuje się przed tym krokiem, a to on uczy najwięcej. Zlicza się, dla każdego robota wyszukiwania i każdego agenta użytkownika, żądane ścieżki i porównuje je z listą opublikowanych stron. Zliczenie odpowiada na pytania, których nie rozstrzyga żadne inne narzędzie:

  1. Których stron nikt nigdy nie czyta? Artykuł opublikowany dwa miesiące temu, o który nie poprosił żaden robot wyszukiwania, prawdopodobnie nie jest w pliku sitemap albo nie da się do niego dojść linkiem.
  2. Które strony czytają agenci użytkownika? To te, które asystenci naprawdę cytują. Porównanie ze stronami, które chciałoby się widzieć cytowane, mówi, gdzie skierować wysiłek redakcyjny.
  3. Czy robot wraca do zmienionych stron? Jeśli strona zaktualizowana w zeszłym tygodniu nie została ponownie pobrana, sygnał świeżości nie przechodzi. Dlaczego tak się dzieje, wyjaśniliśmy w tekście „Sitemap XML: jednakowy lastmod na wszystkich adresach URL czyni plik bezużytecznym”.
# ścieżki najczęściej czytane przez robota wyszukiwania, 7. pole
awk '/OAI-SearchBot/ {print $7}' ia.log | sort | uniq -c | sort -rn | head -30

Krok 6: zanotować kadencję i powtórzyć pomiar

Ostatni odczyt dotyczy czasu. Dla każdego robota notuje się liczbę dni z wizytą w danym okresie, odstęp między dwoma przejściami i zwyczajową godzinę. Robot wyszukiwania przychodzący codziennie wpisał witrynę w swój cykl; robot, który przyszedł raz, przeczytał wszystko, a potem wracał już tylko po plik sitemap, czeka na sygnał zmiany. Ta kadencja jest punktem odniesienia dla kolejnych pomiarów, raz w tygodniu albo raz w miesiącu, zależnie od rytmu publikacji.

Trzeba też zachować plik roboczy. Okres przechowywania zależy od firmy hostingowej i od umowy, a liczy się częściej w dniach niż w miesiącach: sprawdź swój, zanim będzie potrzebny. Po tym czasie dane już nie istnieją, a pytanie zadane w grudniu o to, co działo się we wrześniu, pozostanie bez odpowiedzi.

# dni odwiedzin, potem zwykła godzina
awk '/GPTBot/ {print substr($4,2,11)}' ia.log | sort -u
awk '/GPTBot/ {print substr($4,14,2)}' ia.log | sort | uniq -c

Trzy błędy, które za pierwszym razem popełnia się prawie zawsze

Pierwszy to wyciąganie wniosków z próbki: ostatnie godziny, pierwsza strona jakiegoś narzędzia, jeden dzień. Robot mógł przeczytać całą witrynę we wtorek wieczorem i nie pojawić się przez osiem dni. Patrzy się na cały okres, zanim powie się, że nie przychodzi.

Drugi to testowanie z własnego stanowiska pracy. Wysłanie żądania z user-agent GPTBot z sieci biurowej i otrzymanie kodu 403 dowodzi wyłącznie tego, że podszywający się są odrzucani; prawdziwy robot może przejść. Jedynym wartościowym testem jest porównanie tego, co log pokazuje dla autentycznego robota, z tym, co uzyskuje się samodzielnie.

Trzeci to zapominanie o tym, co do logu nie dociera. Witryna za siecią CDN odrzucającą roboty AI będzie miała access log idealnie czysty i pusty, jeśli chodzi o AI. Czytanie logów zaczyna się od przeczytania konfiguracji CDN i od dzienników samego CDN, o ile są dostępne.

Co daje te pół godziny

Na koniec ćwiczenia wydawca wie trzy rzeczy, których nie da mu żaden panel: które silniki generatywne indeksują jego witrynę, które strony czytają i czy docierają tam realne osoby przez asystenta. To podstawa każdej strategii widoczności w AI, poprzedzająca pomiary share of voice, które opisujemy w tekście „Mierzenie widoczności w AI”. Platforma redakcyjna może ten odczyt zautomatyzować i wyświetlać codziennie; za pierwszym razem trzeba go jednak zrobić ręcznie, żeby wiedzieć, na co się patrzy.

Koncentryczne łuki z punktów rastra nakładają się na siebie na tle w kolorze nocnego błękitu, tworząc centralny motyw obrazujący uwidocznione warstwy informacji, w ziarnistej fakturze druku.
Yann Léguillon

Autor

Yann Léguillon

Prezes Mazette, wydawcy Joornal. Wspiera firmy budujące własne media: strukturę redakcyjną, widoczność w wyszukiwarkach i w odpowiedziach AI, produkcję na dużą skalę.