Cum să extragi date din TripAdvisor cu Python (fără să fii blocat)

Ultima actualizare la April 17, 2026
Cum să extragi date din TripAdvisor cu Python (fără să fii blocat)

Săptămâna trecută am încercat să extrag evaluările hotelurilor și numărul de recenzii pentru aproximativ 200 de proprietăți din trei orașe europene, direct din TripAdvisor. Primul meu script — un simplu requests.get() cu headere implicite — a primit un frumos 403 Forbidden la fiecare cerere. Nici măcar un byte de date utilă.

TripAdvisor este una dintre cele mai bogate surse publice de date din industria turismului: peste 1 miliard de recenzii, peste 8 milioane de listări de afaceri și aproximativ 460 de milioane de vizitatori lunari unici. Influențează mai mult de $60 miliarde în cheltuieli anuale pentru călătorii. Dar să obții aceste date programatic? Aici lucrurile se complică. TripAdvisor folosește detectarea de boți DataDome, Cloudflare WAF, fingerprinting TLS și provocări JavaScript — un sistem de apărare în mai multe straturi care blochează majoritatea încercărilor naive de scraping înainte să înceapă măcar. Acest ghid este resursa completă pe care mi-aș fi dorit s-o am: o comparație directă între trei abordări Python de scraping (plus o opțiune fără cod), cod complet pentru fiecare, o secțiune structurată de depanare anti-bot și pattern-uri reutilizabile care funcționează pentru hoteluri, restaurante și atracții. Indiferent dacă ești începător în Python sau dezvoltator cu experiență, ghidul acesta ar trebui să te scutească de multe erori 403 pierdute degeaba.

Nu vrei să scrii cod? Extrage datele din TripAdvisor pe varianta simplă

Vreau să spun lucrurile foarte clar. Mulți dintre cei care caută „scrape TripAdvisor with Python” nu sunt, de fapt, hotărâți să scrie cod. Ei vor doar datele — nume de hotel, evaluări, număr de recenzii, prețuri — rapid, într-un spreadsheet. Dacă te regăsești în asta, există o cale mult mai scurtă.

Thunderbit este o extensie Chrome bazată pe AI, creată de noi, care poate citi orice pagină TripAdvisor și poate sugera automat coloanele potrivite pentru extragere. Fluxul de lucru chiar se rezumă la două clickuri:

  1. Deschide o pagină de listare TripAdvisor (de exemplu, rezultatele pentru „Hotels in Paris”).
  2. Apasă „AI Suggest Fields” în bara laterală Thunderbit. AI-ul scanează pagina și propune coloane precum Hotel Name, Rating, Review Count, Price și Location.
  3. Apasă „Scrape”. Thunderbit extrage datele din fiecare listare de pe pagină — și gestionează automat paginarea dacă ai nevoie de mai multe rezultate.
  4. Exportă în Excel, Google Sheets, Airtable sau Notion. Exporturile sunt gratuite pe orice plan.

Thunderbit funcționează pentru hoteluri, restaurante și atracții fără nicio modificare de configurație — AI-ul se adaptează la ce există pe pagină. Pentru rezultate paginabile, detectează automat butoanele „Next” și scroll-ul infinit. Și pentru că rulează în browserul tău Chrome real, moștenește cookie-urile sesiunii și fingerprint-ul browserului, ceea ce îi oferă un avantaj natural în fața detectării de boți.

Poți încerca direct cu Thunderbit Chrome Extension — versiunea gratuită include 6 pagini/lună, suficient cât să testezi fluxul.

Dacă ai nevoie de control programatic, logică de parsare personalizată sau plănuiești să extragi peste 10.000 de pagini, Python rămâne soluția potrivită. Continuă să citești.

De ce să extragi date din TripAdvisor cu Python?

Datele din TripAdvisor au un impact direct și măsurabil în business. Un studiu Cornell University a arătat că o creștere de 1 punct a Global Review Index al unui hotel, pe scala de 100 de puncte, duce la o creștere de 0,89% a tarifului mediu zilnic și de 1,42% a veniturilor per cameră disponibilă. Un alt studiu ScienceDirect a arătat că o creștere exogenă de 1 stea în ratingul TripAdvisor se traduce prin 55.000–75.000 USD venit suplimentar anual pentru un hotel mediu. Recenziile nu sunt doar metrici de imagine — ele generează venituri.

Așa folosesc diferite echipe datele din TripAdvisor:

Caz de utilizareCine beneficiazăDate necesare
Analiza concurenței în hotelărieLanțuri hoteliere, revenue managersEvaluări, prețuri, volum de recenzii, facilități
Cercetare de piață pentru restauranteGrupuri de restaurante, branduri foodTipuri de bucătărie, intervale de preț, sentimentul recenziilor
Urmărirea trendurilor pentru atracțiiTouroperatori, organizații de turismClasamente de popularitate, tipare sezoniere
Analiză de sentimentCercetători, analiști de dateText complet din recenzii, ratinguri pe stele, date
Generare de lead-uriEchipe de vânzări, agenții de turismNume de afaceri, date de contact, locații

De ce Python, mai exact? Trei motive. Primul este ecosistemul: BeautifulSoup, Selenium, Playwright, Scrapy, httpx, pandas — Python are biblioteci mai mature pentru scraping și analiză de date decât orice alt limbaj. Al doilea: 71,7% dintre dezvoltatorii de web scraping folosesc Python, ceea ce înseamnă suport mai bun din comunitate, mai multe răspunsuri pe StackOverflow și ghiduri mai actualizate. Al treilea: avantajul de pipeline — poți face scraping cu BeautifulSoup, curățare cu pandas, analiză de sentiment cu Hugging Face Transformers și dashboard-uri — toate într-un singur limbaj. Fără schimbări de context.

Trei moduri de a extrage TripAdvisor cu Python (comparativ)

Fiecare ghid concurent alege o singură abordare și insistă pe ea. Nu e prea util când încerci să decizi înainte să scrii cod. Iată tabelul de comparație pe care mi-aș fi dorit să mi-l dea cineva:

AbordareVitezăSuport JSRezistență anti-botComplexitateCel mai potrivit pentru
requests + BeautifulSoup⚡ Rapid (~120–200 pagini/min brut)❌ Niciunul⚠️ ScăzutăUșorPagini statice de listare, proiecte mici
Selenium / Browser headless🐢 Lent (~8–20 pagini/min)✅ Complet⚠️ MedieMedieConținut dinamic, click pe „Read more”, bannere de cookie-uri
JSON ascuns / API GraphQL⚡⚡ Cel mai rapid (~200–600 pagini/min brut)N/A✅ Mai mareăGreuExtragere la scară mare de recenzii/hoteluri
Fără cod (Thunderbit)⚡ Rapid✅ Integrat✅ IntegratCel mai ușorPersoane non-tech, exporturi rapide, ocazionale

Câteva nuanțe importante. Vitezele brute de mai sus sunt teoretice — limitările de ritm ale TripAdvisor (~10–15 cereri pe minut per IP) reduc debitul real la aproximativ 10 pagini/minut per IP, indiferent de abordare. Metoda cu JSON ascuns îți oferă cele mai multe date per cerere, ceea ce înseamnă mai puține cereri totale și o expunere mai mică la rate limiting. Selenium este de 5 ori mai lent decât abordările bazate pe requests în testele reale, dar este singura opțiune atunci când trebuie să apeși butoane sau să randăm JavaScript.

Restul ghidului trece prin toate cele trei metode Python, cu cod complet. Alege-o pe cea care se potrivește situației tale sau combină-le (eu folosesc adesea requests+BS4 pentru pagini de listare și JSON ascuns pentru pagini de detaliu).

Cum îți configurezi mediul Python

Înainte să începem, hai să pregătim mediul. Ai nevoie de Python 3.10+ (recomand 3.12 sau 3.13 — toate pachetele majore le suportă fără probleme cunoscute).

Instalează totul dintr-o dată:

pip install requests beautifulsoup4 selenium httpx parsel pandas curl-cffi

Note despre pachete:

  • requests (2.33.1) — cereri HTTP, necesită Python 3.10+
  • beautifulsoup4 (4.14.3) — parsare HTML
  • selenium (4.43.0) — automatizare browser, necesită Python 3.10+
  • httpx (0.28.1) — client HTTP async
  • parsel (1.11.0) — selectori CSS/XPath (mai ușor decât BS4)
  • pandas (3.0.2) — export de date, necesită Python 3.11+
  • curl_cffi (0.15.0) — impersonare a fingerprint-ului TLS (esențială pentru a trece de Cloudflare)

ChromeDriver: Dacă folosești Selenium, veste bună — începând cu Selenium 4.6+, Selenium Manager descarcă și cache-uiește automat binarul ChromeDriver corect. Nu ai nevoie de instalare manuală. Se ocupă dinamic de potrivirea versiunilor, așa că nu trebuie să îți faci griji cu nepotriviri între versiunea de Chrome și driver.

Medii virtuale (recomandat):

python -m venv tripadvisor-scraper
source tripadvisor-scraper/bin/activate  # macOS/Linux
tripadvisor-scraper\Scripts\activate     # Windows

Abordarea 1: Scrape TripAdvisor cu Requests și BeautifulSoup

Aceasta este cea mai simplă abordare. Funcționează bine pentru paginile de listare (rezultate de căutare pentru hoteluri, liste de restaurante) unde datele de care ai nevoie există în HTML-ul static. Fără browser, fără randare JavaScript, consum minim de resurse.

Cum funcționează pattern-urile URL de la TripAdvisor

URL-urile TripAdvisor urmează modele previzibile, în funcție de categorie:

  • Hoteluri: https://www.tripadvisor.com/Hotels-g{locationId}-{Location_Name}-Hotels.html
  • Restaurante: https://www.tripadvisor.com/Restaurants-g{locationId}-{Location_Name}.html
  • Atracții: https://www.tripadvisor.com/Attractions-g{locationId}-Activities-{Location_Name}.html

Paginarea folosește parametrul oa (offset anchors), introdus în URL. Fiecare pagină afișează 30 de rezultate:

  • Pagina 1: URL-ul de bază (fără parametru oa)
  • Pagina 2: Hotels-g187768-oa30-Italy-Hotels.html
  • Pagina 3: Hotels-g187768-oa60-Italy-Hotels.html

Pentru paginile de recenzii, parametrul de offset este or, cu increment de 10:

  • Pagina 1: Reviews-or0-Hotel_Name.html
  • Pagina 2: Reviews-or10-Hotel_Name.html

Ca să obții recenzii în toate limbile, adaugă ?filterLang=ALL la URL.

Trimiterea cererilor cu headere realiste

TripAdvisor verifică agresiv headerele. O cerere cu headerele implicite din Python este blocată imediat. Trebuie să mimezi un browser Chrome real:

import requests
import time
import random

session = requests.Session()

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Referer": "https://www.tripadvisor.com/",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Sec-CH-UA": '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
    "Sec-CH-UA-Mobile": "?0",
    "Sec-CH-UA-Platform": '"Windows"',
}

session.headers.update(headers)

url = "https://www.tripadvisor.com/Hotels-g187147-Paris_Ile_de_France-Hotels.html"
response = session.get(url)

print(f"Status: {response.status_code}")
print(f"Content length: {len(response.text)} characters")

Detaliu important: TripAdvisor validează faptul că header-ele User-Agent și Sec-CH-UA sunt consistente. Dacă pretinzi că ești Chrome 135 în User-Agent, dar în Sec-CH-UA apare Chrome 120, vei fi marcat. Rotirea trebuie făcută la nivel de set complet de headere, nu pe headere individuale.

Parsarea listărilor cu BeautifulSoup

După ce primești un răspuns valid, extragi datele cu BeautifulSoup. TripAdvisor folosește atribute data-automation și data-test-attribute care sunt mai stabile decât numele claselor CSS (care se schimbă frecvent):

from bs4 import BeautifulSoup

soup = BeautifulSoup(response.text, "html.parser")

# Găsește toate cardurile cu listări de hoteluri
cards = soup.select('div[data-test-attribute="location-results-card"]')

hotels = []
for card in cards:
    # Numele hotelului
    title_el = card.select_one('div[data-automation="hotel-card-title"]')
    name = title_el.get_text(strip=True) if title_el else None

    # Link către pagina de detaliu
    link_el = card.select_one('div[data-automation="hotel-card-title"] a')
    link = "https://www.tripadvisor.com" + link_el["href"] if link_el else None

    # Evaluarea
    rating_el = card.select_one('[data-automation="bubbleRatingValue"]')
    rating = rating_el.get_text(strip=True) if rating_el else None

    # Numărul de recenzii
    review_el = card.select_one('[data-automation="bubbleReviewCount"]')
    review_count = review_el.get_text(strip=True).replace(",", "").split()[0] if review_el else None

    hotels.append({
        "name": name,
        "rating": rating,
        "review_count": review_count,
        "url": link,
    })

print(f"Am găsit {len(hotels)} hoteluri pe această pagină")
for h in hotels[:3]:
    print(h)

O observație despre selectori: TripAdvisor folosește nume de clase CSS obfuscate (precum FGwzt, yyzcQ) care se schimbă la fiecare update al site-ului. Atributele data-automation și data-test-target sunt mult mai stabile. Preferă întotdeauna atributele de date în locul claselor.

Gestionarea paginării

Ca să extragi mai multe pagini, parcurge parametrul de offset cu o pauză politicoasă între cereri:

import pandas as pd

all_hotels = []
base_url = "https://www.tripadvisor.com/Hotels-g187147-oa{offset}-Paris_Ile_de_France-Hotels.html"

for page in range(5):  # Primele 5 pagini
    offset = page * 30
    url = base_url.format(offset=offset) if page > 0 else "https://www.tripadvisor.com/Hotels-g187147-Paris_Ile_de_France-Hotels.html"

    response = session.get(url)
    if response.status_code != 200:
        print(f"Pagina {page + 1}: status {response.status_code}, opresc.")
        break

    soup = BeautifulSoup(response.text, "html.parser")
    cards = soup.select('div[data-test-attribute="location-results-card"]')

    for card in cards:
        title_el = card.select_one('div[data-automation="hotel-card-title"]')
        name = title_el.get_text(strip=True) if title_el else None
        rating_el = card.select_one('[data-automation="bubbleRatingValue"]')
        rating = rating_el.get_text(strip=True) if rating_el else None
        review_el = card.select_one('[data-automation="bubbleReviewCount"]')
        review_count = review_el.get_text(strip=True).replace(",", "").split()[0] if review_el else None

        all_hotels.append({"name": name, "rating": rating, "review_count": review_count})

    print(f"Pagina {page + 1}: {len(cards)} hoteluri găsite")
    time.sleep(random.uniform(3, 7))  # Pauză aleatorie pentru a evita rate limiting

df = pd.DataFrame(all_hotels)
print(f"\nTotal hoteluri extrase: {len(df)}")

time.sleep(random.uniform(3, 7)) este important. Pragul de rate limiting al TripAdvisor este aproximativ 10–15 cereri pe minut per IP. Dacă mergi mai repede, declanșezi CAPTCHA-uri sau erori 429.

Limitările acestei abordări

Unde se rupe metoda requests+BS4? Eșuează când:

  • TripAdvisor livrează conținut randat prin JavaScript (unele pagini de rezultate necesită JS)
  • Textul recenziilor este trunchiat în spatele butonului „Read more”
  • Măsurile anti-bot escaladează la provocări JavaScript sau CAPTCHA-uri
  • Ai nevoie de date care apar doar după randare client-side (prețuri, disponibilitate)

Pentru astfel de scenarii, ai nevoie fie de Selenium (Abordarea 2), fie de metoda cu JSON ascuns (Abordarea 3).

Abordarea 2: Scrape TripAdvisor cu Selenium (browser headless)

Selenium pornește un browser real, ceea ce înseamnă că poate reda JavaScript, poate apăsa butoane, poate gestiona bannerele de consimțământ pentru cookie-uri și poate interacționa cu conținut dinamic. Costul: este cam de 5 ori mai lent și consumă 300–500 MB RAM per instanță de browser.

Configurarea Selenium cu setări anti-detectare

Din start, Selenium este ușor de detectat. Fingerprinting-ul TripAdvisor îl identifică imediat. Trebuie să dezactivezi flag-urile de automatizare:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

options = Options()
options.add_argument("--headless=new")  # Folosește modul headless nou (Chrome 112+)
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_argument("--window-size=1920,1080")
options.add_argument("user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)

driver = webdriver.Chrome(options=options)

# Elimină proprietatea webdriver din navigator
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})"
})

Este suficient pentru TripAdvisor? Pentru scraping la scară mică (sub 50 de pagini), această configurație, combinată cu proxy-uri rezidențiale, de obicei funcționează. Pentru volume mai mari, s-ar putea să ai nevoie de undetected-chromedriver sau nodriver — protecția DataDome a TripAdvisor analizează peste 1.000 de semnale per cerere, inclusiv fingerprint-uri TLS pe care Selenium-ul standard nu le poate imita.

Extragerea rezultatelor pentru hoteluri cu Selenium

import time
import random

url = "https://www.tripadvisor.com/Hotels-g187147-Paris_Ile_de_France-Hotels.html"
driver.get(url)

# Așteaptă încărcarea cardurilor hotelurilor
wait = WebDriverWait(driver, 15)
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div[data-test-attribute="location-results-card"]')))

# Gestionează popup-ul pentru cookie-uri (dacă apare)
try:
    cookie_btn = driver.find_element(By.ID, "onetrust-accept-btn-handler")
    cookie_btn.click()
    time.sleep(1)
except:
    pass  # Nu apare popup-ul

# Extrage datele despre hoteluri
cards = driver.find_elements(By.CSS_SELECTOR, 'div[data-test-attribute="location-results-card"]')

hotels = []
for card in cards:
    try:
        name = card.find_element(By.CSS_SELECTOR, 'div[data-automation="hotel-card-title"]').text
    except:
        name = None
    try:
        rating = card.find_element(By.CSS_SELECTOR, '[data-automation="bubbleRatingValue"]').text
    except:
        rating = None
    try:
        reviews = card.find_element(By.CSS_SELECTOR, '[data-automation="bubbleReviewCount"]').text
    except:
        reviews = None

    hotels.append({"name": name, "rating": rating, "review_count": reviews})

print(f"Am extras {len(hotels)} hoteluri")
for h in hotels[:3]:
    print(h)

Pe mașina mea, asta a durat aproximativ 8 secunde pentru o singură pagină — comparativ cu sub 1 secundă în cazul requests+BS4. Diferența de 8x se adună rapid când extragi sute de pagini.

Extinderea „Read more” și extragerea recenziilor complete

Paginile de recenzii trunchiază recenziile lungi în spatele unui buton „Read more”. Selenium îl poate apăsa:

review_url = "https://www.tripadvisor.com/Hotel_Review-g187147-d188726-Reviews-Le_Marais_Hotel-Paris_Ile_de_France.html"
driver.get(review_url)

wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div[data-reviewid]')))
time.sleep(2)

# Apasă toate butoanele „Read more”
read_more_buttons = driver.find_elements(By.XPATH, '//button//*[contains(text(), "Read more")]/..')
for btn in read_more_buttons:
    try:
        driver.execute_script("arguments[0].click();", btn)
        time.sleep(0.3)
    except:
        pass

# Extrage recenziile
review_elements = driver.find_elements(By.CSS_SELECTOR, 'div[data-reviewid]')

reviews = []
for rev in review_elements:
    try:
        title = rev.find_element(By.CSS_SELECTOR, 'div[data-test-target="review-title"]').text
    except:
        title = None
    try:
        body = rev.find_element(By.CSS_SELECTOR, 'q.IRsGHoPm span').text
    except:
        try:
            body = rev.find_element(By.CSS_SELECTOR, 'p.partial_entry').text
        except:
            body = None
    try:
        rating_class = rev.find_element(By.CSS_SELECTOR, 'div[data-test-target="review-rating"] span').get_attribute("class")
        # Rating-ul este codificat în clasă, de exemplu "ui_bubble_rating bubble_50" = 5.0
        rating_num = [c for c in rating_class.split() if "bubble_" in c][0].replace("bubble_", "")
        rating = int(rating_num) / 10
    except:
        rating = None

    reviews.append({"title": title, "body": body, "rating": rating})

print(f"Am extras {len(reviews)} recenzii")

Adăugarea rotației de proxy-uri în Selenium

Pentru scraping susținut, ai nevoie de rotație de proxy-uri. Deoarece selenium-wire a fost depreciat din ianuarie 2024, folosește suportul de proxy nativ din Chrome:

# Cu proxy fără autentificare
proxy = "http://your-proxy-address:port"
options.add_argument(f"--proxy-server={proxy}")

# Pentru proxy-uri cu autentificare, folosește o extensie Chrome sau protocolul BiDi din Selenium 4

Pentru rotația programatică a proxy-urilor, creează o nouă instanță de driver cu un proxy diferit pentru fiecare lot de cereri. Nu e elegant, dar este fiabil.

Abordarea 3: Metoda cu JSON ascuns (fără să parsezi HTML-ul)

Majoritatea ghidurilor omit complet această abordare, ceea ce e păcat — este cea mai rapidă și mai curată dintre cele trei. TripAdvisor încorporează date structurate ca JSON direct în paginile HTML — în <script> tags, ca variabile JavaScript precum pageManifest și urqlCache. Dacă extragi acest JSON, obții date mai curate (evaluări ca numere, date în format ISO) cu mai puține cereri și fără nevoie de randare JavaScript.

Cum găsești JSON-ul încorporat în sursa paginii

Ideea-cheie: poți folosi un simplu requests.get() pentru a prelua pagina, apoi să extragi JSON-ul din HTML-ul brut fără să randezi niciodată JavaScript-ul.

import requests
import re
import json

headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Referer": "https://www.tripadvisor.com/",
    "Sec-CH-UA": '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
    "Sec-CH-UA-Mobile": "?0",
    "Sec-CH-UA-Platform": '"macOS"',
}

url = "https://www.tripadvisor.com/Hotel_Review-g188590-d194317-Reviews-NH_City_Centre_Amsterdam.html"
response = requests.get(url, headers=headers)

# Extrage blob-ul JSON pageManifest
match = re.search(r"pageManifest:({.+?})};", response.text)
if match:
    page_data = json.loads(match.group(1))
    print("Am găsit datele pageManifest")
    print(f"Chei: {list(page_data.keys())[:10]}")

Cum găsești singur numele variabilei: Deschide orice pagină de hotel TripAdvisor în Chrome, click dreapta → View Page Source, apoi Ctrl+F pentru pageManifest, urqlCache sau aggregateRating. Datele sunt acolo, așteptând să fie parse-uite.

Parsarea JSON-ului și extragerea datelor structurate

TripAdvisor încorporează și date schema.org application/ld+json, care sunt și mai ușor de extras:

from parsel import Selector

sel = Selector(text=response.text)

# Extrage datele structurate JSON-LD
json_ld_scripts = sel.xpath("//script[@type='application/ld+json']/text()").getall()

for script in json_ld_scripts:
    data = json.loads(script)
    if isinstance(data, dict) and data.get("@type") in ["Hotel", "Restaurant", "TouristAttraction"]:
        print(f"Nume: {data.get('name')}")
        print(f"Evaluare: {data.get('aggregateRating', {}).get('ratingValue')}")
        print(f"Număr recenzii: {data.get('aggregateRating', {}).get('reviewCount')}")
        print(f"Interval de preț: {data.get('priceRange')}")
        print(f"Adresă: {data.get('address', {}).get('streetAddress')}")
        print(f"Coordonate: {data.get('geo', {}).get('latitude')}, {data.get('geo', {}).get('longitude')}")
        break

Datele JSON-LD sunt încorporate în HTML-ul static și NU necesită randare JavaScript. Îți oferă numele proprietății, ratingul agregat, numărul de recenzii, adresa, coordonatele, intervalul de preț și URL-urile fotografiilor — totul fără să parsezi niciun tag HTML.

Pentru date mai bogate (recenzii individuale, distribuția ratingurilor, listele de facilități), ai nevoie de obiectul urqlCache:

# Extrage urqlCache pentru date detaliate despre recenzii
cache_match = re.search(r'"urqlCache"\s*:\s*({.+?})\s*,\s*"redux"', response.text)
if cache_match:
    cache_data = json.loads(cache_match.group(1))
    # Parcurge cache-ul ca să găsești date despre recenzii
    for key, value in cache_data.items():
        if "reviews" in str(value).lower()[:100]:
            reviews_data = json.loads(value.get("data", "{}")) if isinstance(value, dict) else None
            if reviews_data:
                print(f"Am găsit o intrare de review cache: {key[:50]}...")
                break

Căile exacte din JSON se mai schimbă din când în când când TripAdvisor își actualizează frontend-ul, dar structura generală — JSON-LD pentru date de sumar, urqlCache pentru date detaliate — a rămas stabilă ani la rând.

Cum inversezi API-ul GraphQL al TripAdvisor (avansat)

Pentru extragere la scară mare, endpoint-urile GraphQL de la TripAdvisor returnează direct date structurate. Aceasta este cea mai rapidă metodă, dar și cea care necesită cea mai multă întreținere.

import httpx
import random
import string

def generate_request_id():
    """Generează valoarea header-ului X-Requested-By"""
    random_chars = ''.join(random.choices(string.ascii_letters + string.digits, k=180))
    return f"TNI1625!{random_chars}"

# Caută hoteluri în Paris
search_payload = [{
    "variables": {
        "request": {
            "query": "hotels in Paris",
            "limit": 10,
            "scope": "WORLDWIDE",
            "locale": "en-US",
            "scopeGeoId": 1,
            "searchCenter": None,
            "types": ["LOCATION", "QUERY_SUGGESTION", "RESCUE_RESULT"],
            "locationTypes": ["GEO", "AIRPORT", "ACCOMMODATION", "ATTRACTION", "EATERY", "NEIGHBORHOOD"]
        }
    },
    "extensions": {
        "preRegisteredQueryId": "84b17ed122fbdbd4"
    }
}]

graphql_headers = {
    "Content-Type": "application/json",
    "Accept": "*/*",
    "Accept-Language": "en-US,en;q=0.9",
    "Origin": "https://www.tripadvisor.com",
    "Referer": "https://www.tripadvisor.com/Hotels",
    "X-Requested-By": generate_request_id(),
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
}

with httpx.Client() as client:
    response = client.post(
        "https://www.tripadvisor.com/data/graphql/ids",
        json=search_payload,
        headers=graphql_headers
    )
    if response.status_code == 200:
        results = response.json()
        print(json.dumps(results, indent=2)[:1000])
    else:
        print(f"Cererea GraphQL a eșuat: {response.status_code}")

Pentru extragerea recenziilor prin GraphQL:

review_payload = [{
    "variables": {
        "locationId": 194317,  # NH City Centre Amsterdam
        "offset": 0,
        "limit": 20,
        "filters": {},
        "sortType": None,
        "sortBy": "date",
        "language": "en",
        "doMachineTranslation": False,
        "photosPerReviewLimit": 3
    },
    "extensions": {
        "preRegisteredQueryId": "ef1a9f94012220d3"
    }
}]

with httpx.Client() as client:
    response = client.post(
        "https://www.tripadvisor.com/data/graphql/ids",
        json=review_payload,
        headers=graphql_headers
    )
    if response.status_code == 200:
        data = response.json()
        reviews = data[0]["data"]["locations"][0]["reviewListPage"]["reviews"]
        total = data[0]["data"]["locations"][0]["reviewListPage"]["totalCount"]
        print(f"Total recenzii: {total}")
        for r in reviews[:3]:
            print(f"  [{r['rating']}/5] {r['title']} - {r['createdDate']}")

Atenție importantă: Valorile preRegisteredQueryId (precum 84b17ed122fbdbd4 pentru search și ef1a9f94012220d3 pentru recenzii) se pot rupe atunci când TripAdvisor face redeploy. Când se întâmplă asta, cererile tale pot eșua fără mesaj clar. Va trebui să redescoperi ID-urile de query urmărind cererile de rețea în DevTools-ul browserului.

De ce această metodă reduce nevoia de proxy-uri

Calculul este simplu. Cu requests+BS4, extragerea a 100 de pagini de detaliu pentru hoteluri înseamnă 100 de cereri. Cu metoda JSON ascuns, fiecare cerere returnează toate datele de care ai nevoie dintr-o singură încărcare de pagină — fără cereri suplimentare pentru extinderea recenziilor sau încărcarea conținutului dinamic. Cu GraphQL, o singură apelare API poate returna 20 de recenzii odată. Mai puține cereri = expunere mai mică la rate limiting = nevoie mai mică de rotație a proxy-urilor. Pentru proiecte mici și medii (sub 1.000 de pagini), s-ar putea să nu ai nevoie deloc de proxy-uri dacă adaugi întârzieri rezonabile.

Extrage hoteluri, restaurante și atracții cu un singur script reutilizabil

Patru din cinci ghiduri concurente acoperă doar hoteluri. Dar TripAdvisor are trei categorii principale de conținut, iar modelele de URL și câmpurile de date diferă între ele. Iată cum construiești o singură funcție care le gestionează pe toate.

Câmpuri de date disponibile per categorie

CâmpHoteluriRestauranteAtracții
Nume
Evaluare
Număr de recenzii
Preț/interval de prețUneori
Adresă
Tip de bucătărie
Durată/tip de tur
Facilități
Coordonate

Construirea unei funcții reutilizabile scrape_tripadvisor()

import requests
from bs4 import BeautifulSoup
import pandas as pd
import time
import random
import re
import json

def scrape_tripadvisor(category, location_id, location_name, num_pages=3):
    """
    Extrage listări TripAdvisor pentru hoteluri, restaurante sau atracții.

    Args:
        category: "hotels", "restaurants" sau "attractions"
        location_id: TripAdvisor geo ID (de exemplu, "187147" pentru Paris)
        location_name: Nume optimizat pentru URL (de exemplu, "Paris_Ile_de_France")
        num_pages: Numărul de pagini de extras
    """
    url_patterns = {
        "hotels": "https://www.tripadvisor.com/Hotels-g{geo}-oa{offset}-{name}-Hotels.html",
        "restaurants": "https://www.tripadvisor.com/Restaurants-g{geo}-oa{offset}-{name}.html",
        "attractions": "https://www.tripadvisor.com/Attractions-g{geo}-oa{offset}-Activities-{name}.html",
    }

    first_page_patterns = {
        "hotels": "https://www.tripadvisor.com/Hotels-g{geo}-{name}-Hotels.html",
        "restaurants": "https://www.tripadvisor.com/Restaurants-g{geo}-{name}.html",
        "attractions": "https://www.tripadvisor.com/Attractions-g{geo}-Activities-{name}.html",
    }

    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
        "Accept-Language": "en-US,en;q=0.9",
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Referer": "https://www.tripadvisor.com/",
        "Sec-CH-UA": '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
        "Sec-CH-UA-Mobile": "?0",
        "Sec-CH-UA-Platform": '"Windows"',
    }

    session = requests.Session()
    session.headers.update(headers)

    all_items = []

    for page in range(num_pages):
        offset = page * 30
        if page == 0:
            url = first_page_patterns[category].format(geo=location_id, name=location_name)
        else:
            url = url_patterns[category].format(geo=location_id, offset=offset, name=location_name)

        response = session.get(url)
        if response.status_code != 200:
            print(f"  Pagina {page + 1}: status {response.status_code}, opresc.")
            break

        soup = BeautifulSoup(response.text, "html.parser")
        cards = soup.select('div[data-test-attribute="location-results-card"]')

        for card in cards:
            item = {"category": category}
            title_el = card.select_one('div[data-automation="hotel-card-title"]') or card.select_one('a[data-automation]')
            item["name"] = title_el.get_text(strip=True) if title_el else None
            rating_el = card.select_one('[data-automation="bubbleRatingValue"]')
            item["rating"] = rating_el.get_text(strip=True) if rating_el else None
            review_el = card.select_one('[data-automation="bubbleReviewCount"]')
            item["review_count"] = review_el.get_text(strip=True) if review_el else None
            all_items.append(item)

        print(f"  Pagina {page + 1}: {len(cards)} elemente găsite")
        time.sleep(random.uniform(3, 7))

    return pd.DataFrame(all_items)

# Exemple de utilizare
print("=== Hoteluri în Paris ===")
hotels_df = scrape_tripadvisor("hotels", "187147", "Paris_Ile_de_France", num_pages=2)
print(hotels_df.head())

print("\n=== Restaurante în Roma ===")
restaurants_df = scrape_tripadvisor("restaurants", "187791", "Rome_Lazio", num_pages=2)
print(restaurants_df.head())

print("\n=== Atracții în Barcelona ===")
attractions_df = scrape_tripadvisor("attractions", "187497", "Barcelona_Catalonia", num_pages=2)
print(attractions_df.head())

O singură funcție, trei categorii, zero dublare de cod. Dacă TripAdvisor schimbă un selector, îl repari într-un singur loc.

Ce faci când TripAdvisor te blochează (depanare anti-bot)

Aceasta este secțiunea de care aveam cea mai mare nevoie când am început să fac scraping pe TripAdvisor și secțiunea pe care niciun ghid concurent nu o oferă într-o formă structurată. TripAdvisor folosește împreună DataDome (care analizează peste 5 trilioane de puncte de date pe zi) și Cloudflare WAF. Iată un tabel de diagnostic pentru cele mai comune moduri de eșec:

SimptomCauză probabilăSoluție
Răspuns HTTP 403Headere lipsă sau suspecte; provocare JS CloudflareSetează headere realiste User-Agent, Accept-Language, Referer și Sec-CH-UA. Asigură consistența headere-lor.
Pagină CAPTCHA în loc de dateRate limiting sau fingerprinting de browserRotește proxy-uri rezidențiale, adaugă întârzieri aleatorii (2–7 secunde între cereri)
HTML gol sau body blankJavaScript nu este randat de requestsTreci la Selenium sau extrage din JSON-ul ascuns din sursa paginii
Recenzii parțiale / „Read more” nu se extindeConținut încărcat la eveniment de clickFolosește .click() în Selenium sau extrage din blob-ul JSON încorporat
Recenzii doar într-o singură limbăParametrul de limbă lipseșteAdaugă ?filterLang=ALL la URL-ul recenziilor
Datele se opresc după N paginiLimitare bazată pe sesiuneRotește sesiunile, șterge cookie-urile între loturi
HTTP 1020 Access DeniedIP/ASN blocat de CloudflareTreci de la proxy-uri de datacenter la proxy-uri rezidențiale
Buclă de provocare (CAPTCHA infinit)Persistență de cookie-uri defectuoasă„Încălzește” sesiunile vizitând mai întâi homepage-ul; păstrează cookie jar-ul

Logică de retry cu exponential backoff

Niciun articol concurent nu arată efectiv acest cod. Iată o funcție reutilizabilă de retry:

import time
import random
import requests

def fetch_with_retry(session, url, max_retries=4, base_delay=2, max_delay=60):
    """
    Preia un URL cu exponential backoff și jitter.
    Rotește User-Agent la fiecare retry.
    """
    user_agents = [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
    ]

    for attempt in range(max_retries):
        # Rotește User-Agent la retry
        if attempt > 0:
            session.headers["User-Agent"] = random.choice(user_agents)

        try:
            response = session.get(url, timeout=30)

            if response.status_code == 200:
                return response

            if response.status_code == 429:
                # Respectă header-ul Retry-After dacă există
                retry_after = int(response.headers.get("Retry-After", base_delay * (2 ** attempt)))
                print(f"  Limitare de ritm (429). Aștept {retry_after}s...")
                time.sleep(retry_after)
                continue

            if response.status_code in (403, 503):
                wait = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay)
                print(f"  Am primit {response.status_code}. Retry {attempt + 1}/{max_retries} în {wait:.1f}s...")
                time.sleep(wait)
                continue

            # Alte coduri de eroare — nu retry
            print(f"  Status neașteptat {response.status_code} pentru {url}")
            return response

        except requests.exceptions.Timeout:
            wait = min(base_delay * (2 ** attempt) + random.uniform(0, 1), max_delay)
            print(f"  Timeout. Retry {attempt + 1}/{max_retries} în {wait:.1f}s...")
            time.sleep(wait)

    print(f"  Toate cele {max_retries} retry-uri au fost epuizate pentru {url}")
    return None

Rotirea headere-lor, proxy-urilor și sesiunilor

Pentru scraping susținut, păstrează un pool de seturi de headere și rotează-le împreună:

import random

HEADER_SETS = [
    {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
        "Sec-CH-UA": '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
        "Sec-CH-UA-Platform": '"Windows"',
    },
    {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
        "Sec-CH-UA": '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"',
        "Sec-CH-UA-Platform": '"macOS"',
    },
    {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36",
        "Sec-CH-UA": '"Google Chrome";v="134", "Not-A.Brand";v="8", "Chromium";v="134"',
        "Sec-CH-UA-Platform": '"Windows"',
    },
]

PROXY_LIST = [
    "http://user:pass@residential-proxy-1:port",
    "http://user:pass@residential-proxy-2:port",
    # Adaugă mai multe proxy-uri rezidențiale
]

def get_rotated_session():
    """Creează o sesiune nouă cu headere și proxy rotite."""
    session = requests.Session()

    # Alege un set aleator de headere
    header_set = random.choice(HEADER_SETS)
    base_headers = {
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language": "en-US,en;q=0.9",
        "Accept-Encoding": "gzip, deflate, br",
        "Referer": "https://www.tripadvisor.com/",
        "Sec-Fetch-Dest": "document",
        "Sec-Fetch-Mode": "navigate",
        "Sec-CH-UA-Mobile": "?0",
    }
    base_headers.update(header_set)
    session.headers.update(base_headers)

    # Alege un proxy aleator
    if PROXY_LIST:
        proxy = random.choice(PROXY_LIST)
        session.proxies = {"http": proxy, "https": proxy}

    return session

Tipul de proxy contează. Proxy-urile de datacenter sunt blocate aproape imediat de TripAdvisor (HTTP 1020 Access Denied). Proxy-urile rezidențiale sunt obligatorii pentru scraping susținut — ele trec prin ISP-uri de consum și sunt indistinguabile de utilizatorii reali. Așteaptă-te să plătești între 2,50–8,40 USD/GB, în funcție de furnizor.

Exportarea și stocarea datelor extrase din TripAdvisor

După ce ai datele, le poți pune rapid într-un format utilizabil.

Export CSV (cel mai folosit)

import pandas as pd

df = pd.DataFrame(all_hotels)
df.to_csv("tripadvisor_hotels_paris.csv", index=False, encoding="utf-8-sig")
print(f"Am exportat {len(df)} rânduri în CSV")

encoding='utf-8-sig' este important — garantează că Excel afișează corect caracterele non-latine (accente franceze, caractere chinezești etc.) când deschide CSV-ul.

Export JSON (pentru date imbricate)

Când ai recenzii imbricate în interiorul hotelurilor, JSON păstrează ierarhia:

# Structură ierarhică
hotel_data = {
    "property_id": "d194317",
    "name": "NH City Centre Amsterdam",
    "rating": 4.0,
    "reviews": [
        {"title": "Locație excelentă", "rating": 5, "date": "2025-03-15", "text": "..."},
        {"title": "Ședere medie", "rating": 3, "date": "2025-03-10", "text": "..."},
    ]
}

# Pentru analiză plată, folosește json_normalize
flat_reviews = pd.json_normalize(
    hotel_data,
    record_path="reviews",
    meta=["property_id", "name"]
)
flat_reviews.to_csv("reviews_flat.csv", index=False)

Abordarea cu două fișiere pentru date relaționale

Pentru seturi de date mari, folosesc două fișiere CSV:

  • hotels.csv — un rând per proprietate (plat)
  • reviews.csv — un rând per recenzie, cu property_id ca foreign key

Asta face ușoară combinarea în pandas, încărcarea într-o bază de date sau importul în tool-uri BI.

Dacă nu vrei să te ocupi de logica asta de export, Thunderbit îți permite să exporezi direct datele extrase în Excel, Google Sheets, Airtable sau Notion — gratuit, fără cod. Util când trebuie să împărtășești rezultatele cu colegi non-tehnici.

Sfaturi pentru un scraping responsabil și eficient pe TripAdvisor

Scraping responsabil în șase puncte:

  • Verifică robots.txt: TripAdvisor blochează complet boții de antrenare AI (GPTBot, ClaudeBot etc.). Crawlerii standard au restricții selective pe anumite căi. Verifică la tripadvisor.com/robots.txt.
  • Adaugă întârzieri: 3–7 secunde între cereri este un interval sigur. Dacă mergi mai repede de 10–15 cereri pe minut per IP, vei declanșa rate limiting.
  • Extrage doar date publice. Nu te autentifica pentru a accesa conținut restricționat.
  • Stochează datele în siguranță și respectă GDPR/CCPA dacă lucrezi cu informații personale (numele recenzorilor etc.).
  • Ia în calcul API-ul oficial TripAdvisor dacă ai nevoie de date la scară comercială. Developer Portal oferă acces la detalii de afaceri plus până la 5 recenzii și 5 fotografii per locație — limitat, dar legal și stabil.
  • Ține cont de contextul juridic: Hotărârea Curții UE în cazul Ryanair (decembrie 2025) a întărit restricțiile bazate pe Terms of Service în toată UE. Termenii de utilizare TripAdvisor interzic explicit scraping-ul. Fă scraping responsabil și pe propriul risc.

Concluzie

Asta este imaginea completă.

  • Requests + BeautifulSoup este cea mai simplă cale. Funcționează pentru pagini statice de listare, necesită configurare minimă și este rapidă. Începe de aici dacă extragi mai puțin de 100 de pagini și nu ai nevoie de conținut randat cu JavaScript.
  • Selenium face tot ce requests nu poate: conținut dinamic, butoane „Read more”, bannere de cookie-uri. Este de 5 ori mai lent și mai consumator de resurse, dar este singura opțiune când trebuie să interacționezi cu pagina.
  • JSON ascuns / GraphQL este abordarea cea mai curată și mai rapidă. Îți oferă date structurate fără să parsezi HTML-ul, reduce numărul de cereri (și implicit nevoia de proxy-uri) și returnează date într-un format pregătit pentru analiză. Necesită mai mult reverse-engineering la început și mentenanță ocazională atunci când TripAdvisor își schimbă structura datelor.

Funcția reutilizabilă scrape_tripadvisor() acoperă hoteluri, restaurante și atracții. Nu ar trebui să ai nevoie de un al doilea tutorial.

Și dacă, pe parcursul tutorialului, îți dai seama că programarea nu e pentru tine — sau ai nevoie pur și simplu de 50 de hoteluri într-un spreadsheet până la finalul zilei — extensia Chrome de la Thunderbit poate face asta în două clickuri, cu detectare de câmpuri bazată pe AI, paginare automată și export gratuit în Excel sau Google Sheets. Fără Python.

Dacă vrei să aprofundezi, avem și alte ghiduri de scraping pe blogul Thunderbit și pe canalul nostru YouTube.

Întrebări frecvente

1. Este legal să extragi date din TripAdvisor?

Termenii de utilizare TripAdvisor interzic explicit scraping-ul. Totuși, instanțele au considerat în general că extragerea datelor publice (care nu sunt în spatele unui login) nu încalcă Computer Fraud and Abuse Act din SUA. Asta spus, hotărârea Curții UE din 2025 în cazul Ryanair a întărit restricțiile bazate pe Terms of Service în Europa. Extrage doar date publice, respectă robots.txt, nu republica conținut protejat de drepturi de autor și consultă un avocat dacă folosești datele comercial.

2. Pot extrage TripAdvisor fără Python?

Da. Instrumente fără cod precum Thunderbit pot extrage TripAdvisor direct din browser, cu detectare de câmpuri bazată pe AI și paginare automată. Poți folosi și extensii de browser, add-on-uri pentru Google Sheets sau API-uri comerciale de scraping. Python îți oferă cel mai mare control și flexibilitate, dar nu este singura variantă.

3. Cum evit să fiu blocat când extrag date din TripAdvisor?

Tacticile cheie: folosește headere realiste și coerente (mai ales User-Agent și Sec-CH-UA), rotește proxy-uri rezidențiale (IP-urile de datacenter sunt blocate imediat), adaugă întârzieri aleatorii de 3–7 secunde între cereri, folosește metoda JSON ascuns pentru a minimiza numărul total de cereri, implementează retry cu exponential backoff și „încălzește” sesiunile vizitând homepage-ul înainte să extragi pagini adânci.

4. Ce date pot extrage din TripAdvisor?

Hoteluri, restaurante și atracții — inclusiv nume, evaluări, număr de recenzii, intervale de preț, adrese, coordonate, facilități (hoteluri), tipuri de bucătărie (restaurante), duratele tururilor (atracții) și text complet din recenzii, cu ratinguri individuale și date. Abordările cu JSON ascuns și GraphQL oferă cele mai bogate date per cerere.

5. Câte pagini pot extrage din TripAdvisor pe zi?

Cu un singur IP și întârzieri rezonabile: aproximativ 600–1.000 de pagini pe zi. Cu 20 de proxy-uri rezidențiale rotative: aproximativ 200.000–300.000 de pagini pe zi folosind abordări bazate pe requests. Selenium este mai lent — așteaptă-te la 8.000–12.000 de pagini pe zi per proxy. Abordarea JSON/GraphQL îți oferă cele mai multe date per cerere, așa că s-ar putea să ai nevoie de mult mai puține pagini totale pentru aceeași cantitate de informație.

Află mai multe

Ke
Ke
CTO la Thunderbit | Senior Data Scientist și expert ML Cu aproape un deceniu de experiență în machine learning și data science, Ke Shen este absolvent al Columbia University și fost Senior Data Scientist la Walmart Labs. Cu o expertiză profundă, recunoscută de colegi, în Python, R, Java și statistică, el împărtășește perspective testate în practică despre cum să transforme algoritmi AI complecși din teorie într-o arhitectură pregătită pentru producție.

Încearcă Thunderbit

Extrage leaduri și alte date în doar 2 clicuri. Susținut de AI.

Obține Thunderbit Este gratuit
Extrage date folosind AI
Transferă ușor datele în Google Sheets, Airtable sau Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week