Powrót do strony głównej

Weryfikacja postów AI w X za pomocą Puppeteer

Artykuł analizuje problem fałszywych sukcesów agenta AI w X: 83 kliki DOM przeciwko 16 rzeczywistym postom. Opisana implementacja weryfikacji przez przeładowanie strony i skan DOM do wyodrębnienia tweet ID. Po fixie success rate osiągnął 94%. Podejście stosowalne do dowolnych platform z silent filters.

83 fałszywe sukcesy AI w X: jak naprawiamy weryfikacją
Advertisement 728x90

Weryfikacja publikacji AI-agenta na X: od 83 fałszywych sukcesów do 94% rzeczywistych

AI-agent do automatycznych komentarzy na X pokazywał 83 udane publikacje, ale rzeczywistych odpowiedzi było tylko 16. Różnica powstała z powodu niepełnej weryfikacji: kliknięcie przycisku Reply nie gwarantuje pojawienia się treści na platformie. Spam-filtry X silently dropują posty bez powiadomień.

Mechanizm publikacji przez przeglądarkę

Agent używa Puppeteer CDP do zarządzania prawdziwą przeglądarką. Otwiera wątek, wprowadza tekst i klika Reply. Pierwsza wersja funkcji sprawdzała tylko zdarzenie DOM:

const button = await page.$('[data-testid="tweetButton"]');
if (button) {  
  const disabled = await button.evaluate(el =>     
     el.getAttribute('aria-disabled') === 'true'  
  );  
  if (!disabled) {    
    await button.click();
    return true; // <-- problem wczesnego sukcesu  
  }
}
return false;

Zwrot true rejestrował sukces na poziomie DOM, bez weryfikacji platformy. Baza danych gromadziła rekordy, dashboard zieleniał.

Google AdInline article slot

X nie sygnalizuje odrzucenia: pole jest czyszczone, URL się nie zmienia. Rate limiter lub polityka treści działają w ciszy, pozostawiając przeglądarkę w iluzji sukcesu.

Problemy z ID postów

Do śledzenia agent wyodrębniał ID z page.url() po kliknięciu:

const tweetId = page.url().split('/status/')[1];

X nie przekierowuje na nowy post — URL pozostaje nadrzędnym. Wszystkie 83 rekordy otrzymały ten sam parent_tweet_id, maskując problem pod ważnymi danymi.

Google AdInline article slot

Odkrycie nastąpiło ręcznie przez analitykę X: 83 vs 16 rzeczywistych odpowiedzi.

Źródło problemu: rozbieżność między DOM a platformą

DOM: button.click() → success ✓
Browser: event fired → success ✓
X Platform: content dropped → ??? (cisza)
Database: recorded as "posted" → success ✓
Dashboard: 83 engagements → doskonale ✓
Reality: 16 actual posts

Monitoring ograniczał się do przeglądarki. Platformowe filtry — czarna skrzynka.

Rozwiązanie: post-weryfikacja z przeładowaniem

Nowa funkcja verifyReplyPosted czeka na render, przeładowuje stronę i skanuje DOM w poszukiwaniu tekstu:

Google AdInline article slot
export async function verifyReplyPosted(  
  page: Page,  
  replyText: string,  
  parentTweetId: string,
): Promise<{ verified: boolean; replyTweetId: string | null }> {
  
  await new Promise(r => setTimeout(r, 3000));  
  await page.reload({ waitUntil: "domcontentloaded" });  
  await new Promise(r => setTimeout(r, 5000));
  
  await page.evaluate("window.scrollBy(0, 1000)");  
  await new Promise(r => setTimeout(r, 2000));
  
  const result = await page.evaluate(`    
     (function() {      
         var snippet = '${safe}'; // pierwsze 30 znaków      
         var articles = document.querySelectorAll(        
           'article[data-testid="tweet"]'      
         );
         for (var i = 0; i < articles.length; i++) {        
             var textEl = articles[i].querySelector(          
                 '[data-testid="tweetText"]'        
             );    

             if (!textEl) continue;        
             var text = (textEl.innerText || '').slice(0, 60);

             if (text.indexOf(snippet.slice(0, 30)) !== -1) {

                 var links = articles[i].querySelectorAll(            
                   'a[href*="/status/"]'          
                 );          

                 return { verified: true, replyTweetId: realId };        
               }      
         }            

         return { verified: false, replyTweetId: null };    
     })()  
 `);    
  return result;
}
  • Przeładowanie zapewnia aktualny wątek bez cache.
  • Wyszukiwanie po article[data-testid="tweet"] i [data-testid="tweetText"].
  • ID jest wyodrębniane z href linków wewnątrz article.
  • Tylko verified: true jest zapisywane w bazie.

Uniwersalność podejścia

Problem nie jest unikalny dla X. Platformy (social media, formularze, płatności, deploy) silently rejectują treść.

Kluczowe zasady weryfikacji:

  • Imitować użytkownika: przeładowanie + scroll do leniwego ładowania.
  • Szukać markera (fragment tekstu) w docelowym DOM.
  • Wyodrębniać identyfikatory z rzeczywistych elementów, nie z URL/zdarzeń.
  • Anulować zapis przy braku dowodu.
  • Logować failures w czasie rzeczywistym.

Co jest ważne

  • Zdarzenia DOM ≠ sukces platformy: kliknięcie nie gwarantuje publikacji.
  • Silent drops: spam-filtry działają bez alertów, aby utrudnić obejście.
  • Weryfikacja przez skanowanie DOM: przeładowanie + wyszukiwanie tekstu/ID.
  • Metryki po poprawce: 94% verified success rate, failures są widoczne natychmiast.
  • Zastosowanie: każdy automatyczny posting/submit wymaga weryfikacji podobnej do użytkownika.

Po wdrożeniu agent rejestruje rzeczywiste publikacje, dashboard odzwierciedla prawdę. Podejście skaluje się na inne platformy z analogicznymi filtrami.

— Editorial Team

Advertisement 728x90

Czytaj dalej