Craigslist nadal przyciąga około 108 milionów wizyt miesięcznie w blisko 700 lokalnych serwisach — i wciąż nie oferuje publicznego API. Jeśli potrzebujesz uporządkowanych danych z ofert mieszkań, aut używanych, ogłoszeń o pracę czy zleceń, scraping to w praktyce jedyna opcja.
Problem w tym, że Craigslist ma własny, bezlitosny system anty-botowy. To nie jest Cloudflare ani DataDome — serwis korzysta z autorskiego limitera opartego na nginx, dopracowywanego od ponad dekady. Źle trafisz i dostaniesz twarde 403, zanim zdążysz dopić pierwszą kawę. Spędziłem sporo czasu, testując różne podejścia do zabezpieczeń Craigslist, a ten poradnik jest efektem tych prac: aktualny na 2025 rok, niezależny od kategorii tutorial w Pythonie, który obejmuje metodę ekstrakcji JSON-LD (największy krok naprzód względem przestarzałych wpisów), uczciwe strategie unikania blokad, kontekst prawny oraz alternatywę no-code dla osób, które chcą tylko danych, a nie pisania kodu.
Co właściwie znaczy scrapować Craigslist w Pythonie?
Web scraping Craigslist polega na tym, że skrypty Pythona programowo odwiedzają strony Craigslist, wyciągają interesujące Cię dane strukturalne — tytuły, ceny, opisy, zdjęcia, lokalizacje, daty publikacji — i zapisują je do arkusza, bazy danych albo pliku JSON.
Python jest tu językiem pierwszego wyboru ze względu na bogaty ekosystem bibliotek. Dzięki requests, BeautifulSoup, lxml i curl_cffi możesz zbudować działający scraper Craigslist w mniej niż 100 liniach. Społeczność jest ogromna, więc kiedy Craigslist coś zmienia (a zmienia często), ktoś zwykle już znalazł rozwiązanie.
Kluczowa rzecz do zapamiętania: Craigslist nie udostępnia publicznego API do odczytu. Jedynym oficjalnym interfejsem programistycznym jest Bulk Posting Interface (BAPI), ale działa on wyłącznie do zapisu — pozwala zatwierdzonym, płacącym ogłoszeniodawcom dodawać wpisy, a nie je pobierać. Każdy produkt typu „Craigslist API” widoczny na platformach zewnętrznych to nieoficjalny scraper, a nie autoryzowany endpoint. Jeśli chcesz dane masowo, scrapujesz.
Dlaczego warto scrapować Craigslist? Przykłady z realnego świata
Craigslist to nie tylko miejsce na znalezienie używanej kanapy. To ogromny, stale aktualizowany zbiór danych obejmujący dziesiątki kategorii. Oto kto rzeczywiście korzysta na jego scrapowaniu:
| Przypadek użycia | Kto zyskuje | Jakie dane pobierasz |
|---|---|---|
| Monitorowanie cen mieszkań i najmu | Agenci nieruchomości, najemcy, firmy PropTech | Cena, metraż, liczba sypialni, dzielnica, szer./dł. geograficzna |
| Analiza rynku aut używanych | Salony samochodowe, aplikacje konsumenckie, badacze | Cena, marka, model, rocznik, przebieg, stan |
| Badania rynku pracy | Rekruterzy, ekonomiści pracy, analitycy rynku | Tytuł, wynagrodzenie, typ zatrudnienia, data publikacji |
| Generowanie leadów | Zespoły sprzedaży, firmy usługowe | Dane kontaktowe, nazwy firm, obszar działania |
| Analiza konkurencyjnych cen | Lokalni usługodawcy, e-commerce, operacje handlowe | Cenniki usług, opisy, obsługiwane obszary |
Najczęściej cytowanym przykładem akademickim jest „Used Cars Dataset” na Kaggle — około 500 000 ogłoszeń o autach używanych w USA z 26 zmiennymi, które posłużyły jako baza dla dziesiątek publikacji, w tym badania z 2024 roku na ResearchGate dotyczącego dynamiki amerykańskiego rynku aut używanych. Fundusze hedgingowe kupowały zagregowane dane o najmie z Craigslist do badań trendów czynszowych. Zespoły sprzedażowe regularnie scrapują kategorie usług i zleceń w celu pozyskiwania leadów.
Matematyka jest prosta: 8 godzin ręcznego kopiowania i wklejania kontra około 10 minut pracy dobrze napisanego scrapera.

Scrapowanie Craigslist w Pythonie: każda kategoria, nie tylko samochody
Prawie każdy poradnik o scrapowaniu Craigslist, jaki znalazłem, dotyczy wyłącznie samochodów na sprzedaż — to tak, jakby pisać tutorial do Google, który obejmuje tylko wyszukiwanie obrazów. Craigslist ma dziesiątki kategorii, a wzorce URL różnią się między nimi.
Struktura zawsze wygląda tak: https://{city}.craigslist.org/search/{category_slug}
Zmieniasz subdomenę miasta i slug, a trafiasz w zupełnie inny segment. Oto tabela referencyjna najpopularniejszych kategorii (zweryfikowana w kwietniu 2025):
| Kategoria | Slug URL | Typowe pola do pobrania |
|---|---|---|
| Mieszkania / najem | /search/apa | Cena, metraż, sypialnie, lokalizacja, zasady dotyczące zwierząt |
| Samochody i ciężarówki | /search/cta | Cena, marka, model, rocznik, przebieg |
| Praca | /search/jjj | Tytuł, firma, wynagrodzenie, typ zatrudnienia |
| Usługi | /search/bbb | Tytuł, opis, numer telefonu, obszar |
| Zlecenia / gig | /search/ggg | Tytuł, wynagrodzenie, data, kategoria |
| Na sprzedaż (ogólnie) | /search/sss | Tytuł, cena, stan, lokalizacja |
Możesz też dodawać parametry zapytań do filtrowania:
| Parametr | Zastosowanie | Przykład |
|---|---|---|
query | Słowo kluczowe full-text | ?query=studio |
min_price / max_price | Zakres cen | &min_price=1500&max_price=3000 |
hasPic | Tylko ogłoszenia ze zdjęciami | &hasPic=1 |
postedToday | Ostatnie 24 godziny | &postedToday=1 |
sort | Sortowanie | &sort=priceasc |
s | Offset paginacji (120 na stronę) | ?s=120 |
Zatem adres taki jak https://newyork.craigslist.org/search/apa?min_price=1500&max_price=3000&hasPic=1 zwróci mieszkania w Nowym Jorku w cenie od 1 500 do 3 000 dolarów, ze zdjęciami. Każdy scraper w Pythonie z tego poradnika działa we wszystkich tych kategoriach — wystarczy podmienić slug.
Selektory HTML Craigslist w 2025: stare vs nowe (i skrót przez JSON)
Najczęstszym powodem, dla którego scrapery Craigslist przestają działać, są zmiany w strukturze HTML. Jeśli korzystasz z poradnika z 2022 roku, który każe targetować .result-row albo .result-info, Twój scraper jest już martwy.
Craigslist przepisał markup wyników wyszukiwania w latach 2023–2024. Stare klasy nadal występują wewnątrz nowych kontenerów, ale ich użycie na najwyższym poziomie DOM zwraca pustą listę. Oto co się zmieniło:
| Element | Stary selektor (przed 2024) | Aktualny selektor (2025) |
|---|---|---|
| Kontener ogłoszenia | .result-info | .cl-search-result |
| Link tytułu | .result-title | .posting-title a |
| Cena | .result-price | .priceinfo |
| Metadane (obszar) | .result-hood | .meta |
Ale jest tu ważniejszy wniosek — i to on odróżnia aktualny scraper z 2025 roku od reszty: dla wyników wyszukiwania w ogóle nie musisz parsować HTML.
Craigslist osadza teraz każde widoczne ogłoszenie w tagu <script id="ld_searchpage_results"> jako ustrukturyzowane dane JSON-LD. Jedno wywołanie requests.get() zwraca pełny schemat ItemList ze schema.org dla wszystkich ogłoszeń na stronie — tytuł, cena, waluta, lokalizacja, URL obrazka, link do strony szczegółów. Bez renderowania JavaScriptu. Bez kruchej zależności od selektorów CSS.
Podejście JSON-LD jest szybsze, stabilniejsze i znacznie mniej podatne na awarie, gdy Craigslist zmienia interfejs. To rozwiązanie stosują aktywnie utrzymywane repozytoria na GitHubie i właśnie ono posłuży nam w dalszej części.
Jedno zastrzeżenie: blok JSON-LD jest dostępny dla kategorii z ceną — mieszkania (apa), oferty na sprzedaż (sss), auta (cta), housing (hhh). Często go nie ma albo jest ubogi dla pracy (jjj), gigów (ggg), community (ccc) i usług (bbb), ponieważ te ogłoszenia nie mają cen w schema.org/Offer. W takich przypadkach wracaj do ścieżki HTML .cl-search-result.
Wybór stacku Pythona: Requests + BS4 vs Selenium vs Playwright
To pytanie pojawia się na każdym forum o scrapingu: „Z jakiej biblioteki powinienem skorzystać?”. W przypadku Craigslist odpowiedź jest prostsza niż w większości serwisów.
| Czynnik | requests + BeautifulSoup | Selenium | Playwright |
|---|---|---|---|
| Szybkość | 5–15 stron/s (ograniczenie sieciowe) | 0,3–1 strona/s | 0,5–2 strony/s |
| Treść renderowana przez JS | Nie | Tak | Tak |
| Pamięć | ~30–60 MB | ~400–700 MB | ~300–500 MB |
| Złożoność konfiguracji | Niska | Średnia | Średnia |
| Odporność na anty-bota | Niska (wymaga nagłówków/proxy) | Średnia (prawdziwa przeglądarka) | Średnio-wysoka |
| Najlepszy przypadek użycia na Craigslist | Wyniki wyszukiwania (JSON-LD) | Strony szczegółów z dynamiczną treścią | Duże, asynchroniczne scrapowanie |
| Krzywa nauki | Przyjazna dla początkujących | Umiarkowana | Umiarkowana |
Strony Craigslist są renderowane po stronie serwera. Blok JSON-LD znajduje się w początkowym HTML. Na ścieżkach odczytu nie ma żadnych wyzwań JavaScriptowych. Każdy aktywnie utrzymywany scraper Craigslist na GitHubie używa requests + BeautifulSoup albo Scrapy. Zero Selenium. Zero Playwrighta. To nie przypadek — framework do automatyzacji przeglądarki dodaje setki MB pamięci, spowalnia operacje 10–100 razy i tworzy bardziej widoczny fingerprint, nie dając w zamian żadnej korzyści.
Moja rekomendacja:
- requests + BS4: zacznij tutaj. Idealnie współgra z ekstrakcją JSON-LD i pokrywa 95% potrzeb scrapingu Craigslist.
- Selenium: tylko jeśli musisz wchodzić w interakcję z dynamiczną treścią na konkretnych stronach szczegółów (na Craigslist rzadko konieczne).
- Playwright: jeśli skalujesz do tysięcy stron z asynchroniczną współbieżnością — ale szczerze, w Craigslist wąskim gardłem jest limiter, a nie przepustowość biblioteki.
Osobno omówiliśmy porównanie Playwright vs. Puppeteer oraz zestawienie najlepszych narzędzi Pythona do web scrapingu, jeśli chcesz pełniejszego obrazu.
Scrapuj Craigslist bez pisania Pythona Get Started Free
Alternatywa no-code: scrapuj Craigslist bez pisania Pythona
Krótki przystanek przed kodem — ta sekcja jest dla osób, które nie są programistami. Agenci nieruchomości, zespoły sprzedaży, menedżerowie operacyjni — jeśli po prostu chcesz dane i nie zależy Ci na pisaniu Pythona, istnieje szybsza droga.
Thunderbit to AI web scraper działający jako rozszerzenie Chrome. Potrafi scrapować Craigslist w około 2 kliknięcia, bez kodu. Oto jak wygląda proces:
- Wejdź na dowolną stronę wyników wyszukiwania Craigslist (mieszkania, auta, praca — dowolna kategoria).
- Kliknij „AI Suggest Fields” w panelu Thunderbit. AI odczytuje stronę i automatycznie wykrywa kolumny, takie jak tytuł ogłoszenia, cena, lokalizacja i link.
- Kliknij „Scrape” — dane zostaną pobrane w kilka sekund.
- Użyj Subpage Scraping, aby odwiedzić stronę szczegółów każdego ogłoszenia i wzbogacić dane o pełne opisy, numery telefonów, zdjęcia i atrybuty.
- Eksportuj bezpośrednio do Google Sheets, Excel, Airtable lub Notion — całkowicie za darmo.
Dla powtarzalnych zadań — na przykład codziennego monitorowania cen mieszkań albo cotygodniowych zrzutów ofert pracy — Scheduled Scraper w Thunderbit pozwala opisać harmonogram zwykłym językiem i uruchamia wszystko automatycznie. Bez cronów, bez konfiguracji serwera.
Thunderbit obsługuje też mechanizmy anty-botowe przez tryb Cloud Scraping, więc nie musisz martwić się o rotację proxy ani ręczne tworzenie nagłówków. Jeśli chcesz przetestować narzędzie, pobierz rozszerzenie Thunderbit do Chrome i sprawdź sam.
Jeśli zależy Ci na pełnej kontroli i personalizacji, czytaj dalej — poniżej znajdziesz instrukcję krok po kroku w Pythonie.
Krok po kroku: jak scrapować Craigslist w Pythonie (pełny poradnik)
- Poziom trudności: średni
- Szacowany czas: ~30 minut (konfiguracja + pierwszy scraping)
- Czego potrzebujesz: Python 3.8+, przeglądarka Chrome (do podglądu stron), terminal
Krok 1: przygotuj środowisko Pythona
Zainstaluj wymagane biblioteki:
pip install requests beautifulsoup4 lxml
lxml jest opcjonalne, ale zauważalnie przyspiesza parsowanie BeautifulSoup. Jeśli później trafisz na problemy z fingerprintem TLS (więcej o tym w sekcji o blokadach), możesz też doinstalować curl_cffi:
pip install curl_cffi
Twój blok importów:
import requests
from bs4 import BeautifulSoup
import json
import csv
import time
import random
Masz teraz czyste środowisko Pythona ze wszystkimi zależnościami.
Krok 2: zbuduj URL Craigslist dla dowolnej kategorii
Twórz adres docelowy dynamicznie, używając miasta, slugu kategorii i opcjonalnych filtrów:
from urllib.parse import urlencode
BASE = "https://{city}.craigslist.org/search/{slug}"
def build_url(city, slug, **params):
return f"{BASE.format(city=city, slug=slug)}?{urlencode(params)}"
# Przykład: mieszkania w Nowym Jorku, 1500–3000 USD, ze zdjęciami
url = build_url("newyork", "apa", min_price=1500, max_price=3000, hasPic=1)
print(url)
# https://newyork.craigslist.org/search/apa?min_price=1500&max_price=3000&hasPic=1
Zamień "apa" na "cta" (auta), "jjj" (praca), "bbb" (usługi) albo dowolny slug z tabeli kategorii wyżej. Zamień "newyork" na "sfbay", "chicago", "losangeles" itd.
Krok 3: pobierz stronę i wyodrębnij osadzony JSON
Wyślij żądanie GET z odpowiednimi nagłówkami, a potem sparsuj blok JSON-LD:
HEADERS = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/124.0.0.0 Safari/537.36"
),
"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.craigslist.org/",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "same-origin",
"Upgrade-Insecure-Requests": "1",
}
session = requests.Session()
r = session.get(url, headers=HEADERS, timeout=20)
r.raise_for_status()
soup = BeautifulSoup(r.text, "html.parser")
tag = soup.select_one("script#ld_searchpage_results")
data = json.loads(tag.text) if tag else {"itemListElement": []}
Jeśli tag ma wartość None, blok JSON-LD nie występuje dla danej kategorii — wtedy wróć do parsowania HTML (patrz tabela selektorów wyżej). Dla mieszkań, aut i kategorii sprzedażowych blok JSON-LD jest zazwyczaj obecny.
Krok 4: zamień ogłoszenia na ustrukturyzowane rekordy
Przejdź po elementach JSON i pobierz potrzebne pola:
listings = []
for entry in data["itemListElement"]:
item = entry["item"]
offers = item.get("offers", {}) or {}
addr = (offers.get("availableAtOrFrom") or {}).get("address", {})
listings.append({
"name": item.get("name"),
"url": offers.get("url"),
"price": offers.get("price"),
"currency": offers.get("priceCurrency"),
"locality": addr.get("addressLocality"),
"region": addr.get("addressRegion"),
"image": item.get("image"),
})
print(f"Znaleziono {len(listings)} ogłoszeń")
Powinieneś zobaczyć coś w stylu „Znaleziono 120 ogłoszeń” (Craigslist pokazuje 120 wyników na stronę). Część ogłoszeń może mieć None w polu ceny, jeśli autor jej nie podał — uwzględnij to w dalszej logice.
Krok 5: pobierz strony szczegółów, żeby uzyskać bogatsze dane
Wyniki wyszukiwania dają tylko podsumowanie. Pełne opisy, atrybuty (liczba sypialni, metraż, zasady dla zwierząt), współrzędne oraz zdjęcia znajdziesz dopiero na stronie szczegółów każdej oferty.
def fetch_detail(url, session):
r = session.get(url, headers=HEADERS, timeout=20)
r.raise_for_status()
s = BeautifulSoup(r.text, "html.parser")
body = s.select_one("#postingbody")
mp = s.select_one("#map")
return {
"description": body.get_text("\n", strip=True) if body else None,
"attributes": [x.get_text(" ", strip=True)
for x in s.select("p.attrgroup span, div.attrgroup .attr")],
"lat": mp.get("data-latitude") if mp else None,
"lng": mp.get("data-longitude") if mp else None,
"images": [img["src"] for img in s.select("div.gallery img")],
}
for item in listings:
item.update(fetch_detail(item["url"], session))
time.sleep(random.uniform(3, 6)) # kluczowe: losowy odstęp anty-botowy
time.sleep(random.uniform(3, 6)) nie jest opcjonalne. Pomiń to, a w ciągu kilkudziesięciu requestów dostaniesz 403. Strony szczegółów są renderowane po stronie serwera i mają stabilne selektory (#titletextonly, #postingbody, #map), które nie zmieniły się mniej więcej od 2017 roku — czyli należą do nielicznych rzeczy na Craigslist, na których można polegać.
Krok 6: obsłuż paginację i pobierz wszystkie wyniki
Craigslist używa parametru offsetu ?s=120 do paginacji. Każda strona pokazuje 120 wyników, a maksymalny offset to zwykle 2999.
def iter_all(city, slug, max_pages=25, **filters):
for page in range(max_pages):
offset = page * 120
url = build_url(city, slug, s=offset, **filters)
r = session.get(url, headers=HEADERS, timeout=20)
r.raise_for_status()
soup = BeautifulSoup(r.text, "html.parser")
tag = soup.select_one("script#ld_searchpage_results")
if not tag:
break
data = json.loads(tag.text)
items = data.get("itemListElement", [])
if not items:
break
for entry in items:
item = entry["item"]
offers = item.get("offers", {}) or {}
yield {
"name": item.get("name"),
"url": offers.get("url"),
"price": offers.get("price"),
}
time.sleep(random.uniform(2.5, 5.0))
Nie próbuj scrapować tysięcy stron jedna po drugiej. Limit Craigslist działa per IP, a zrównoważona przepustowość dla pojedynczego adresu IP zwykle kończy się w okolicach 0,3–0,5 requestu na sekundę, niezależnie od biblioteki. Ten limit ustala Craigslist, nie Python.
Krok 7: eksportuj dane Craigslist do CSV, JSON lub Google Sheets
Zapisz wyniki:
# CSV
with open("craigslist.csv", "w", newline="", encoding="utf-8") as f:
w = csv.DictWriter(f, fieldnames=listings[0].keys())
w.writeheader()
w.writerows(listings)
# JSON
with open("craigslist.json", "w", encoding="utf-8") as f:
json.dump(listings, f, indent=2, ensure_ascii=False)
Jeśli wolisz w ogóle pominąć kod eksportu, Thunderbit oferuje darmowy eksport bezpośrednio z przeglądarki do Google Sheets, Excel, Airtable lub Notion. Ale w pipeline’ach Pythona standardem pozostają CSV i JSON. Możesz też przepuścić dane bezpośrednio do pandas do analizy albo do bazy danych z sqlite3.
Jak uniknąć bana podczas scrapowania Craigslist w Pythonie
Większość poradników traktuje ten temat bardzo powierzchownie. System anty-botowy Craigslist jest autorski, a nie gotowy „z półki”, i ma kilka specyficznych pułapek.

Używaj realistycznych nagłówków requestów
Craigslist weryfikuje kolejność i kompletność nagłówków. Żądanie bez Sec-Fetch-Dest albo ze starym User-Agentem zostanie oznaczone zanim dotrze do treści. Pełny zestaw nagłówków z Chrome 120+ (pokazany w kroku 3) to minimum. Rotuj User-Agent na poziomie sesji pomiędzy 5–10 aktualnymi desktopowymi stringami Chrome/Firefox — ale nie zmieniaj go w trakcie jednej sesji, bo wygląda to nienaturalnie.
Brak nagłówków Sec-Fetch-* to najczęstszy powód natychmiastowych blokad u początkujących scraperów.
Dodawaj losowe przerwy między requestami
Konsensus społeczności z wielu źródeł (ScrapingBee, Scraperly, Oxylabs, Multilogin) wskazuje na losowe 2–5 sekund między pobieraniem stron wyników oraz 3–6 sekund między stronami szczegółów. Stałe odstępy wyglądają jak ruch bota. Używaj time.sleep(random.uniform(2, 5)) — nigdy time.sleep(2).
Rotuj proxy, jeśli scrapujesz na dużą skalę
Craigslist blokuje całe zakresy IP z AWS, GCP i Azure. Proxy z centrów danych często padają od razu. Przy wolumenie większym niż kilkaset stron potrzebujesz rotujących proxy residential, zmienianych co 20–30 requestów. Proxy mobilne mają najniższe ryzyko wykrycia, ale kosztują 8–30 USD/GB.
| Typ proxy | Ryzyko wykrycia na Craigslist | Koszt (2025) |
|---|---|---|
| Datacenter | Bardzo wysokie — często blokowane przy pierwszym requestie | $0.50–2/GB |
| Residential rotating | Niskie — rekomendowane | $5–15/GB |
| Mobile | Najniższe | $8–30/GB |
Tryb Cloud Scraping w Thunderbit automatycznie obsługuje rotację proxy, jeśli nie chcesz robić tego samodzielnie.
Obsługuj CAPTCHA z głową
CAPTCHA na Craigslist są rzadkie na ścieżkach odczytu — zwykle pojawiają się przy publikowaniu albo odpowiadaniu na ogłoszenia. Jeśli się pojawią: odczekaj co najmniej 60 sekund, zmień IP, wyczyść ciasteczka i zwolnij tempo. Uporczywe CAPTCHA to znak, że jedziesz za agresywnie, a nie łamigłówka do rozwiązywania siłą.
Szanuj limity i stosuj backoff
Craigslist zwraca 403, a nie 429, gdy przekroczysz limit. 403 oznacza, że bieżące IP trafiło na listę blokad — nie powtarzaj ślepo zapytania. Zmień IP, User-Agent i poczekaj.
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
retry = Retry(
total=5,
backoff_factor=1.5, # 1.5, 3, 6, 12, 24 s
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods={"GET"},
respect_retry_after_header=True,
)
adapter = HTTPAdapter(max_retries=retry)
session.mount("https://", adapter)
Jeszcze jedna wskazówka: raporty społeczności konsekwentnie wskazują, że 2:00–6:00 rano czasu lokalnego docelowego miasta to najbezpieczniejsze okno scrapowania, z około 30–40% mniejszym odsetkiem blokad niż w ciągu dnia.
Fingerprinting TLS — ukryta pułapka
Warstwa botowa Craigslist analizuje TLS ClientHello. Biblioteka requests w Pythonie (oparta na OpenSSL) ma fingerprint JA3, który nie pasuje do żadnej prawdziwej przeglądarki. Idealny User-Agent połączony z niefizycznym fingerprintem TLS to łatwo wykrywalna niespójność. Obejściem jest curl_cffi z impersonate="chrome124", które emuluje handshake TLS Chrome:
from curl_cffi import requests as cffi_requests
r = cffi_requests.get(url, headers=HEADERS, impersonate="chrome124")
Jeśli dostajesz niewyjaśnione 403 mimo czystych residential IP i poprawnych nagłówków, fingerprint TLS jest niemal na pewno przyczyną.
robots.txt Craigslist, warunki korzystania i etyczny scraping
Większość poradników pomija ten temat albo wrzuca jedno zdanie do FAQ. Biorąc pod uwagę, że Craigslist wygrał wyrok na 60,5 mln USD przeciwko scraperowi (RadPad, 2017), temat zasługuje na coś więcej niż przypis.
Co tak naprawdę mówi robots.txt Craigslist?
Plik robots.txt jest zaskakująco krótki. Zawiera jeden blok User-agent: * i tylko siedem wykluczonych ścieżek:
Disallow: /reply
Disallow: /fb/
Disallow: /suggest
Disallow: /flag
Disallow: /mf
Disallow: /mailflag
Disallow: /eaf
Wszystkie siedem to interaktywne lub modyfikujące endpointy: odpowiedzi, zgłaszanie, sugestie, wysłanie maila do znajomego. Strony ogłoszeń (/search/..., pojedyncze URL-e postów) nie są wykluczone. Nie ma też dyrektywy Crawl-delay, choć Craigslist i tak egzekwuje ją przez blokady IP.
Subdomeny miast publikują sitemapę — np. https://newyork.craigslist.org/sitemap/index.xml — czyli oficjalnie dostępny punkt wejścia do ogłoszeń.
Precedens prawny: sprawy, które mają znaczenie
Craigslist v. 3Taps (2013, ugoda 2015): 3Taps scrapował ogłoszenia Craigslist i odsprzedawał je dalej. Gdy Craigslist wysłał wezwanie do zaprzestania i zablokował ich IP, 3Taps obejść blokadę przez rotujące proxy. Sąd uznał, że obchodzenie blokad IP po jednoznacznym cofnięciu zgody stanowi działanie „without authorization” w rozumieniu CFAA. 3Taps zawarł ugodę na 1 mln USD.
Meta v. Bright Data (2024): Nowszy wyrok stwierdził, że warunki korzystania Meta nie mogą zakazywać scrapowania publicznie dostępnych danych przez wylogowanego użytkownika. Sąd uznał, że scraper bez logowania jest „na miejscu zwykłego odwiedzającego”. To najważniejsze rozstrzygnięcie dla scraperów w latach 2024–2025 — jeśli nigdy nie zakładasz konta Craigslist, nigdy się nie logujesz i korzystasz wyłącznie z publicznie widocznych stron, warunki korzystania mogą nie być wobec Ciebie egzekwowalne jako umowa.
Praktyczny wniosek: ryzyko CFAA jest znacznie mniejsze po Van Buren (2021) i hiQ v. LinkedIn (2022) w przypadku stron publicznie dostępnych. Ale roszczenia z prawa stanowego — takie jak trespass-to-chattels czy misappropriation — nadal istnieją. To właśnie one doprowadziły zarówno do ugody 3Taps, jak i do wyroku na 60,5 mln USD wobec RadPad.
To materiał informacyjny, nie porada prawna. Jeśli planujesz komercyjnie scrapować Craigslist, porozmawiaj z prawnikiem.
Praktyczna checklista etycznego scrapingu
- ✅ Respektuj każdy
Disalloww robots.txt — szczególnie siedem endpointów akcji - ✅ Trzymaj się wyraźnie poniżej 1 000 stron na 24 godziny na jedno IP (warunki Craigslist przypisują powyżej tego progu 0,25 USD za stronę jako z góry określone odszkodowanie)
- ✅ Pozostań wylogowany — nigdy nie twórz konta Craigslist wyłącznie do scrapowania
- ✅ Nigdy nie obchodź blokad IP przez proxy po eksplicytnym banie (to pogrążyło 3Taps)
- ✅ Dodawaj opóźnienia między requestami — minimum 2–5 sekund
- ✅ Nie scrapuj danych kontaktowych do spamu
- ✅ Nie redystrybuuj surowych danych Craigslist ani nie przedstawiaj ich jako własnej platformy
- ✅ Używaj danych wyłącznie do legalnych badań, analiz lub użytku osobistego
- ✅ Jeśli to możliwe, preferuj opublikowane sitemap y zamiast brutalnego crawl'owania
- ✅ Usuwaj dane osobowe (PII), takie jak e-maile i numery telefonów, na etapie ingestii, jeśli je przechowujesz
Przygotowaliśmy też bardziej szczegółowy przewodnik o prawnych konsekwencjach web scrapingu, jeśli chcesz pełniejszy obraz.
Python vs no-code: które podejście będzie dla Ciebie lepsze?
| Czynnik | Python (requests + BS4) | Thunderbit (no-code) |
|---|---|---|
| Czas konfiguracji | 30–60 min (instalacja, kod) | 2 minuty (instalacja rozszerzenia Chrome) |
| Wymagana wiedza techniczna | Python na poziomie średnim | Brak |
| Personalizacja | Pełna kontrola nad logiką, polami i przepływem | AI automatycznie wykrywa pola; użytkownik może je dopasować |
| Skala | Praktycznie nieograniczona (z proxy i harmonogramem) | Scheduled Scraper do zadań cyklicznych |
| Obsługa blokad | Ręczna (nagłówki, opóźnienia, proxy, TLS) | Wbudowana (Cloud Scraping) |
| Opcje eksportu | CSV, JSON (piszesz sam) | Google Sheets, Excel, Airtable, Notion — za darmo |
| Najlepsze dla | Programistów, data scientistów, niestandardowych pipeline’ów | Zespołów sprzedaży, agentów nieruchomości, menedżerów operacyjnych |
Użyj Pythona, jeśli potrzebujesz pełnej personalizacji, planujesz integrację z większym pipeline’em danych albo chcesz dokładnie rozumieć, co dzieje się pod maską. Wybierz Thunderbit, jeśli zależy Ci na szybkich wynikach bez pisania i utrzymywania kodu. Oba podejścia są dobre — wszystko sprowadza się do Twojego scenariusza i do tego, czy wolisz spędzać czas w terminalu, czy w przeglądarce.
Podsumowanie
Craigslist to bogate, stale aktualizowane źródło danych o mieszkaniach, autach, pracy, usługach, zleceniach i wielu innych obszarach — a ponieważ nie ma publicznego API, scraping jest jedynym sposobem na pozyskanie danych strukturalnych na dużą skalę. Podejście, które działa w 2025 roku: wyciągaj osadzony JSON-LD z wyników wyszukiwania (zamiast kruchych selektorów CSS), używaj requests + BeautifulSoup (zamiast Selenium), dodawaj realistyczne nagłówki z polami Sec-Fetch-*, losuj opóźnienia i korzystaj z residential proxy, jeśli idziesz poza kilkaset stron.
Metoda JSON-LD to największa poprawa względem przestarzałych poradników. Jest szybsza, bardziej odporna na zmiany layoutu i nie wymaga żadnego renderowania JavaScriptu. Połącz ją z powyższymi strategiami unikania blokad, a ominiesz 403, które zatrzymują większość scraperów.
Jeśli wolisz całkowicie pominąć kod, rozszerzenie Thunderbit do Chrome może scrapować dowolną kategorię Craigslist w kilka kliknięć i eksportować dane bezpośrednio do preferowanego arkusza lub bazy danych. Jeśli chcesz wejść głębiej, nasze poradniki o web scrapingu w Pythonie i najlepszych praktykach web scrapingu omawiają fundamenty bardziej szczegółowo.
Wypróbuj Thunderbit do scrapowania Craigslist
Wypróbuj AI Web Scraper do danych z Craigslist Get Started Free
FAQ
Czy scrapowanie Craigslist jest legalne?
Warunki korzystania Craigslist zabraniają automatycznego scrapowania i zawierają klauzulę odszkodowawczą (0,25 USD za stronę powyżej 1 000 dziennie). Jednak nowsze orzeczenia sądowe — szczególnie Meta v. Bright Data (2024) i hiQ v. LinkedIn (2022) — ograniczyły odpowiedzialność CFAA w przypadku scrapowania publicznie dostępnych danych przez wylogowanego użytkownika. Roszczenia na gruncie prawa stanowego (trespass-to-chattels) nadal stanowią ryzyko, zwłaszcza przy komercyjnej redystrybucji. Respektuj robots.txt, pozostań wylogowany, dodawaj opóźnienia i nie rozpowszechniaj surowych danych. To ogólna informacja, nie porada prawna.
Czy Craigslist ma publiczne API?
Nie. Craigslist udostępnia wyłącznie interfejs Bulk Posting Interface (BAPI) do zapisu dla zatwierdzonych płacących ogłoszeniodawców. Nie ma publicznego API do odczytu, portalu deweloperskiego ani limitowanej warstwy do pobierania danych. Każdy produkt „Craigslist API” widoczny na platformach zewnętrznych to nieoficjalny scraper.
Dlaczego mój scraper Craigslist ciągle się psuje?
Prawie zawsze przez zmiany w HTML. Craigslist przepisał markup wyników wyszukiwania w latach 2023–2024, a poradniki używające starych selektorów, takich jak .result-row czy .result-info, nie działają. Przejdź na metodę osadzonego JSON-LD (parsowanie script#ld_searchpage_results), która jest dużo bardziej odporna. Sprawdź też, czy nagłówki zawierają pola Sec-Fetch-* — ich brak powoduje natychmiastowe blokady.
Czy mogę scrapować Craigslist bez Pythona?
Tak. Rozszerzenie Chrome Thunderbit AI web scraper działa na każdej stronie Craigslist — mieszkaniach, autach, pracy, usługach. Kliknij „AI Suggest Fields”, aby automatycznie wykryć kolumny, kliknij „Scrape”, aby pobrać dane, a następnie wyeksportuj je za darmo do Google Sheets, Excel, Airtable lub Notion. Bez kodu, bez konfiguracji, bez zarządzania proxy.
Jak często mogę scrapować Craigslist, żeby nie dostać bana?
Przy pojedynczym residential IP zrównoważona przepustowość to około 0,3–0,5 requestu na sekundę, przy losowych przerwach 2–5 sekund między stronami. Nie przekraczaj 1 000 stron na 24 godziny na jedno IP, aby uniknąć zarówno banów, jak i progu odszkodowań zapisanych w warunkach Craigslist. Scrapowanie poza godzinami szczytu (2:00–6:00 rano czasu lokalnego docelowego miasta) obniża odsetek blokad o około 30–40%. Przy większych wolumenach rotuj residential proxy co 20–30 requestów.
Dowiedz się więcej


