Как я собираю Hacker News с помощью Python: 2 способа, полный код

Последнее обновление: April 16, 2026

Несколько месяцев назад я решил собрать ежедневную подборку самых интересных материалов с Hacker News для команды Thunderbit. Сначала мне показалось, что проще всего просто добавить сайт в закладки и просматривать его каждое утро. Но уже через три дня я понял, что трачу по 20 минут в день только на чтение заголовков и копирование ссылок в таблицу.

Hacker News — один из самых насыщенных и концентрированных источников техно-новостей в интернете: примерно , около 1300 новых публикаций ежедневно и примерно 13 000 комментариев в сутки. Если вы следите за новыми технологическими трендами, мониторите упоминания бренда, строите воронку найма из тредов «Who’s Hiring» или просто хотите понимать, чем живёт developer-сообщество, вручную отслеживать всё это — заведомо проигрышная стратегия.

Хорошая новость: собирать данные с Hacker News на Python на удивление просто. В этом руководстве я покажу два полноценных способа — парсинг HTML через BeautifulSoup и официальный HN Firebase API — а также разберу пагинацию, экспорт данных, production-подходы и no-code альтернативу на случай, если Python кажется вам избыточным.

Зачем собирать Hacker News с помощью Python?

Hacker News — это не просто ещё один агрегатор ссылок. Это кураторская, основанная на сообществе лента, где самые интересные техно-истории поднимаются наверх благодаря голосам и активному обсуждению. Аудитория сильно смещена в сторону IT-профессионалов (примерно ), а показатель прямого трафика в 66% говорит о том, что это лояльные, привычные читатели, а не случайные посетители.

Вот зачем люди собирают данные HN:

СценарийЧто вы получаете
Ежедневный технодайджестТоп-истории, оценки и ссылки в почте или Slack
Мониторинг бренда и конкурентовУведомления, когда упоминают вашу компанию или продукт
Анализ трендовОтслеживание технологий, языков и тем, которые набирают популярность
РекрутингРазбор тредов "Who’s Hiring" для вакансий, стеков и сигналов по зарплатам
Исследование контентаПоиск тем, которые хорошо заходят у аудитории
Анализ тональностиОценка мнений сообщества о продуктах, запусках и изменениях в индустрии

Компании с совокупной капитализацией свыше 400 миллиардов долларов — Stripe, Dropbox, Airbnb — получили на Hacker News важную раннюю обратную связь и первых пользователей. Drew Houston в апреле 2007 года опубликовал демо Dropbox на HN, оно вышло на первое место, а лист ожидания бета-версии вырос с 5000 до 75 000 пользователей всего за один день. Данные HN не просто интересны — они приносят коммерческую ценность.

Данные доступны публично, но структура сайта делает ручной сбор слишком трудоёмким. Поэтому автоматизация на Python — наиболее практичное решение.

Два способа собирать Hacker News на Python: обзор

В этом руководстве я покажу два полностью рабочих подхода:

  1. Парсинг HTML с помощью requests + BeautifulSoup — загружаем сырой HTML с news.ycombinator.com и разбираем его, чтобы извлечь данные о публикациях. Отличный вариант, если вы хотите освоить основы парсинга и брать ровно то, что отображается на странице.
  2. Официальный Hacker News Firebase API — обращаемся напрямую к JSON-эндпоинтам, без разбора HTML. Более надёжный вариант для продакшн-пайплайнов, доступа к комментариям и историческим данным.

Вот сравнение в лоб, чтобы было проще выбрать подходящий метод:

КритерийHTML-парсинг (requests + BS4)HN Firebase APIThunderbit (No-code)
Сложность настройкиСредняя (нужно разбирать HTML-селекторы)Низкая (JSON-эндпоинты)Нет (расширение Chrome в 2 клика)
Актуальность данныхРеальное время на главной страницеРеальное время (любой элемент по ID)Реальное время
Риск ограничения по частотеСредний (robots.txt указывает задержку 30 сек)Низкий (официальный, щедрый)Управляется Thunderbit
Доступ к комментариямСложно (вложенный HTML)Просто (рекурсивные item ID)Функция парсинга подстраниц
Исторические данныеОграниченноЧерез Algolia Search APIНе поддерживается
Лучше всего подходит дляИзучения основ парсингаНадёжных пайплайновНетехнических пользователей, быстрых выгрузок

Оба метода включают полный рабочий Python-код. А если вам нужны только данные — без написания кода — я покажу и такой вариант.

Перед началом

  • Уровень сложности: от новичка до среднего
  • Время: примерно 15–20 минут на каждый метод
  • Что понадобится:
    • Python 3.11+ установлен
    • Терминал или редактор кода
    • Браузер Chrome (если хотите посмотреть HTML HN или попробовать no-code-способ)
    • (необязательно, для no-code метода)

scrape-hacker-news-methods.webp

Настраиваем Python-окружение

Прежде чем трогать данные HN, подготовим окружение. Я рекомендую создать виртуальное окружение, чтобы зависимости проекта были изолированы и не засоряли систему.

1# Создаём и активируем виртуальное окружение
2python3 -m venv hn-scraper
3# macOS/Linux:
4source hn-scraper/bin/activate
5# Windows:
6hn-scraper\Scripts\activate
7# Устанавливаем пакеты, которые понадобятся для обоих способов
8pip install requests==2.33.1 beautifulsoup4==4.14.3 pandas==3.0.2 openpyxl==3.1.5

Для производственных сценариев, где нужны кеширование и повторы запросов, пригодятся ещё и эти пакеты:

1pip install requests-cache==1.3.1 tenacity==9.1.4

Никаких специальных API-ключей или токенов авторизации не нужно. Данные HN открыты.

Способ 1: собираем Hacker News на Python через BeautifulSoup

Это классический путь: скачиваем HTML, разбираем его и вытаскиваем нужные данные. Именно так большинство людей впервые знакомятся с веб-скрейпингом, а простая табличная структура HN делает сайт отличным полигоном для практики.

Шаг 1: загружаем главную страницу Hacker News

Откройте редактор и создайте файл scrape_hn_bs4.py. Вот стартовый код:

1import requests
2from bs4 import BeautifulSoup
3> This paragraph contains content that cannot be parsed and has been skipped.
4print(f"Status: {response.status_code}, Page length: {len(response.text)} chars")

Запустите его. Вы должны увидеть Status: 200 и длину страницы примерно 40 000–50 000 символов. Это и есть сырой HTML главной страницы HN, уже загруженный в память и готовый к разбору.

Шаг 2: разбираем HTML-структуру

HN использует табличную вёрстку — без современных CSS grid или flexbox. Каждая публикация на странице состоит из двух ключевых строк <tr>:

  • Строка истории (<tr class="athing submission">): содержит номер, заголовок и ссылку
  • Строка метаданных (следующая строка <tr>): содержит очки, автора, время и число комментариев

Важные селекторы:

  • span.titleline > a — заголовок и URL истории
  • span.score — количество голосов (например, "118 points")
  • a.hnuser — имя пользователя автора
  • span.age — время публикации
  • Последний <a> в .subtext со словом "comment" — число комментариев

Если щёлкнуть правой кнопкой по любому заголовку на HN в Chrome и выбрать "Inspect", вы увидите примерно такое:

1<span class="titleline">
2  <a href="https://darkbloom.dev">DarkbloomPrivate inference on idle Macs</a>
3</span>

А ниже — строку метаданных:

1<span class="score" id="score_47788542">118 points</span>
2by <a href="user?id=twapi" class="hnuser">twapi</a>
3<span class="age" title="2026-04-16T04:06:39 1776312399">
4  <a href="item?id=47788542">2 hours ago</a>
5</span>
6| <a href="item?id=47788542">65&nbsp;comments</a>

Понимание этих селекторов критически важно: если HN когда-нибудь изменит разметку, селекторы придётся обновить. (Спойлер: API-метод полностью снимает эту проблему.)

Шаг 3: извлекаем заголовки, ссылки и оценки

Теперь переходим к практике. Мы пройдёмся по каждой строке с историей, возьмём заголовок и ссылку из строки самой истории, а затем заберём оценку из строки метаданных сразу под ней.

1import requests
2from bs4 import BeautifulSoup
3from pprint import pprint
4> This paragraph contains content that cannot be parsed and has been skipped.
5stories = []
6story_rows = soup.select("tr.athing")
7for row in story_rows:
8    # Заголовок и URL из строки истории
9    title_tag = row.select_one("span.titleline > a")
10    if not title_tag:
11        continue
12    title = title_tag.get_text()
13    link = title_tag.get("href", "")
14    # Метаданные из следующей строки
15    meta_row = row.find_next_sibling("tr")
16    score = 0
17    author = ""
18    comments = 0
19> This paragraph contains content that cannot be parsed and has been skipped.
20> This paragraph contains content that cannot be parsed and has been skipped.
21# Фильтруем истории с 50+ очками и сортируем по оценке
22top_stories = sorted(
23    [s for s in stories if s["score"] >= 50],
24    key=lambda x: x["score"],
25    reverse=True,
26)
27pprint(top_stories[:10])

Несколько замечаний по коду:

  • Оператор присваивания в выражении (:=) работает в Python 3.8+. Он позволяет присваивать и проверять значение в одной строке — удобно для необязательных элементов вроде span.score, которых может не быть в каждой строке (например, у job-постов нет оценки).
  • В HN между числом и словом "comments" используется \xa0 — неразрывный пробел, поэтому мы делим строку именно по нему.
  • Если история ведёт на другую страницу HN (например, посты вида "Ask HN"), URL будет относительным и начнётся с item?id=. В таком случае можно добавить префикс https://news.ycombinator.com/.

Шаг 4: запускаем и смотрим результат

Сохраните файл и выполните:

1python scrape_hn_bs4.py

Вы должны увидеть примерно такой вывод:

1[{'author': 'twapi',
2  'comments': 65,
3  'score': 118,
4  'title': 'Darkbloom – Private inference on idle Macs',
5  'url': 'https://darkbloom.dev'},
6 {'author': 'sebg',
7  'comments': 203,
8  'score': 247,
9  'title': 'Show HN: I built an open-source Perplexity alternative',
10  'url': 'https://github.com/...'},
11 ...]

Это 30 историй с первой страницы. Но на HN всегда есть сотни активных публикаций. Пагинацию мы разберём чуть позже.

Способ 2: собираем Hacker News через официальный API

HN Firebase API — это официальный способ получать данные Hacker News. Без авторизации, без API-ключей, без разбора HTML. Вы получаете аккуратные JSON-ответы. Я использую этот метод для всего, что должно стабильно работать в продакшене.

Основные API-эндпоинты, которые нужно знать

Базовый URL: https://hacker-news.firebaseio.com/v0/. Вот самые важные эндпоинты:

This paragraph contains content that cannot be parsed and has been skipped.

Пример объекта истории выглядит так:

1{
2  "by": "twapi",
3  "descendants": 65,
4  "id": 47788542,
5  "kids": [47789171, 47788769, 47788762],
6  "score": 118,
7  "time": 1776312399,
8  "title": "Darkbloom – Private inference on idle Macs",
9  "type": "story",
10  "url": "https://darkbloom.dev"
11}

Поле kids содержит ID дочерних комментариев первого уровня. Каждый комментарий — это тоже отдельный item, у которого могут быть свои kids. Так и строится дерево комментариев.

Шаг 1: получаем ID лучших историй

Создайте файл scrape_hn_api.py:

1import requests
2import time
3from pprint import pprint
4API_BASE = "https://hacker-news.firebaseio.com/v0"
5# Получаем ID лучших историй
6response = requests.get(f"{API_BASE}/topstories.json")
7story_ids = response.json()
8print(f"Got {len(story_ids)} top story IDs")
9# Output: Got 500 top story IDs

500 ID историй за один запрос — без селекторов, без разбора HTML, просто JSON-массив.

Шаг 2: получаем данные истории по ID

Теперь нужны сами данные историй. И здесь появляется проблема fan-out: 500 историй означают 500 отдельных запросов к API. По моим замерам, один запрос к item при последовательной обработке занимает около 1,2 секунды. Для 500 историй это примерно 10 минут.

Для большинства задач вам не нужны все 500. Вот код, который забирает топ-30:

1def fetch_story(story_id):
2    """Получает данные одной истории из HN API."""
3    resp = requests.get(f"{API_BASE}/item/{story_id}.json")
4    return resp.json()
5> This paragraph contains content that cannot be parsed and has been skipped.
6# Сортируем по score и показываем топ-10
7top = sorted(stories, key=lambda x: x["score"], reverse=True)[:10]
8pprint(top)

time.sleep(0.1) добавляет небольшую паузу из вежливости. У Firebase API нет явно указанного лимита, но без пауз «долбить» любой API — плохая практика.

Шаг 3: собираем комментарии (рекурсивный обход дерева)

Вот здесь API действительно выигрывает у HTML-парсинга. Комментарии на HN глубоко вложенные — ответы на ответы на ответы. В HTML это значит сложный разбор вложенных таблиц. Через API всё проще: у каждого комментария есть поле kids со списком ID дочерних комментариев, и вы просто рекурсивно обходите дерево.

1def fetch_comments(item_id, depth=0, max_depth=3):
2    """Рекурсивно получает комментарии до max_depth."""
3    item = requests.get(f"{API_BASE}/item/{item_id}.json").json()
4    if not item or item.get("type") != "comment":
5        return []
6> This paragraph contains content that cannot be parsed and has been skipped.
7    if depth < max_depth and item.get("kids"):
8        for kid_id in item["kids"]:
9            comments.extend(fetch_comments(kid_id, depth + 1, max_depth))
10            time.sleep(0.05)
11    return comments
12# Пример: собираем комментарии для самой верхней истории
13if stories:
14    top_story = stories[0]
15    top_story_full = requests.get(f"{API_BASE}/item/{top_story['id']}.json").json()
16    if top_story_full.get("kids"):
17        print(f"\nComments for: {top_story['title']}")
18        all_comments = []
19        for kid_id in top_story_full["kids"][:5]:  # Первые 5 комментариев верхнего уровня
20            all_comments.extend(fetch_comments(kid_id, depth=0, max_depth=2))
21            time.sleep(0.1)
22        for c in all_comments[:15]:
23            indent = "  " * c["depth"]
24            preview = c["text"][:80].replace("\n", " ") if c["text"] else "[no text]"
25            print(f"{indent}[{c['author']}] {preview}...")

Такой рекурсивный подход намного проще, чем попытки разбирать вложенные HTML-треды комментариев. Если вам нужно полное дерево комментариев, API — лучший путь.

Шаг 4: запускаем и смотрим результат

1python scrape_hn_api.py

Вы увидите структурированные данные по историям, а затем — вложенный предпросмотр комментариев. Данные чище, доступ к комментариям проще, и нет риска, что парсер сломается из-за изменения CSS-класса на стороне HN.

Выходим за пределы первой страницы: пагинация и исторические данные

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

Парсим несколько страниц с BeautifulSoup

Пагинация HN использует простой шаблон URL: ?p=2, ?p=3 и так далее. Каждая страница содержит 30 историй, а сайт отдаёт примерно до 20 страниц (около 600 историй в сумме). Дальше идут пустые страницы.

1import time
2def scrape_hn_pages(num_pages=5):
3    """Собирает истории с нескольких страниц главной HN."""
4    all_stories = []
5    for page in range(1, num_pages + 1):
6        url = f"https://news.ycombinator.com/news?p={page}"
7        response = requests.get(url, headers=headers)
8        soup = BeautifulSoup(response.text, "html.parser")
9        story_rows = soup.select("tr.athing")
10        if not story_rows:
11            print(f"Page {page}: no stories found, stopping.")
12            break
13        for row in story_rows:
14            title_tag = row.select_one("span.titleline > a")
15            if not title_tag:
16                continue
17            meta_row = row.find_next_sibling("tr")
18            score = 0
19            if meta_row and (score_tag := meta_row.select_one("span.score")):
20                score = int(score_tag.get_text().replace(" points", ""))
21> This paragraph contains content that cannot be parsed and has been skipped.
22        print(f"Page {page}: scraped {len(story_rows)} stories")
23        # Соблюдаем crawl-delay 30 секунд из robots.txt
24        if page < num_pages:
25            time.sleep(30)
26    return all_stories
27stories = scrape_hn_pages(5)
28print(f"\nTotal stories scraped: {len(stories)}")

time.sleep(30) здесь очень важен. В HN прямо просит соблюдать 30-секундную задержку между обходами. Если игнорировать это требование, можно получить ограничение по частоте запросов (HTTP 429) или временную блокировку. Пять страниц с интервалом 30 секунд займут около 2,5 минут — не мгновенно, но уважительно.

Если вы не хотите вручную управлять пагинацией, автоматически обрабатывает пагинацию по кликам и бесконечную прокрутку. Он нажимает кнопку "More" внизу страниц HN без какой-либо настройки.

Доступ к историческим данным Hacker News через Algolia API

Firebase API даёт актуальные данные. Для исторического анализа — например, «Какие Python-истории были в топе в 2023 году?» или «Как менялся охват темы AI за последние 5 лет?» — нужен .

1import requests
2ALGOLIA_BASE = "https://hn.algolia.com/api/v1"
3> This paragraph contains content that cannot be parsed and has been skipped.
4# Пример: найти истории про Python scraping с 10+ очками начиная с января 2024
5results = search_hn(
6    query="python scraping",
7    tags="story",
8)
9print(f"Found {results['nbHits']} total results")
10for hit in results["hits"][:5]:
11    print(f"  [{hit.get('points', 0)} pts] {hit['title']}")

Для запросов с фильтрацией по дате используйте numericFilters:

1import calendar, datetime
2# Истории с 1 января 2024
3start_date = datetime.datetime(2024, 1, 1)
4start_ts = int(calendar.timegm(start_date.timetuple()))
5> This paragraph contains content that cannot be parsed and has been skipped.
6Algolia API работает быстро (59 мс серверного времени обработки), не требует API-ключа и поддерживает пагинацию до 500 страниц. Для массового исторического анализа это лучший вариант.
7## Экспорт данных Hacker News в CSV, Excel и Google Sheets
8Практически каждый туториал по HN заканчивается выводом `pprint()` в терминал. Для отладки это удобно, но если вы делаете ежедневный дайджест или анализ трендов, данные нужно сохранять в файл. Вот как это сделать.
9### Экспорт в CSV на Python
10```python
11import csv
12def export_to_csv(stories, filename="hn_stories.csv"):
13    """Сохраняет собранные истории в CSV-файл."""
14    fieldnames = ["title", "url", "score", "author", "comments"]
15    with open(filename, "w", newline="", encoding="utf-8") as f:
16        writer = csv.DictWriter(f, fieldnames=fieldnames)
17        writer.writeheader()
18        writer.writerows(stories)
19    print(f"Saved {len(stories)} stories to {filename}")
20export_to_csv(stories)

Экспорт в Excel на Python

1import pandas as pd
2def export_to_excel(stories, filename="hn_stories.xlsx"):
3    """Сохраняет собранные истории в Excel-файл."""
4    df = pd.DataFrame(stories)
5    df.to_excel(filename, index=False, engine="openpyxl")
6    print(f"Saved {len(stories)} stories to {filename}")
7export_to_excel(stories)

Убедитесь, что openpyxl установлен — pandas использует его как движок для Excel. Если пакета нет, появится ошибка ImportError.

Отправка в Google Sheets (по желанию)

Для автоматизированных сценариев вы можете отправлять данные напрямую в Google Sheets через библиотеку gspread. Для этого нужно один раз настроить service account в Google Cloud:

1import gspread
2gc = gspread.service_account(filename="service_account.json")
3sh = gc.open("HN Daily Digest")
4worksheet = sh.sheet1
5# Преобразуем истории в строки
6header = list(stories[0].keys())
7rows = [list(s.values()) for s in stories]
8worksheet.clear()
9worksheet.update([header] + rows)
10print("Pushed to Google Sheets")

No-code альтернатива экспорту

Если настройка service account и написание кода для экспорта кажется более сложной задачей, чем сам сбор данных, я вас понимаю. В Thunderbit мы сделали бесплатный экспорт данных, который позволяет отправлять собранную информацию напрямую в Excel, Google Sheets, Airtable или Notion — без кода, без учётных данных, без поддержки пайплайна. Для разовой выгрузки это действительно быстрее. Об этом ещё ниже.

Делаем скрейпер готовым к продакшену: обработка ошибок, кеширование и расписание

Если вы запускаете скрейпер один раз ради интереса, код выше подойдёт. Но если он должен работать ежедневно в составе процесса, нужны дополнительные элементы.

Обработка ошибок и повторные попытки

Сети падают. Серверы ограничивают частоту. Одна неудачная попытка не должна валить весь сбор. Вот функция retry с экспоненциальной задержкой:

1from tenacity import retry, stop_after_attempt, wait_exponential_jitter
2import requests
3@retry(stop=stop_after_attempt(5), wait=wait_exponential_jitter(initial=1, max=60))
4def fetch_with_retry(url):
5    """Загружает URL с автоматическими повторами и экспоненциальной задержкой."""
6    response = requests.get(url, timeout=10)
7    response.raise_for_status()
8    return response
9# Использование:
10try:
11    resp = fetch_with_retry("https://hacker-news.firebaseio.com/v0/topstories.json")
12    story_ids = resp.json()
13except Exception as e:
14    print(f"Failed after retries: {e}")

Библиотека tenacity аккуратно берёт на себя retry-логику. Она попробует повторить запрос до 5 раз с экспоненциальной задержкой и jitter — начиная с 1 секунды и увеличивая паузу максимум до 60 секунд. Это помогает мягко переживать HTTP 429 (слишком много запросов), 503 (сервис недоступен) и временные сетевые сбои.

Кеширование ответов, чтобы не сканировать одно и то же заново

Во время разработки вы будете запускать скрипт много раз, отлаживая логику парсинга. Без кеша каждый прогон снова обращается к серверам HN за теми же данными. Библиотека requests-cache решает это буквально двумя строками:

1import requests_cache
2requests_cache.install_cache("hn_cache", expire_after=3600)  # Кеш на 1 час

После добавления этих строк в начало скрипта все вызовы requests.get() автоматически сохраняются в локальную SQLite-базу. Запустите скрипт 10 раз в течение часа — и только первый запуск действительно пойдёт в сеть. Это инструмент, который , и не зря.

Разделяйте сбор и разбор данных

Паттерн, который любят опытные скрейперы: сначала скачайте сырые данные, потом разбирайте их. Так, если в логике парсинга окажется баг, вы исправите его и просто заново выполните разбор без повторной загрузки.

1import os, json
2def crawl_and_save(story_ids, output_dir="raw_data"):
3    """Загружает данные историй и сохраняет сырой JSON на диск."""
4    os.makedirs(output_dir, exist_ok=True)
5    for sid in story_ids:
6        filepath = os.path.join(output_dir, f"{sid}.json")
7        if os.path.exists(filepath):
8            continue  # Пропускаем уже скачанные элементы
9        resp = fetch_with_retry(f"{API_BASE}/item/{sid}.json")
10        with open(filepath, "w") as f:
11            json.dump(resp.json(), f)
12> This paragraph contains content that cannot be parsed and has been skipped.
13Такой двухэтапный подход особенно полезен, когда вы собираете сотни элементов и хотите быстро экспериментировать с обработкой данных.
14### Автоматизируем запуск по расписанию
15Для ежедневного дайджеста HN скрейпер должен запускаться автоматически. Два популярных варианта:
16**Вариант 1: cron (Linux/Mac)**
17```bash
18# Запуск каждый день в 8:30 UTC
1930 8 * * * /usr/bin/python3 /home/user/scrape_hn.py >> /home/user/scrape.log 2>&1

Вариант 2: GitHub Actions (бесплатно, без сервера)

1name: Scrape Hacker News
2on:
3  schedule:
4    - cron: '30 8 * * *'  # Ежедневно в 8:30 UTC
5  workflow_dispatch:        # Кнопка ручного запуска
6jobs:
7  scrape:
8    runs-on: ubuntu-latest
9    steps:
10      - uses: actions/checkout@v4
11      - uses: actions/setup-python@v6
12        with:
13          python-version: '3.12'
14      - run: pip install requests beautifulsoup4 pandas openpyxl
15      - run: python scrape_hn.py
16      - run: |
17          git config user.name "GitHub Actions Bot"
18          git config user.email "actions@github.com"
19          git add -A
20          git diff --staged --quiet || git commit -m "Update HN data $(date -u +%Y-%m-%dT%H:%M:%SZ)"
21          git push

Несколько нюансов по расписанию в GitHub Actions: все cron-время указаны в UTC, задержки в 15–60 минут — обычное дело (используйте времена вроде :30, а не :00), а GitHub может отключить запланированные workflow в репозиториях без активности в течение 60 дней. Всегда добавляйте workflow_dispatch, чтобы можно было запускать workflow вручную для теста.

Если хотите более простой вариант, Scheduled Scraper в Thunderbit позволяет задать расписание обычным языком — например, «собирать каждое утро в 8:00» — без сервера и без настройки cron.

Когда Python избыточен: no-code способ собрать Hacker News

Скажу честно, даже несмотря на то, что я люблю Python и моя команда делает инструменты для разработчиков. Если вам нужны просто сегодняшние топ-100 историй HN в таблице — прямо сейчас, один раз — писать, отлаживать и запускать Python-скрипт не нужно. Одна только подготовка окружения (виртуальное окружение, установка пакетов, поиск селекторов) занимает больше времени, чем сам сбор данных.

Вот здесь и подходит . Рабочий процесс такой:

  1. Откройте news.ycombinator.com в Chrome
  2. Нажмите иконку расширения Thunderbit, затем выберите "AI Suggest Fields"
  3. AI проанализирует страницу и предложит столбцы: Title, URL, Score, Author, Comment Count, Time Posted
  4. При необходимости отредактируйте поля — переименуйте, удалите или добавьте свои; можно даже добавить AI-подсказку вроде "Categorize as AI/DevTools/Web/Other"
  5. Нажмите "Scrape" — данные появятся в структурированной таблице
  6. Экспортируйте в Excel, Google Sheets, Airtable или Notion

Два клика — и у вас структурированные данные. Без селекторов, без кода, без сопровождения.

Ещё одно важное преимущество: AI в Thunderbit автоматически подстраивается под изменения вёрстки. Классические скрейперы на CSS-селекторах ломаются, когда сайт меняет разметку — а у HN HTML хоть и довольно стабилен, но всё же менялся (например, класс class="athing submission" обновлялся, а span.titleline заменил старый a.storylink). AI-скрейпер каждый раз читает страницу заново, поэтому ему всё равно, как называются CSS-классы.

python-vs-thunderbit-comparison.webp

Thunderbit также умеет работать с пагинацией (автоматически нажимает кнопку "More" на HN) и собирать данные со страниц подстраниц (переходить на страницу комментариев каждой истории и вытаскивать обсуждение). Для сценария это аналог рекурсивного API-кода из Способа 2 — только без единой строчки кода.

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

Python против API против no-code: какой способ выбрать?

Вот полная схема принятия решения:

КритерийBeautifulSoup (HTML)Firebase APIAlgolia APIThunderbit (No-code)
Нужный уровень навыкаPython среднего уровняPython для новичковPython для новичковНе нужен
Время на настройку10–15 мин5–10 мин5–10 мин2 мин
Нагрузка на поддержкуСредняя (селекторы ломаются)Низкая (стабильный JSON)Низкая (стабильный JSON)Нет
Глубина данныхТолько главная страницаЛюбой item, пользователиПоиск + историяГлавная + подстраницы
КомментарииСложноПросто (рекурсивно)Просто (вложенное дерево)Парсинг подстраниц
Исторические данныеНетНетДа (полный архив)Нет
ЭкспортПишете самиПишете самиПишете самиВстроенный (Excel, Sheets и т. д.)
Расписаниеcron / GitHub Actionscron / GitHub Actionscron / GitHub ActionsВстроенный планировщик
Лучший вариант дляОбучения скрейпингуНадёжных пайплайновИсследований и аналитикиБыстрых выгрузок

Если вы учите Python или делаете что-то кастомное, выбирайте Способ 1 или 2. Если нужны исторические данные, добавьте Algolia API. Если хотите просто получить данные без кода, .

Итоги и ключевые выводы

Теперь у вас в арсенале есть:

  • Два полноценных Python-способа собирать данные с Hacker News — BeautifulSoup для парсинга HTML и Firebase API для чистых JSON-данных
  • Пагинация для сбора данных дальше первой страницы, включая Algolia API для исторических данных, уходящих в 2007 год
  • Код экспорта в CSV, Excel и Google Sheets — потому что данные, лежащие в терминале, никому в команде не помогут
  • Production-подходы — retry-логика, кеширование, разделение сбора и парсинга, а также автоматический запуск по cron или GitHub Actions
  • No-code альтернативу на случай, если Python — это уже лишний инструмент

Моя рекомендация: для большинства задач начинайте с Firebase API (Способ 2). Он чище, надёжнее и позволяет получать комментарии без мучений с разбором вложенного HTML. Если нужны исторические данные — подключайте Algolia API. А держите под рукой на случай, когда нужен быстрый spreadsheet и нет желания поднимать целый Python-проект.

Если хотите углубиться, попробуйте собирать комментарии HN для , построить ежедневный дайджест через GitHub Actions или исследовать Algolia API, чтобы понять, как менялись технологические тренды за последнее десятилетие.

Попробуйте Thunderbit для быстрого сбора данных с Hacker News

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

Законно ли собирать данные с Hacker News?

Данные HN находятся в открытом доступе, и Y Combinator предоставляет официальный API специально для программного доступа. В сайта разрешён сбор только для контента для чтения (главная страница, страницы элементов, страницы пользователей), но указана просьба соблюдать 30-секундную задержку между обходами. Если соблюдать паузу, не трогать интерактивные эндпоинты (голосование, вход в систему) и действовать аккуратно, вы на безопасной стороне. Подробнее об этике скрейпинга — в нашем руководстве по .

Есть ли у Hacker News официальный API?

Да. по адресу hacker-news.firebaseio.com/v0/ бесплатен, не требует авторизации и даёт доступ к историям, комментариям, профилям пользователей и всем типам лент (top, new, best, ask, show, jobs). Он возвращает чистый JSON и не заявляет жёсткого лимита по частоте, хотя соблюдать разумную частоту запросов всегда стоит.

Как собирать комментарии Hacker News на Python?

Через Firebase API сначала получите item истории, чтобы достать её поле kids — массив ID комментариев первого уровня. Каждый комментарий сам является item со своим kids для ответов. Обходите дерево рекурсивно функцией, которая загружает каждый комментарий и его потомков. Полный код есть в разделе "Собираем комментарии (рекурсивный обход дерева)" выше. Альтернативно, эндпоинт /items/<id> в возвращает полное вложенное дерево комментариев за один запрос — это гораздо быстрее для историй с большим количеством обсуждений.

Можно ли собрать Hacker News без кода?

Да. работает как расширение Chrome: откройте HN, нажмите "AI Suggest Fields", и система автоматически определит столбцы вроде title, URL, score и author. Нажмите "Scrape" и сразу экспортируйте данные в Excel, Google Sheets, Airtable или Notion. Поддерживаются пагинация и даже переход на подстраницы для сбора комментариев. Без Python, без селекторов, без сопровождения.

Как получить исторические данные Hacker News?

Лучший инструмент для этого — . Используйте эндпоинт search_by_date с numericFilters=created_at_i>TIMESTAMP, чтобы фильтровать по диапазону дат. Можно искать по ключевым словам, фильтровать по типу истории и проходить до 500 страниц результатов. Для массового исторического анализа также доступны открытые датасеты в (полный архив), (28 миллионов записей) и (4 миллиона историй).

Узнать больше

Содержание

Попробуй Thunderbit

Собирай лиды и другие данные всего в 2 клика. На базе AI.

Получить Thunderbit Это бесплатно
Извлекай данные с помощью AI
Легко передавай данные в Google Sheets, Airtable или Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week