Clutch.co перечисляет более 150 000 поставщиков услуг в сферах IT, маркетинга, дизайна и разработки, и каждый профиль компании несёт именно те структурированные B2B-данные, которые на деле нужны конвейеру лидогенерации, дашборду конкурентного анализа или рыночному исследованию: название компании, рейтинг в звёздах, число отзывов, минимальный размер проекта, диапазон почасовой ставки, местоположение и ссылку на полный профиль. Загвоздка в том, что Clutch стоит за мощной защитой от ботов, поэтому обычный HTTP-запрос редко вообще доходит до списка.

Это руководство показывает, как построить Python-скрапер для Clutch.co надёжным способом. Вы создадите небольшой работающий скрипт, который получает отрисованную страницу категории через Crawling API, разбирает карточку каждой компании с помощью BeautifulSoup и записывает чистые структурированные строки. Весь разбор ограничен публичными данными списка компаний, а раздел о законности ближе к концу не для галочки, так что прочитайте его, прежде чем направлять этот скрипт на любой реальный объём.

Что вы построите

Python-скрипт, который принимает публичный URL категории Clutch.co, получает отрисованный HTML через Crawling API и извлекает структурированную запись для каждой компании на странице. В качестве сквозного примера мы используем каталог IT-услуг и вытащим из каждой карточки следующие поля:

  • Название компании указанное наименование бизнеса поставщика.
  • Рейтинг совокупная звёздная оценка, показанная на карточке.
  • Число отзывов сколько отзывов клиентов подкрепляют этот рейтинг.
  • Мин. размер проекта наименьший заказ, который берёт поставщик, например «$5,000+».
  • Почасовая ставка указанный диапазон почасовой ставки, например «$50 - $99 / hr».
  • Местоположение основной город или регион поставщика.
  • URL профиля ссылка на полный профиль компании на Clutch.

Почему обычный запрос не срабатывает на Clutch.co

Если запросить URL категории Clutch.co голым HTTP-клиентом, вы обычно вообще не получите список в ответ. Clutch использует агрессивную защиту от ботов, и IP-адрес из дата-центра, делающий очевидно автоматизированный запрос, получает проверку или ответ 403 ещё до того, как до вас дойдут данные компаний. Даже когда запрос проскакивает, часть страницы догружается на стороне клиента, поэтому в сыром HTML могут отсутствовать те самые карточки, ради которых вы пришли.

Так что рабочему скраперу Clutch нужны две вещи в одном запросе: браузер, который действительно отрисовывает страницу, и IP-адрес, который платформа воспринимает как реального посетителя. Вы можете собрать это самостоятельно из headless-браузера и пула ротируемых резидентных прокси, но сшить их вместе и поддерживать в рабочем состоянии и есть основная часть работы. Crawling API объединяет и то и другое в один вызов: вы отправляете ему URL с JavaScript-токеном, он отрисовывает страницу за доверенным резидентным IP и возвращает готовый HTML, который вам останется разобрать.

Зачем JS-токен

Crawlbase предлагает два типа токенов. Обычный токен получает статический HTML; JavaScript (JS) токен сначала отрисовывает страницу в настоящем браузере и направляет запрос через ротируемые резидентные IP. Clutch хорошо защищён и частично отрисовывается на стороне клиента, поэтому здесь вам нужен JS-токен. Вы получаете до 20 000 бесплатных запросов, чтобы начать, без необходимости указывать кредитную карту.

Предварительные требования

Прежде чем писать код, вам нужно подготовить несколько вещей. Ни одна из них не займёт много времени.

Базовый Python. Вы должны уверенно писать и запускать Python-скрипт и устанавливать пакеты через pip. Если BeautifulSoup для вас в новинку, наше руководство по использованию BeautifulSoup в Python охватывает основы разбора, которые этот туториал предполагает известными.

Python 3.8 или новее. Подтвердите свою версию командой python --version. Если его у вас нет, установите его с python.org и убедитесь, что Python прописан в системном PATH.

Учётная запись Crawlbase и JS-токен. Зарегистрируйтесь, откройте дашборд и скопируйте свой JavaScript (JS) токен. Относитесь к токену как к паролю: он аутентифицирует ваши запросы, поэтому держите его вне системы контроля версий.

Настройте проект

Создайте виртуальное окружение, чтобы зависимости проекта оставались изолированными, затем установите библиотеки, которые нужны скраперу.

bash
python --version

python -m venv clutch_env
source clutch_env/bin/activate

pip install crawlbase beautifulsoup4 pandas

В Windows активируйте окружение командой clutch_env\Scripts\activate вместо строки source. Три зависимости делают всю работу: crawlbase это официальный клиент для Crawling API, beautifulsoup4 разбирает возвращённый HTML, чтобы вы могли вытащить поля по CSS-селектору, а pandas в конце превращает собранные строки в CSV.

Шаг 1: Получите отрисованную страницу категории

Начните с получения готовой страницы. Импортируйте класс CrawlingAPI, инициализируйте его своим JS-токеном и запросите URL категории. Проверка статуса перед разбором делает сбои громкими, а не молчаливыми.

python
from crawlbase import CrawlingAPI

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_JS_TOKEN"})

def fetch_html(url):
    response = api.get(url, {"ajax_wait": "true", "page_wait": 5000})
    if response["status_code"] == 200:
        return response["body"].decode("utf-8")
    print(f"Request failed: {response['status_code']}")
    return None

if __name__ == "__main__":
    base_url = "https://clutch.co/it-services"
    html = fetch_html(base_url)
    print(html[:500] if html else "No HTML returned")

Два параметра ожидания важны для защищённой, частично отрисовываемой на клиенте цели вроде этой. ajax_wait сообщает API, что нужно дождаться окончания загрузки асинхронного контента, а page_wait выдерживает фиксированное число миллисекунд после загрузки, чтобы поздно отрисовываемые карточки появились до того, как страница будет захвачена. Пять секунд это разумное начало; повысьте значение, если карточки приходят пустыми. Запустите скрипт командой python scraper.py, и вы должны увидеть реальную разметку поставщиков, а не страницу 403, которую возвращает обычный requests.get. Это подтверждает, что запрос проходит, ещё до того как вы напишете хоть один селектор.

Crawlbase Crawling API

Clutch.co отвечает на голый запрос кодом 403, поэтому вам нужна отрисованная страница за доверенным IP в одном вызове. Crawling API принимает JS-токен, выполняет страницу в настоящем браузере, ротирует резидентные IP на стороне сервера и отдаёт вам готовый HTML, так что вы избегаете запуска собственного headless-флота и пула прокси. Сначала направьте его на публичный каталог IT-услуг на бесплатном тарифе.

Шаг 2: Разберите карточки компаний с помощью BeautifulSoup

Имея на руках отрисованный HTML, загрузите его в BeautifulSoup и вытащите каждого поставщика по его селектору. Clutch раскладывает свои списки в повторяющейся структуре: каждый поставщик это li.provider внутри ul.providers__list, поэтому вы один раз выбираете все карточки, а затем читаете одни и те же поля из каждой. Осмотрите живую страницу в инструментах разработчика браузера (обычно F12), чтобы подтвердить текущие имена классов; селекторы ниже соответствуют разметке на момент написания.

python
import re
from bs4 import BeautifulSoup

def text_of(card, selector):
    el = card.select_one(selector)
    return re.sub(r"\s+", " ", el.get_text(strip=True)) if el else "N/A"

def parse_html(html):
    soup = BeautifulSoup(html, "html.parser")
    data = []

    companies = soup.select("ul.providers__list > li.provider")
    for company in companies:
        profile = company.select_one("h3.provider__title a")
        profile_url = profile["href"] if profile else "N/A"

        data.append({
            "Company Name": text_of(company, "h3.provider__title"),
            "Rating": text_of(company, "span.sg-rating__number"),
            "Number of Reviews": text_of(company, "a.sg-rating__reviews"),
            "Min Project Size": text_of(company, "li.provider__highlights-item.min-project-size span"),
            "Hourly Rate": text_of(company, "li.provider__highlights-item.hourly-rate span"),
            "Location": text_of(company, "li.provider__highlights-item.location span.locality"),
            "Profile URL": profile_url,
        })

    return data

Помощник text_of делает сразу две полезные вещи: он возвращает "N/A", когда элемент отсутствует, вместо того чтобы упасть при вызове .get_text() по пустоте, и он схлопывает последовательности пробелов через re.sub(r"\s+", " ", ...), так что число отзывов вроде "\n 128 reviews " возвращается чистым. Это сохраняет извлечение устойчивым, когда поле отсутствует, что бывает часто, поскольку не каждый поставщик указывает минимальный размер проекта или почасовую ставку. URL профиля читается из атрибута href якоря, а не из его текста, поэтому он обрабатывается отдельно.

Селекторы дрейфуют

Имена классов Clutch меняются без предупреждения. Считайте селекторы выше отправным шаблоном, а не контрактом. Когда поле возвращается как "N/A" для каждой карточки, заново осмотрите живой список в инструментах разработчика браузера и обновите селектор. Периодическое обслуживание селекторов это норма для любого продакшен-скрапера, а не признак того, что что-то сломалось.

Шаг 3: Обработайте пагинацию

Clutch перечисляет поставщиков на многих страницах и использует параметр запроса page, чтобы перемещаться между ними. Чтобы собрать весь каталог, вы обходите страницы в цикле, получаете каждую через ту же функцию и собираете строки. Поскольку каждая страница использует одну и ту же структуру карточек, парсер, который вы уже написали, работает на всех них без изменений.

python
import time

def scrape_clutch_data(base_url, pages):
    all_data = []
    for page in range(1, pages + 1):
        url = f"{base_url}?page={page}"
        html = fetch_html(url)
        if html:
            all_data.extend(parse_html(html))
        time.sleep(3)
    return all_data

Пауза time.sleep(3) между запросами сделана намеренно. Размеренный темп удерживает вас от долбления Clutch в плотном цикле, что есть самый быстрый способ получить троттлинг, даже когда каждый запрос отрисовывается через доверенный IP. Начните с горстки страниц, пока подтверждаете, что селекторы держатся, затем повысьте счётчик, когда вывод станет выглядеть правильно.

Шаг 4: Соберите всё вместе и сохраните в CSV

Теперь свяжите получение, разбор и цикл пагинации в один работающий скрипт, затем передайте собранные строки в pandas, чтобы записать CSV. Плоский CSV это самый переносимый вывод для B2B-данных: он открывается в любой таблице, загружается в базу данных и подаётся в импорт CRM без дополнительной работы.

python
import re
import time
import pandas as pd
from bs4 import BeautifulSoup
from crawlbase import CrawlingAPI

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_JS_TOKEN"})

def fetch_html(url):
    response = api.get(url, {"ajax_wait": "true", "page_wait": 5000})
    if response["status_code"] == 200:
        return response["body"].decode("utf-8")
    print(f"Request failed: {response['status_code']}")
    return None

def text_of(card, selector):
    el = card.select_one(selector)
    return re.sub(r"\s+", " ", el.get_text(strip=True)) if el else "N/A"

def parse_html(html):
    soup = BeautifulSoup(html, "html.parser")
    data = []
    for company in soup.select("ul.providers__list > li.provider"):
        profile = company.select_one("h3.provider__title a")
        data.append({
            "Company Name": text_of(company, "h3.provider__title"),
            "Rating": text_of(company, "span.sg-rating__number"),
            "Number of Reviews": text_of(company, "a.sg-rating__reviews"),
            "Min Project Size": text_of(company, "li.provider__highlights-item.min-project-size span"),
            "Hourly Rate": text_of(company, "li.provider__highlights-item.hourly-rate span"),
            "Location": text_of(company, "li.provider__highlights-item.location span.locality"),
            "Profile URL": profile["href"] if profile else "N/A",
        })
    return data

def scrape_clutch_data(base_url, pages):
    all_data = []
    for page in range(1, pages + 1):
        html = fetch_html(f"{base_url}?page={page}")
        if html:
            all_data.extend(parse_html(html))
        time.sleep(3)
    return all_data

def main():
    base_url = "https://clutch.co/it-services"
    data = scrape_clutch_data(base_url, pages=5)
    df = pd.DataFrame(data)
    df.to_csv("clutch_data.csv", index=False)
    print(f"Saved {len(data)} companies to clutch_data.csv")

if __name__ == "__main__":
    main()

Запустите полный скрипт командой python scraper.py, и он обходит пять страниц каталога IT-услуг, разбирает каждого поставщика на каждой и записывает один CSV. Замените base_url на любую другую публичную категорию, например https://clutch.co/agencies/digital, и измените pages, чтобы управлять глубиной обхода.

Как выглядит вывод

Каждая строка это чистая структурированная запись, готовая к открытию в таблице, загрузке в базу данных или подаче в CRM. Вот образец данных, которые производит скрипт, показанный в виде JSON для читаемости.

json
[
  {
    "Company Name": "Lorem Software Group",
    "Rating": "4.9",
    "Number of Reviews": "128 reviews",
    "Min Project Size": "$25,000+",
    "Hourly Rate": "$50 - $99 / hr",
    "Location": "Austin, TX",
    "Profile URL": "https://clutch.co/profile/lorem-software-group"
  },
  {
    "Company Name": "Ipsum Digital Labs",
    "Rating": "4.7",
    "Number of Reviews": "54 reviews",
    "Min Project Size": "$10,000+",
    "Hourly Rate": "$100 - $149 / hr",
    "Location": "London, England",
    "Profile URL": "https://clutch.co/profile/ipsum-digital-labs"
  }
]

Масштабирование по категориям и сохранение разблокировки

Один каталог это демо; реальная задача проходит по многим категориям. Форма остаётся той же: держите список URL категорий, запускайте scrape_clutch_data на каждой и объединяйте строки перед записью CSV. Парсер работает на всех них без изменений. Clutch это, однако, трудная коммерческая цель, поэтому несколько привычек поддерживают долгий прогон в здоровом состоянии.

  • Размеряйте свои запросы. Долбление страниц в плотном цикле это самый быстрый способ получить троттлинг. Сохраняйте паузу между запросами и растягивайте крупную задачу во времени, а не обходите весь каталог на полной скорости.
  • Опирайтесь на ротацию. Пул резидентных IP распределяет запросы по множеству адресов реальных пользователей, так что ни один из них не упирается в лимит частоты. Crawling API делает это за вас; если вы собираете свой собственный стек, это та часть, которую нужно сделать правильно.
  • Читайте коды статусов. Прогон, который начинает возвращать 403 или другие проверки, говорит вам, что текущий темп слишком агрессивен. Воспринимайте это как сигнал отступить, а не как шум, который можно игнорировать.

Более широкий план действий смотрите в как скрапить сайты, не попадая в блокировку и в более глубоком разборе как обходить капчи при веб-скрапинге. Поскольку Clutch отрисовывает часть своих страниц на стороне клиента, наше руководство по скрапингу JavaScript-страниц на Python объясняет, почему отрисовка имеет значение. А если вы предпочитаете направлять собственный трафик через ротируемый пул, вместо того чтобы использовать управляемый API, Smart AI Proxy (также называемый AI Proxy) даёт вам ту же ротацию резидентных IP в виде drop-in прокси-эндпоинта.

Законно ли скрапить Clutch.co?

Разрешён ли скрапинг Clutch.co, зависит от условий обслуживания Clutch, вашей юрисдикции и того, что вы делаете с данными. Условия Clutch налагают ограничения на автоматизированный доступ, поэтому скрапинг может вступать в противоречие с этими условиями, как бы аккуратен ни был ваш инструментарий. Ничего из кода здесь этого не меняет; он лишь заставляет техническую часть работать. Прочитайте Условия обслуживания Clutch и его robots.txt и относитесь к обоим как к границе того, что вы собираете. Clutch не публикует публичный, открытый API для своего каталога, поэтому нет санкционированного эндпоинта, которому стоило бы отдать предпочтение перед страницей; это делает соблюдение заявленных ограничений более важным, а не менее.

Несколько правил, которых стоит держаться. Собирайте только публичные данные списка компаний: название компании, рейтинг, число отзывов, минимальный размер проекта, почасовую ставку, местоположение и ссылку на профиль, которые любой может увидеть на странице категории без учётной записи. Держите объём запросов скромным, чтобы не нагружать серверы Clutch, и размеряйте прогон, а не вытягивайте весь каталог за раз. Если вы планируете повторно использовать данные коммерчески, для рассылки, перепродажи или продукта, получите разрешение или официальное соглашение, а не исходите из того, что молчание есть согласие.

Это руководство намеренно ограничено публичными страницами каталога и категорий, потому что именно эта черта удерживает работу в защитимых рамках. Оно не охватывает ничего за логином, персональные данные рецензентов, контактные сведения, которые не указаны публично, или защищённый авторским правом текст отзывов, который вы перераспределяли бы как свой собственный. Только публичные данные списка компаний. Если вашему проекту нужно больше, чем это, правильный путь это партнёрство по данным с Clutch, а не более хитрый скрапер.

Итоги

Ключевые выводы

  • Clutch блокирует обычные запросы. Голый requests.get обычно возвращает 403, поэтому вам нужно отрисовать страницу за доверенным IP, прежде чем вы сможете её разобрать.
  • Используйте JS-токен через Crawling API. Один вызов отрисовывает страницу в настоящем браузере и ротирует резидентные IP; ajax_wait и page_wait управляют тем, как долго он ждёт контента.
  • BeautifulSoup выполняет извлечение. Выберите каждый li.provider в ul.providers__list, затем прочитайте название компании, рейтинг, отзывы, мин. размер проекта, почасовую ставку, местоположение и URL профиля, и ожидайте, что селекторы будут дрейфовать.
  • Пагинируйте по параметру page. Clutch обходит страницы через ?page=N, поэтому реальная задача проходит страницы в цикле, переиспользует тот же парсер и делает паузы между запросами.
  • Оставайтесь на публичных данных. Уважайте ToS и robots.txt Clutch, держите объём скромным и получайте разрешение перед любым коммерческим повторным использованием.

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

Почему обычный запрос к Clutch.co возвращает 403?

Clutch использует агрессивную защиту от ботов. IP-адрес из дата-центра, делающий очевидно автоматизированный запрос, получает проверку или блокировку с кодом 403 ещё до того, как до вас дойдут данные списка. Чтобы получить реальные данные, вам нужен запрос, который отрисовывает страницу и приходит с IP, который платформа воспринимает как реального посетителя, и именно это обеспечивает за вас JS-токен Crawling API.

Нужен ли мне обычный токен или JS-токен для Clutch.co?

JS-токен. Обычный токен получает статический HTML и не запускает браузер, поэтому на защищённом, частично отрисовываемом на клиенте сайте вроде Clutch он, как правило, возвращается пустым или заблокированным. JS-токен отрисовывает страницу в настоящем браузере и направляет её через ротируемые резидентные IP, прежде чем отдать HTML, так что карточки компаний присутствуют, когда BeautifulSoup их разбирает.

Какие данные я могу скрапить из списка Clutch.co?

Со страницы публичной категории вы можете прочитать название компании каждого поставщика, совокупный рейтинг, число отзывов, минимальный размер проекта, диапазон почасовой ставки, местоположение и ссылку на его полный профиль. Это руководство вытягивает именно эти поля. Всё, что за логином, персональные данные рецензентов или приватные контактные сведения, находится вне области и за пределами рамок.

Как мне скрапить несколько страниц результатов Clutch.co?

Clutch пагинирует с помощью параметра запроса page, поэтому вы строите каждый URL как f"{base_url}?page={page}" и обходите номера страниц в цикле. Получайте каждую страницу через ту же функцию, запускайте тот же парсер и собирайте строки. Добавьте короткую паузу time.sleep между запросами, чтобы не долбить сайт, и повысьте счётчик страниц, когда вывод станет выглядеть правильно.

Мои селекторы возвращают «N/A» для каждой карточки. Что изменилось?

Почти наверняка разметка Clutch. Её имена классов меняются без предупреждения, поэтому селекторы, работавшие в прошлом месяце, могут сломаться. Заново осмотрите живой список в инструментах разработчика браузера и обновите селекторы, например h3.provider__title или span.sg-rating__number. Периодическое обслуживание селекторов это норма для любого продакшен-скрапера.

Как мне избежать блокировки при скрапинге Clutch.co?

Держите частоту запросов на один IP низкой, размеряйте прогон паузой между запросами и направляйте трафик через ротируемые резидентные IP, чтобы ни один адрес не упирался в лимит частоты. Crawling API управляет ротацией и пулом доверенных IP за вас; если вы строите собственный стек, это та часть, в которую стоит вложиться. Следите за кодами статусов и отступайте, когда начинаете видеть ответы 403 или другие проверки.

Начать создавать

Обходите любой сайт в масштабе, без борьбы с инфраструктурой.

Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.

Самообслуживание · Звонок отдела продаж не требуется · Доступны корпоративные объёмы краулинга