Cum funcționează API-ul de scraping, cerere cu cerere
Trimiți o singură cerere HTTP cu un URL. Undeva între ea și JSON-ul care se întoarce, se alege un IP de ieșire, se respectă o țară, se trece prin blocaje cu reîncercări, poate porni un browser, iar o pagină devine câmpuri. Pagina asta parcurge drumul acela în ordine. Este varianta utilă a lui „ne ocupăm noi de părțile grele” — dacă evaluezi un API de web scraping, ar trebui să știi exact care părți și unde sunt marginile.
Singura cerere pe care o trimiți
Totul este un singur POST cu un antet X-Api-Key. POST /v1/extract cu un url și o hartă fields este cererea pe care o folosesc majoritatea oamenilor de cele mai multe ori; POST /v1/fetch returnează în schimb pagina întreagă, ca HTML, text vizibil, Markdown sau octeți bruți. Nu există sesiune de stabilit, crawler de configurat sau stare de păstrat între apeluri. Fiecare parametru de mai jos este o cheie în același corp JSON.
Există și un forward proxy brut, dacă ce vrei este acces HTTP la pagină prin tine, nu date structurate. Îndreaptă orice client către el, cu cheia ta API pe post de nume de utilizator, iar aceleași controale de rotație, țară și sesiune se aplică. Restul paginii descrie ambele variante, pentru că folosesc același motor.
Pasul 1: alegerea unei ieșiri
Fiecare cerere iese implicit printr-o altă adresă IP. Nu administrezi o listă de proxy-uri, nu roteșți nimic și nu te ocupi de un pool care se învechește — trimiți un URL, iar adresa este aleasă pentru tine, proaspătă, la fiecare cerere.
Ce adrese ți se oferă depinde de planul tău. Planurilor plătite li se oferă întâi ieșiri ISP și de datacenter premium, apoi o rezervă mai adâncă de adrese verificate continuu, apoi o ultimă încercare, ca o cerere plătită să nu eșueze doar pentru că nicio ieșire nu era liberă. Planul Free este servit dintr-un pool public cu latență mare — aceeași rotație, aceleași funcții, adrese mai lente pe care țintele dificile le blochează mai des. Exact pentru asta există nivelul gratuit: prototipare și testare.
Țintirea pe țară
Adaugă "country": "us" — orice cod ISO de țară — și cererea pleacă din acea țară. Pe proxy-ul brut, se scrie -country-us adăugat la cheia ta. Contează mai mult decât pare: prețurile, disponibilitatea, limba și uneori pagina întreagă diferă în funcție de locul de unde pare că vine cererea, iar un preț din SUA luat de pe un IP european este greșit în tăcere, nu vizibil stricat.
Un detaliu de implementare pe care merită să îl spunem, pentru că nu e abordarea evidentă: rezolvăm țara fiecărei adrese direct, în loturi, nu făcând o cerere prin ea. Geolocalizarea unui proxy prin folosirea lui înseamnă că doar proxy-urile folosite recent au o țară cunoscută, deci partea din pool care poate fi țintită e mereu o fracțiune din pool-ul activ. Rezolvarea directă păstrează practic întregul pool activ țintibil geografic.
Sesiuni persistente
Rotația e alegerea corectă până în momentul în care nu mai e. Un login, un coș, un formular în mai mulți pași sau orice se află în spatele unui cookie de sesiune are nevoie de același IP pe mai multe cereri, pentru că site-ul urmărește exact tiparul în care o sesiune sare între țări în mijlocul plății. Trimite "session": "some-name" și acel nume este fixat pe un singur IP de ieșire aproximativ zece minute, apoi se rotește. Folosește un nume de sesiune distinct pentru fiecare utilizator sau job logic. Sesiunile persistente funcționează pe orice plan, inclusiv Free, și nu costă nimic în plus.
Pasul 2: reîncercarea și de ce blocajele sunt gratuite
Asta e partea pe care merită să o înțelegi bine, pentru că aici un API de scraping fie își merită prețul, fie îți facturează în tăcere propriile eșecuri.
Când vine un răspuns, decidem dacă este un răspuns al țintei sau un simptom al ieșirii pe care am ales-o. Un 403, un 429, un 407, un timeout, un 5xx, o eroare de scut CDN — acelea spun „acest IP nu e binevenit”, nu „asta conține pagina”. Așa că aruncăm complet răspunsul, trecem la altă ieșire și încercăm din nou. Nu primești niciodată așa ceva și nu ești facturat niciodată pentru așa ceva.
Direcția cealaltă este la fel de deliberată. Un 400, 401, 404, 410 sau 451 este un răspuns autentic al țintei despre cererea ta, așa că ți-l predăm direct, în loc să ardem încă trei ieșiri ca să descoperim că pagina chiar lipsește. Statusurile venite de la țintă sunt transmise nemodificate; nu traducem răspunsurile site-ului în ale noastre.
Merită știute două limite. Cererile neidempotente — un POST, un PUT — nu se reîncearcă niciodată, pentru că o reîncercare ar putea trimite un formular sau plasa o comandă de două ori; o ieșire eșuată pe un POST tot nu se facturează, doar că nu mai încercăm automat. Iar dacă toate ieșirile încercate au eșuat, primești o eroare nefacturată, nu ultima bucată de gunoi pe care am văzut-o. Facturarea la livrare înseamnă că nu avem ce să îți dăm și nu avem ce să taxăm.
Învățarea din blocaje
Când o țintă blochează o cerere cu un 403, 429 sau 451, notăm ce domeniu a blocat ce țară de ieșire pentru contul tău și rutăm data viitoare domeniul acela prin alte țări. Se întâmplă asincron și nu încetinește niciodată cererea care a declanșat-o. Pe un job lung împotriva unui site căruia nu îi place o anumită regiune, asta e diferența dintre o buclă de reîncercări și o rută care se așază.
Pasul 3: randarea, când pagina are nevoie de un browser
Multe pagini sunt o carcasă care se asamblează singură în JavaScript. Dacă preiei una simplu, primești un div gol și o referință la un bundle. Adaugă "render": true și pornim un Chrome real, lăsăm pagina să ruleze, apoi citim DOM-ul și aplicăm selectorii tăi pe ce a devenit pagina de fapt.
Combină-l cu "wait_for" setat pe un selector CSS, ca să aștepte până există acel element înainte de citire — mult mai sigur decât să ghicești o durată de așteptare, pentru că așteaptă lucrul care te interesează, nu un număr ales de tine. Pentru conținut care apare doar după interacțiune, actions rulează întâi pași scriptați: scroll, click, wait, wait_for și fill, ceea ce acoperă scroll infinit și conținut ascuns în spatele unui buton. device: "mobile" randează ca un telefon, dacă layoutul mobil e cel pe care îl vrei, iar fingerprint: true prezintă o identitate de browser coerentă cu țara aleasă — fus orar, locale, navigator.languages — astfel încât randarea să se citească drept un client real din acea regiune.
O randare nu e o preluare cu un flag setat. Descarcă tot ce cere pagina — scripturi, foi de stil, imagini, fonturi, trackere — și ocupă un slot de browser pe toată durata. Măsurat pe 14 pagini într-un browser real, o randare trage între aproximativ 1 și 300 de ori octeții aceleiași pagini preluate simplu, cu o mediană în jur de 17 ori, comerțul plin de imagini fiind la capătul de sus al intervalului. De aceea se facturează 5 unități de cerere în loc de 1, și 10 dacă vrei și un screenshot.
Tot de aceea block_resources costă 1. Sărirea imaginilor, fonturilor și media lasă complet neschimbat DOM-ul pe care îl citesc selectorii tăi și elimină în jur de 40% din transfer pe o pagină grea. Dacă extragi câmpuri, nu te uiți la poze, este valoarea implicită pe care o vrei. Randările sunt plafonate la 5 pe secundă per cont, pe orice plan; pentru orice e mai lent sau mai voluminos, POST /v1/jobs rulează asincron, cu un buget de cinci minute, și poate apela un webhook când termină.
Pasul 4: transformarea paginii în câmpuri
În punctul ăsta există un document. Ce primești înapoi depinde de ce ai cerut, iar există trei feluri de a cere.
O hartă fields de selectori CSS sau XPath returnează un obiect data cu o cheie pentru fiecare câmp, pe orice plan inclusiv Free — iar când un selector nu se compilează, câmpul este null și o intrare field_errors îl numește, așa că „pagina nu are preț” și „selectorul tău e stricat” nu sunt niciodată același răspuns. Un prompt descrie în schimb câmpurile în cuvinte obișnuite, adaptându-se la markup pe care nu l-ai văzut niciodată, pe Scale și mai sus. Iar POST /v1/fetch îți dă documentul în sine ca html, text, markdown sau octeți bruți, la o unitate de cerere.
Ce primești înapoi și cât costă
Un singur răspuns JSON, cu statusul propriu al țintei transmis mai departe și cu țara de ieșire raportată într-un antet. Până la 20 de URL-uri pot împărți un singur apel prin POST /v1/batch, fiecare facturat ca propria cerere livrată. Orice durează mult merge la POST /v1/jobs, care returnează imediat un id și fie se interoghează, fie trimite către un webhook indicat de tine — semnat cu HMAC-SHA256, ca să poți verifica că vine de la noi. Refuzurile cauzate de planul tău răspund toate cu un code stabil, citibil de mașină, și cu un fallback care îți spune ce să faci în schimb, așa că scrii o singură ramură, nu potriviri de propoziții în engleză.