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

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

Что вы создадите

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

  • Заголовок статьи, название материала, например «Antacids Associated with Higher Risk of Migraine».
  • URL, канонический адрес публичной страницы статьи.
  • Автор, подпись, когда Healthline отображает её на странице.
  • Дата публикации или обновления, дата выхода или последней проверки статьи.
  • Категория, раздел, к которому относится статья, например health news или nutrition.
  • Резюме, краткое описание или лид, показываемый Healthline под заголовком.

Почему обычный запрос не работает на Healthline

Если запросить URL листинга или поиска Healthline с помощью обычного HTTP-клиента, вы получите ответ со статусом 200 и почти без данных статей в теле. Healthline рендерит карточки результатов в браузере с помощью JavaScript, поэтому исходный HTML является оболочкой, которая заполняется только после выполнения скриптов страницы. Страница результатов поиска в особенности формируется на стороне клиента из потока данных, что означает: заголовки, ссылки и резюме, за которыми вы пришли, отсутствуют в необработанной разметке, возвращаемой обычным вызовом requests.

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

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

Crawlbase предлагает два типа токенов. Обычный токен получает статический HTML; JavaScript (JS) токен сначала рендерит страницу в настоящем браузере. Healthline рендерится на стороне клиента, поэтому здесь нужен JS-токен. При использовании обычного токена возвращается та же пустая оболочка, что и при обычном запросе, из которой нечего парсить.

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

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

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

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

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

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

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

bash
mkdir healthline_scraper
cd healthline_scraper

python -m venv healthline_env
source healthline_env/bin/activate

pip install crawlbase beautifulsoup4 pandas

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

Шаг 1: Получение отрендеренной страницы листинга

Начните с получения готовой страницы. Импортируйте класс CrawlingAPI, инициализируйте его с помощью JS-токена и запросите URL листинга. Проверка кода статуса перед парсингом делает сбои явными, а не скрытыми. Обратите внимание на два параметра ожидания: ajax_wait указывает API дождаться завершения загрузки асинхронного контента, а page_wait задаёт фиксированное количество миллисекунд, чтобы поздно рендерящиеся карточки появились до захвата страницы.

python
from crawlbase import CrawlingAPI

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

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

if __name__ == "__main__":
    page_url = "https://www.healthline.com/search?q1=migraine"
    html = crawl(page_url)
    print(html[:500] if html else "No HTML returned")

Запустите скрипт командой python scraper.py и вы должны увидеть реальную разметку карточек результатов, а не пустую оболочку от обычного запроса. Пять секунд, разумное начальное значение page_wait; увеличьте его, если карточки возвращаются пустыми. Это подтверждает работоспособность рендеринга до написания единого селектора.

Crawlbase Crawling API

Healthline требует полностью отрендеренную страницу за доверенным IP в одном вызове, что именно вы подтвердили на шаге 1. Crawling API принимает JS-токен, запускает страницу в настоящем браузере, чтобы появились клиентские карточки статей, и ротирует жилые IP на стороне сервера, избавляя вас от необходимости запускать headless-флот и пул прокси самостоятельно. Направьте его на публичную страницу поиска с бесплатного уровня.

Шаг 2: Изучение структуры карточки результата

Перед написанием селекторов откройте страницу поиска или листинга Healthline в браузере и проверьте карточку результата с помощью инструментов разработчика. Healthline использует хешированные, генерируемые при сборке имена классов, поэтому точные строки меняются со временем. На момент написания каждый результат поиска ссылается через элемент <a> с классом вроде css-17zb9f8, а краткое описание находится в дочернем <div class="css-1evntxy">. Нужные поля примерно соответствуют следующей структуре:

  • Заголовок и URL статьи находятся на ссылке результата: текст ссылки является заголовком, href, публичным URL статьи.
  • Резюме находится в блоке описания, краткий лид, показываемый Healthline под каждым результатом.
  • Категория может быть извлечена из пути URL, например /health-news/ или /nutrition/, который Healthline использует в качестве префикса раздела.

Автор и дата не всегда присутствуют на карточке листинга; они находятся на самой странице статьи, что рассматривается на шаге 4. Поскольку имена классов Healthline хешированы и обновляются при каждой сборке, воспринимайте их как отправную точку, а не контракт, и повторно проверяйте живую страницу, когда поле возвращает пустое значение.

Шаг 3: Парсинг листинга и экспорт в CSV

Имея отрендеренный HTML, загрузите его в BeautifulSoup, выберите все ссылки результатов и извлеките из каждой заголовок, URL, резюме и категорию. Оберните чтение полей так, чтобы отсутствующий элемент возвращал пустую строку, а не прерывал выполнение, затем передайте записи в pandas для записи в CSV.

python
from bs4 import BeautifulSoup
import pandas as pd

def category_from_url(url):
    parts = url.split("/")
    return parts[3] if len(parts) > 3 else ""

def parse_listing(html):
    soup = BeautifulSoup(html, "html.parser")
    articles = []
    for link in soup.select('a.css-17zb9f8'):
        url = link.get("href", "")
        if not url:
            continue
        summary_el = link.find_next("div", class_="css-1evntxy")
        articles.append({
            "title": link.get_text(strip=True),
            "url": url,
            "category": category_from_url(url),
            "summary": summary_el.get_text(strip=True) if summary_el else "",
        })
    return articles

def save_to_csv(data, filename):
    df = pd.DataFrame(data)
    df.to_csv(filename, index=False)
    print(f"Saved {len(data)} rows to {filename}")

Ссылка результата читается один раз для получения и заголовка, и href, категория выводится из пути URL без отдельного селектора, а резюме читается с защитой, возвращающей пустую строку при отсутствии блока описания. Вспомогательный метод save_to_csv преобразует записи в DataFrame pandas и записывает их через to_csv, что является основой для дальнейшей работы в данном руководстве.

Селекторы меняются

Разметка Healthline изменяется без предупреждения, и хешированные имена классов выше могут быть переименованы при любой сборке. Когда поле возвращает пустые значения во всех карточках, повторно проверьте живую страницу в инструментах разработчика браузера и обновите селектор. Периодическое обслуживание селекторов нормально для любого продакшен-скрейпера, это не признак неисправности.

Шаг 4: Обогащение данными об авторе, дате и категории со страницы статьи

Листинг предоставляет заголовок, URL и резюме. Для заполнения автора и даты публикации или обновления получите каждую страницу статьи и прочитайте её публичные метаданные. Healthline содержит заголовок в элементе <h1>, подпись в блоке с атрибутом data-testid="byline", а дату в элементе <time>, чей атрибут datetime содержит машиночитаемую метку времени. Мы читаем только эти метаданные, но не тело статьи.

python
def text_or_empty(soup, selector):
    el = soup.select_one(selector)
    return el.get_text(strip=True) if el else ""

def parse_article_meta(html, url):
    soup = BeautifulSoup(html, "html.parser")
    time_el = soup.find("time")
    return {
        "title": text_or_empty(soup, "h1"),
        "url": url,
        "author": text_or_empty(soup, '[data-testid="byline"]'),
        "date": time_el.get("datetime", "") if time_el else "",
        "category": category_from_url(url),
    }

Каждое поле имеет запасной вариант, поэтому отсутствующая подпись или дата дают пустую строку, а не исключение. Атрибут datetime элемента <time> предпочтительнее видимого текста даты, поскольку он уже находится в стандартном формате ISO, что упрощает сортировку и фильтрацию после загрузки данных в CSV. Обратите внимание, что функция намеренно не собирает: абзацы статьи. Мы ограничиваемся заголовком, автором, датой, категорией и резюме из листинга.

Шаг 5: Собираем всё вместе

Теперь объедините парсинг листинга, обогащение по каждой статье и экспорт в CSV в один рабочий скрипт. Получите листинг, разберите его на URL, получите каждую страницу статьи для её метаданных и запишите всё в единый CSV. Короткая пауза между запросами поддерживает вежливый темп выполнения.

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

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_JS_TOKEN"})
OPTIONS = {"ajax_wait": "true", "page_wait": 5000}

def crawl(page_url):
    response = api.get(page_url, OPTIONS)
    if response["status_code"] == 200:
        return response["body"].decode("utf-8")
    print(f"Request failed: {response['status_code']}")
    return None

def main():
    listing_url = "https://www.healthline.com/search?q1=migraine"
    listing_html = crawl(listing_url)
    if not listing_html:
        return

    listing = parse_listing(listing_html)
    records = []
    for item in listing:
        article_html = crawl(item["url"])
        if article_html:
            meta = parse_article_meta(article_html, item["url"])
            meta["summary"] = item["summary"]
            records.append(meta)
        time.sleep(2)

    save_to_csv(records, "healthline_articles.csv")

if __name__ == "__main__":
    main()

Предполагается, что функции parse_listing, parse_article_meta, category_from_url и save_to_csv из предыдущих шагов находятся в том же файле. Алгоритм прост: один запрос для листинга, затем один запрос на статью для её обогащения автором и датой, затем единая запись в CSV в конце. Резюме summary из карточки листинга объединяется с метаданными каждой статьи, чтобы каждая строка была полной.

Как выглядит результат

Запустите полный скрипт командой python scraper.py и получите CSV с одной строкой на статью, каждая из которых содержит только публичные метаданные, готовые для анализа в pandas или в таблице.

csv
title,url,author,date,category,summary
"Antacids Associated with Higher Risk of Migraine",https://www.healthline.com/health-news/antacids-increase-migraine-risk,"Nancy Schimelpfening",2024-01-09,health-news,"New research suggests people who take antacids may be at greater risk for migraine attacks."
"Migraine: What to Ask Your Doctor",https://www.healthline.com/health/migraine/what-to-ask-doctor-migraine,"Healthline Editorial Team",2023-11-02,health,"A short list of questions to bring to your next appointment."

Поскольку дата берётся из атрибута datetime элемента <time>, она записывается в формате ISO, что позволяет сортировать по свежести или фильтровать диапазон дат без разбора свободного текста. Колонка категорий, выведенная из пути каждого URL, позволяет группировать количество по разделам, чтобы видеть, на чём концентрирует публикации издатель.

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

Один листинг, это демонстрация; реальная задача охватывает множество тем и страниц результатов. Поиск Healthline принимает параметр запроса, поэтому можно перебирать список тем и использовать одну и ту же пару «получение, парсинг» для каждой. Поскольку все результаты поиска имеют одинаковую структуру карточек, уже написанный парсер работает со всеми ними без изменений. Добавляйте строки из каждой темы в один список и записывайте единый CSV в конце.

python
def scrape_topics(topics):
    all_articles = []
    for topic in topics:
        url = f"https://www.healthline.com/search?q1={topic}"
        html = crawl(url)
        if html:
            all_articles.extend(parse_listing(html))
        time.sleep(2)
    return all_articles

topics = ["migraine", "nutrition", "sleep"]
save_to_csv(scrape_topics(topics), "healthline_topics.csv")

Вызов time.sleep(2) между темами намеренен. Непрерывный поиск в жёстком цикле, это самый быстрый способ получить ограничение, даже при обработке рендеринга и ротации за вас. Распределяйте запросы и прекращайте раньше, если тема перестаёт возвращать новые статьи.

Оставаться незаблокированным

Даже при обработке рендеринга, Healthline отслеживает трафик, похожий на скрейперский. Несколько привычек помогают поддерживать работоспособность запуска, и они применимы к любому крупному издателю.

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

Для более широкого руководства по стратегии см. статьи о том, как парсить сайты без блокировки и о способах обхода CAPTCHA при веб-скрейпинге. Если вы предпочитаете направлять собственный трафик через ротирующийся пул вместо использования управляемого API, Smart AI Proxy (также называемый AI Proxy) предоставляет ту же ротацию жилых IP в виде прокси-эндпоинта для прямой замены.

Законно ли парсить Healthline?

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

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

Ещё один момент, специфичный для медицинского издателя: это руководство предназначено для каталогизации и исследований на основе публичных метаданных, а не для получения медицинских рекомендаций. Медицинская информация меняется, и точность статьи зависит от контекста, который одна строка данных не может передать. Не полагайтесь на scraped медицинский контент при принятии медицинских решений и проконсультируйтесь с квалифицированным медицинским или юридическим специалистом перед использованием или распространением любого из них. Healthline не предлагает публичного API для массового доступа к статьям, поэтому если ваш проект требует полного контента или крупномасштабного распространения, правильный путь состоит в запросе разрешения или лицензионного соглашения, а не в разработке более умного скрейпера.

Итоги

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

  • Healthline рендерится на стороне клиента. Обычный запрос возвращает пустую оболочку, поэтому страницу необходимо отрендерить перед парсингом.
  • Рендеринг и доверенный IP работают вместе. Crawling API с JS-токеном делает оба в одном вызове, используя ajax_wait и page_wait, чтобы карточки статей завершили загрузку до захвата.
  • BeautifulSoup вместе с pandas выполняют работу. Сопоставьте заголовок, URL, автора, дату, категорию и резюме с хуками страницы, затем экспортируйте строки прямо в CSV.
  • Масштабируйтесь через перебор тем. Обходите список поисковых запросов с одним и тем же парсером и задавайте темп цикла, чтобы не получить ограничение.
  • Оставайтесь в рамках публичных метаданных. Соблюдайте условия использования Healthline и robots.txt, никогда не переиздавайте защищённые авторским правом тексты статей и проконсультируйтесь со специалистом перед использованием медицинского контента.

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

Можно ли парсить Healthline только с помощью requests и BeautifulSoup?

Ненадёжно. Healthline рендерит карточки результатов в браузере с помощью JavaScript, поэтому обычный вызов requests возвращает статус 200 с пустыми листингами. Вам нужно что-то, что сначала отрендерит страницу, чем и занимаются JS-токен Crawling API и опции ajax_wait с page_wait, прежде чем BeautifulSoup увидит HTML.

Какой токен нужен для Healthline: обычный или JS?

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

Какие данные следует собирать с Healthline?

Ограничьтесь публичными метаданными: заголовком статьи, URL, автором, датой публикации или обновления, категорией и кратким резюме, показываемым на публичных страницах. Не парсите и не переиздавайте полные тексты статей. Статьи Healthline являются защищёнными авторским правом редакционными материалами, поэтому безопасная и обоснованная область применения ограничивается структурой и резюме для исследований, но не самим текстом.

Как экспортировать scraped данные в CSV?

Создайте список словарей (по одному на статью), затем передайте его в pandas: pd.DataFrame(data).to_csv("healthline_articles.csv", index=False). Вспомогательный метод save_to_csv в данном руководстве оборачивает именно это. Поскольку каждая строка содержит только плоские поля метаданных, CSV чисто открывается в любой таблице или загружается обратно в pandas для анализа.

Мои селекторы возвращают пустые строки. Что изменилось?

Почти наверняка разметка Healthline. Хешированные имена классов, на которые опирается парсер, обновляются при каждой сборке, а редизайн может переименовать хуки подписи или даты. Повторно проверьте живую страницу в инструментах разработчика браузера и обновите селекторы. Периодическое обслуживание селекторов нормально для любого продакшен-скрейпера.

Можно ли полагаться на scraped медицинскую информацию?

Нет. Воспринимайте scraped строки как метаданные для каталогизации и исследований, а не как медицинские рекомендации. Медицинская информация меняется и зависит от контекста, который одно поле не может передать, поэтому проконсультируйтесь с квалифицированным медицинским или юридическим специалистом перед использованием или распространением любого из них. Для полного контента или крупномасштабного распространения обратитесь за разрешением или лицензией к Healthline, а не занимайтесь парсингом текстов статей.

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

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

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

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