Как парсить объявления Craigslist: транспорт, аренда и подработки

Craigslist — это кладезь данных, защищённый агрессивными ограничениями на IP. Вот структура URL по городам, математика пагинации 120 на страницу, RSS-ярлык, который многие упускают, и настройка прокси, которая убережёт вас от блокировки.

Craigslist содержит огромное количество доступных публичных данных — подержанные автомобили, аренда квартир, подработки, товары на продажу, услуги — распределённых по сотням городских сайтов. Это также стена для новичков из-за CAPTCHA и блокировок IP, так как Craigslist жёстко ограничивает по IP-адресу. Хорошая новость: структура URL сайта проста и предсказуема, есть RSS-ярлык, который большинство руководств пропускает, а проблема блокировок почти полностью связана с гигиеной IP. Это руководство охватывает шаблон URL по городам, математику пагинации, парсинг, маршрут RSS и настройку прокси, которая убережёт парсер от блокировки. Парсите для личного или исследовательского использования, уважайте условия Craigslist и рассматривайте это как общую информацию, а не юридическую консультацию.

Шаблон URL — это всё

Craigslist делится по субдомену города и коду категории, а всё остальное — это параметры запроса. Изучите структуру один раз, и вы сможете нацелиться на любой город и раздел: https://{city}.craigslist.org/search/{category}?query={q}. Коды категорий короткие — sss для всех товаров на продажу, cto для автомобилей от владельцев, apa для квартир, ggg для подработок. Добавьте min_price, max_price и другие фильтры как параметры. Пагинация использует параметр s, и каждая страница показывает 120 результатов — так что вторая страница это s=120, третья s=240 и так далее.

import requests
from bs4 import BeautifulSoup

PROXY = "http://USER:PASS@rotating.quantumproxies.io:8000"
PROXIES = {"http": PROXY, "https": PROXY}
UA = ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
      "(KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36")

def build_url(city, category, query, page=0, min_price=None, max_price=None):
    base = f"https://{city}.craigslist.org/search/{category}"
    params = [f"query={query}"]
    if min_price: params.append(f"min_price={min_price}")
    if max_price: params.append(f"max_price={max_price}")
    if page:      params.append(f"s={page * 120}")   # 120 results per page
    return base + "?" + "&".join(params)

url = build_url("minneapolis", "cto", "bmw", page=0, max_price=8000)
r = requests.get(url, headers={"User-Agent": UA}, proxies=PROXIES, timeout=20)

Парсинг объявлений

Строки результатов поиска отмечены стабильным набором классов — блок объявления это .result-info, внутри которого .result-title, .result-price и .result-date. Защитите каждое поле, так как не каждое объявление имеет цену:

def parse_listings(html):
    soup = BeautifulSoup(html, "html.parser")
    out = []
    for row in soup.select(".result-info"):
        title_el = row.select_one(".result-title")
        price_el = row.select_one(".result-price")
        date_el  = row.select_one(".result-date")
        if not title_el:
            continue
        out.append({
            "title": title_el.get_text(strip=True),
            "url":   title_el.get("href"),
            "price": price_el.get_text(strip=True) if price_el else None,
            "date":  date_el.get("datetime") if date_el else None,
        })
    return out

listings = parse_listings(r.text)
print(len(listings), "listings on this page")

Для более богатых записей — пробег автомобиля, количество спален в аренде — следуйте по URL каждого объявления и парсите страницу с деталями. Это удваивает количество запросов, поэтому именно здесь начинают иметь значение темп и ротация.

Диаграмма, разбивающая URL поиска Craigslist на субдомен города, код категории, запрос и параметр пагинации s
URL Craigslist полностью предсказуемы: субдомен города, код категории, затем запрос и параметр s с шагом 120.

RSS-ярлык, который многие руководства пропускают

У Craigslist нет общей публичной API, но он предоставляет RSS-канал для результатов поиска — добавьте &format=rss к любому URL поиска, и вы получите структурированный XML-канал вместо HTML для парсинга. Он легче, менее вероятно, что он вызовет антиботовые эвристики, чем повторная загрузка полной страницы результатов, и идеально подходит для мониторинга: опрашивайте сохранённый поиск по расписанию и сравнивайте для новых элементов. Он возвращает меньше полей, чем HTML-страница (заголовок, ссылка, временная метка), поэтому используйте его для мониторинга свежести и возвращайтесь к HTML, когда вам нужны цена и детали.

import feedparser

# Any Craigslist search becomes a feed with &format=rss
feed_url = build_url("sfbay", "apa", "loft", max_price=3500) + "&format=rss"
raw = requests.get(feed_url, headers={"User-Agent": UA}, proxies=PROXIES, timeout=20)
feed = feedparser.parse(raw.content)

for entry in feed.entries[:5]:
    print(entry.updated, entry.title, entry.link)

Почему Craigslist вас блокирует и как избежать блокировки

Craigslist использует несколько защит, но у них один корень: он отслеживает запросы по IP-адресу и блокирует адреса, которые слишком активно обращаются к нему. Конкретные меры включают ограничение скорости по IP, CAPTCHA для подозрительного трафика, мониторинг User-Agent, отслеживание сессий и временные блокировки IP. Каждую из них можно обойти, выглядя как множество обычных посетителей, а не одна неумолимая машина.

Поскольку блокировки основаны на IP, выходной IP выполняет основную работу. Чистый пул резидентных прокси выглядит как реальные домашние подключения, а ротация по запросу распределяет многогородской обход так тонко, что счётчики по IP Craigslist никогда не срабатывают. Если вы собираете данные по многим городам, наше руководство по исправлению 429 ограничений скорости охватывает сторону темпа и бюджета параллельности, а чеклист по избежанию блокировок связывает всё вместе.

Парсинг Craigslist на чистых резидентных IP

Масштабирование по городам

Настоящая сила данных Craigslist — это сравнение между городами — одна и та же подержанная машина или аренда по цене в дюжине мегаполисов. Перебирайте список городов, привязывайте свежий вращающийся выход для каждого города, ограничивайте параллельность и сохраняйте город вместе с каждой записью. Для исследований транспорта и аренды те же шаблоны питают конвейер компов; смотрите наши руководства по парсингу объявлений автомобилей и данным о недвижимости для превращения сырых объявлений в рыночные сигналы.

Чеклист, сопоставляющий защиты Craigslist от парсинга, такие как ограничение скорости по IP и CAPTCHA, с решениями, такими как ротация резидентных IP и темп
Каждая защита Craigslist — это проблема IP и темпа — ротируйте резидентные выходы и оставайтесь в пределах 1-2 запросов в секунду.

Часто задаваемые вопросы

Можно ли парсить Craigslist?

Да — публичные страницы поиска и объявлений можно парсить, и Craigslist даже предоставляет RSS-канал для поисков. Препятствием является агрессивное ограничение скорости по IP, а не парсинг. Ротируйте резидентные IP, темпируйте запросы до 1-2 в секунду, и вы сможете надёжно собирать данные о транспорте, аренде, подработках и товарах на продажу. Уважайте условия Craigslist и парсите только публичные данные.

Есть ли у Craigslist API?

Нет общей публичной API, но каждый URL поиска может возвращать RSS-канал, добавив &format=rss. Это даёт вам структурированный XML-канал с заголовками, ссылками и временными метками — идеально для мониторинга новых объявлений — в то время как HTML-страницы содержат более полные поля, такие как цена и описание.

Как избежать блокировки IP при парсинге Craigslist?

Craigslist блокирует по скорости IP, поэтому решения связаны с распределением и замедлением нагрузки: ротируйте резидентные IP по запросу, придерживайтесь 1-2 запросов в секунду с джиттером, ротируйте ваш User-Agent, используйте свежую сессию для каждого города и отступайте сразу, как только увидите CAPTCHA или 403. Датацентр IP, активно работающий по одному городу, блокируется быстрее всего.

Как работает пагинация на Craigslist?

Craigslist показывает 120 результатов на страницу и использует параметр запроса s в качестве смещения. Первая страница опускает s, вторая страница это s=120, третья s=240 и так далее. Увеличивайте шагами по 120, пока страница не вернёт меньше 120 результатов, что обозначает конец.

Craigslist легко читать и легко попасть под блокировку — и вторая проблема полностью связана с гигиеной IP. Освойте шаблон URL, используйте RSS для мониторинга, переходите шагами по 120 и направляйте всё через вращающиеся резидентные IP с человеческим темпом. Делайте это, и CAPTCHA просто перестанут появляться.

Начните с вращающихся резидентных прокси