Como eu faço scraping do Hacker News com Python (2 métodos, código completo)

Última atualização em April 16, 2026

Há alguns meses, eu queria montar um resumo diário com as principais histórias do Hacker News para o time da Thunderbit. Minha primeira ideia foi simplesmente salvar o site nos favoritos e dar uma olhada nele toda manhã. Isso durou uns três dias, até eu perceber que estava gastando 20 minutos por dia só lendo manchetes e copiando links para uma planilha.

O Hacker News é uma das fontes mais ricas e concentradas de inteligência sobre tecnologia na internet — cerca de , aproximadamente 1.300 novas histórias enviadas por dia e algo em torno de 13.000 comentários gerados diariamente. Se você acompanha tendências emergentes de tecnologia, monitora sua marca, cria um funil de recrutamento a partir dos tópicos “Who’s Hiring” ou simplesmente quer ficar por dentro do que importa para o mundo dev, tentar acompanhar tudo isso manualmente é uma batalha perdida.

A boa notícia: fazer scraping do Hacker News com Python é surpreendentemente simples. Neste guia, vou te mostrar dois métodos completos — scraping de HTML com BeautifulSoup e a API oficial do HN Firebase — além de paginação, exportação de dados, padrões prontos para produção e um atalho sem código para quando Python parecer exagero.

Por que fazer scraping do Hacker News com Python?

O Hacker News não é apenas mais um agregador de links. É um feed curado pela comunidade, em que as histórias de tecnologia mais interessantes sobem para o topo por meio de votos e discussões ativas. O público é fortemente inclinado para profissionais de tecnologia (cerca de ), e a taxa de tráfego direto de 66% mostra que estamos falando de uma audiência fiel e habitual — não de visitantes ocasionais.

Veja por que tanta gente coleta dados do HN:

Caso de usoO que você obtém
Resumo diário de tecnologiaHistórias em destaque, pontuação e links entregues no e-mail ou no Slack
Monitoramento de marca/concorrentesAlertas quando sua empresa ou produto for mencionado
Análise de tendênciasAcompanhe quais tecnologias, linguagens ou temas estão ganhando força ao longo do tempo
RecrutamentoExtraia vagas, stacks e sinais salariais dos tópicos “Who’s Hiring”
Pesquisa de conteúdoEncontre temas com bom desempenho para escrever ou compartilhar
Análise de sentimentoMeça a opinião da comunidade sobre produtos, lançamentos ou mudanças no setor

Empresas que juntas valem mais de US$ 400 bilhões — Stripe, Dropbox, Airbnb — atribuem ao Hacker News parte importante do feedback inicial e dos primeiros usuários. Em abril de 2007, Drew Houston publicou a demo do Dropbox no HN, ela ficou em #1, e a lista de espera do beta saltou de 5.000 para 75.000 usuários em um único dia. Os dados do HN não são só interessantes — eles têm valor comercial.

Os dados são públicos, mas a estrutura do site torna a coleta manual cansativa. Automatizar com Python é a solução mais prática.

Duas formas de fazer scraping do Hacker News com Python: visão geral

Este guia cobre duas abordagens completas e executáveis:

  1. Scraping de HTML com requests + BeautifulSoup — baixa o HTML bruto de news.ycombinator.com e faz o parse para extrair os dados das histórias. É ótimo para aprender os fundamentos de scraping e capturar exatamente o que está na página.
  2. A API oficial do Hacker News Firebase — acessa endpoints JSON diretamente, sem precisar fazer parsing de HTML. É melhor para pipelines confiáveis, acesso a comentários e dados históricos.

Aqui vai uma comparação lado a lado para ajudar você a escolher o que faz mais sentido:

CritérioScraping de HTML (requests + BS4)API HN FirebaseThunderbit (sem código)
Complexidade de configuraçãoMédia (parsers de HTML)Baixa (endpoints JSON)Nenhuma (extensão Chrome em 2 cliques)
Atualidade dos dadosPágina inicial em tempo realTempo real (qualquer item por ID)Tempo real
Risco de limite de requisiçõesMédio (robots.txt pede atraso de 30 s)Baixo (oficial e generoso)Gerenciado pela Thunderbit
Acesso a comentáriosDifícil (HTML aninhado)Fácil (IDs recursivos)Recurso de scraping de subpáginas
Dados históricosLimitadosVia Algolia Search APIN/A
Melhor paraAprender fundamentos de scrapingPipelines confiáveisNão desenvolvedores, exportações rápidas

Os dois métodos incluem código Python completo e executável. E, se você só quiser os dados sem escrever nenhum código, eu também vou mostrar essa opção.

Antes de começar

  • Nível: Iniciante a intermediário
  • Tempo necessário: ~15–20 minutos por método
  • O que você vai precisar:
    • Python 3.11+ instalado
    • Um terminal ou editor de código
    • Navegador Chrome (se quiser inspecionar o HTML do HN ou testar a opção sem código)
    • (opcional, para o método sem código)

scrape-hacker-news-methods.webp

Configurando seu ambiente Python

Antes de mexer em qualquer dado do HN, vamos preparar o ambiente. Recomendo criar um ambiente virtual para manter as dependências do projeto organizadas.

1# Crie e ative um ambiente virtual
2python3 -m venv hn-scraper
3# macOS/Linux:
4source hn-scraper/bin/activate
5# Windows:
6hn-scraper\Scripts\activate
7# Instale os pacotes que vamos usar nos dois métodos
8pip install requests==2.33.1 beautifulsoup4==4.14.3 pandas==3.0.2 openpyxl==3.1.5

Para os padrões de produção mais à frente (cache, retries), você também vai querer:

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

Sem chaves de API especiais, sem tokens de autenticação. Os dados do HN são abertos.

Método 1: fazer scraping do Hacker News com Python usando BeautifulSoup

Essa é a abordagem clássica — baixar o HTML, fazer o parse e puxar os dados que você quer. É assim que a maioria das pessoas aprende web scraping, e o layout simples em tabela do HN faz dele um ótimo campo de treinamento.

Etapa 1: buscar a página inicial do Hacker News

Abra seu editor e crie um arquivo chamado scrape_hn_bs4.py. Aqui está o código inicial:

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")

Execute. Você deve ver Status: 200 e um tamanho de página em torno de 40.000 a 50.000 caracteres. Esse é o HTML bruto da página inicial do HN carregado na memória, pronto para ser analisado.

Etapa 2: entender a estrutura do HTML

O HN usa um layout baseado em tabela — nada de grid ou flex modernos. Cada história na página é composta por duas linhas <tr> principais:

  • A linha da história (<tr class="athing submission">): contém a posição, o título e o link
  • A linha de metadados (a próxima <tr>): contém pontos, autor, horário e contagem de comentários

Os seletores importantes:

  • span.titleline > a — título da história e URL
  • span.score — quantidade de votos (por exemplo, “118 points”)
  • a.hnuser — nome de usuário do autor
  • span.age — horário da publicação
  • O último <a> em .subtext com “comment” no texto — contagem de comentários

Se você clicar com o botão direito em qualquer título no Chrome e escolher “Inspecionar”, verá algo parecido com isto:

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

E a linha de metadados logo abaixo:

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>

Entender esses seletores é essencial — se o HN mudar o markup, você vai precisar atualizar isso. (Spoiler: o método da API evita esse problema completamente.)

Agora vem a parte prática. Vamos percorrer cada linha de história, pegar o título e o link da linha principal e, em seguida, coletar a pontuação da linha de metadados logo abaixo.

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    # Título e URL da linha da história
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    # Metadados da próxima linha irmã
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# Filtrar histórias com 50+ pontos, ordenadas por pontuação
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])

Algumas observações sobre o código:

  • O operador walrus (:=) funciona no Python 3.8+. Ele permite atribuir e verificar em uma única linha — útil para elementos opcionais como span.score, que podem não existir em todas as linhas (por exemplo, posts de vagas não têm pontuação).
  • O HN usa \xa0 (espaço sem quebra) entre o número e “comments”, então fazemos o split nesse caractere.
  • Histórias que apontam para outras páginas do HN (como posts “Ask HN”) terão URLs relativas começando com item?id=. Você pode querer acrescentar https://news.ycombinator.com/ nesses casos.

Etapa 4: executar e ver os resultados

Salve e rode:

1python scrape_hn_bs4.py

Você deve ver uma saída parecida com:

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 ...]

Essas são 30 histórias da página 1. Mas o HN tem centenas de histórias ativas a qualquer momento. Vamos falar de paginação numa seção mais adiante.

Método 2: fazer scraping do Hacker News com Python usando a API oficial

A API Firebase do HN é a forma oficialmente autorizada de acessar dados do Hacker News. Sem autenticação, sem chave de API, sem parsing de HTML. Você recebe respostas JSON limpas. Eu uso esse método para tudo o que precisa funcionar de forma confiável em produção.

Principais endpoints da API que você precisa conhecer

A URL base é https://hacker-news.firebaseio.com/v0/. Aqui estão os endpoints que importam:

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

Um item de história se parece com isto:

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}

O campo kids contém os IDs dos comentários filhos diretos. Cada comentário também é um item que pode ter seus próprios kids — é assim que a árvore de comentários é estruturada.

Etapa 1: buscar os IDs das principais histórias

Crie um arquivo chamado scrape_hn_api.py:

1import requests
2import time
3from pprint import pprint
4API_BASE = "https://hacker-news.firebaseio.com/v0"
5# Buscar IDs das principais histórias
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 IDs de histórias em uma única requisição — sem parsing, sem seletores, só um array JSON.

Etapa 2: buscar os detalhes de cada história por ID

Agora precisamos dos dados reais das histórias. É aqui que aparece o problema de escala: 500 histórias significam 500 chamadas individuais à API. Nos meus testes, cada requisição de item leva cerca de 1,2 segundo de forma sequencial. Para 500 histórias, isso dá algo em torno de 10 minutos.

Na maioria dos casos, você não precisa de todas as 500. Aqui vai um código para buscar as 30 primeiras:

1def fetch_story(story_id):
2    """Busca os detalhes de uma única história na API do HN."""
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# Ordenar por pontuação e mostrar as 10 primeiras
7top = sorted(stories, key=lambda x: x["score"], reverse=True)[:10]
8pprint(top)

O time.sleep(0.1) adiciona uma pequena pausa por cortesia. A Firebase API não informa um limite de requisições, mas bombardear qualquer API sem intervalos é má prática.

Etapa 3: fazer scraping dos comentários (percurso recursivo da árvore)

Aqui é onde a API realmente brilha em comparação com o scraping de HTML. Os comentários no HN são profundamente aninhados — respostas de respostas de respostas. Em HTML, isso significaria lidar com estruturas de tabela complexas e aninhadas. Com a API, cada comentário tem seu campo kids com os IDs dos filhos, e você simplesmente percorre a árvore de forma recursiva.

1def fetch_comments(item_id, depth=0, max_depth=3):
2    """Busca comentários recursivamente até 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# Exemplo: buscar comentários da história principal
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]:  # Primeiros 5 comentários de nível superior
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}...")

Essa abordagem recursiva é muito mais simples do que tentar interpretar threads de comentários aninhadas em HTML. Se você precisa da árvore completa de comentários, a API é o caminho certo.

Etapa 4: executar e ver os resultados

1python scrape_hn_api.py

Você verá os dados estruturados das histórias, seguidos por uma prévia hierárquica dos comentários. Os dados ficam mais limpos, o acesso aos comentários é trivial e não existe o risco de seu scraper quebrar porque o HN mudou o nome de uma classe CSS.

Indo além da página 1: paginação e dados históricos

A maioria dos tutoriais de scraping do HN para na página 1 — 30 histórias. Isso é suficiente para uma demo rápida, mas casos reais muitas vezes exigem mais profundidade.

Fazendo scraping de várias páginas com BeautifulSoup

A paginação do HN usa um padrão simples de URL: ?p=2, ?p=3 etc. Cada página retorna 30 histórias, e o site entrega até aproximadamente a página 20 (cerca de 600 histórias no total). Depois disso, as páginas ficam vazias.

1import time
2def scrape_hn_pages(num_pages=5):
3    """Faz scraping de várias páginas da seção inicial do 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"Página {page}: nenhuma história encontrada, encerrando.")
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"Página {page}: {len(story_rows)} histórias coletadas")
23        # Respeite o crawl-delay de 30 segundos do robots.txt
24        if page < num_pages:
25            time.sleep(30)
26    return all_stories
27stories = scrape_hn_pages(5)
28print(f"\nTotal de histórias coletadas: {len(stories)}")

Esse time.sleep(30) é importante. O do HN solicita explicitamente um atraso de 30 segundos entre crawls. Ignorar isso pode fazer você sofrer rate limit (HTTP 429) ou até bloqueio temporário. Cinco páginas com intervalos de 30 segundos levam cerca de 2,5 minutos — não é instantâneo, mas é respeitoso.

Para quem não quer lidar com código de paginação, a faz a paginação por clique e a rolagem infinita automaticamente. Ela clica no botão “More” no fim das páginas do HN sem nenhuma configuração.

Como acessar dados históricos do Hacker News com a API do Algolia

A Firebase API entrega dados atuais. Para análise histórica — “Quais foram as principais histórias sobre Python em 2023?” ou “Como a cobertura sobre IA mudou nos últimos 5 anos?” — você precisa da .

1import requests
2ALGOLIA_BASE = "https://hn.algolia.com/api/v1"
3> This paragraph contains content that cannot be parsed and has been skipped.
4# Exemplo: encontrar histórias sobre scraping em Python com 10+ pontos desde jan/2024
5results = search_hn(
6    query="python scraping",
7    tags="story",
8)
9print(f"Encontrados {results['nbHits']} resultados no total")
10for hit in results["hits"][:5]:
11    print(f"  [{hit.get('points', 0)} pts] {hit['title']}")

Para consultas com filtro de data, use numericFilters:

1import calendar, datetime
2# Histórias desde 1º de janeiro de 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.
6A API do Algolia é rápida (59 ms de processamento no servidor), não exige chave de API e suporta paginação de até 500 páginas. Para análise histórica em volume, é a melhor opção disponível.
7## Exportando os dados coletados do Hacker News para CSV, Excel e Google Sheets
8Todo tutorial de scraping do HN que eu vi termina com saída de `pprint()` no terminal. Isso é ótimo para depuração, mas, se você estiver montando um resumo diário ou fazendo análise de tendências, precisa colocar os dados em um arquivo. Veja como fazer isso.
9### Exportar para CSV com Python
10```python
11import csv
12def export_to_csv(stories, filename="hn_stories.csv"):
13    """Salva as histórias coletadas em um arquivo 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"Salvas {len(stories)} histórias em {filename}")
20export_to_csv(stories)

Exportar para Excel com Python

1import pandas as pd
2def export_to_excel(stories, filename="hn_stories.xlsx"):
3    """Salva as histórias coletadas em um arquivo Excel."""
4    df = pd.DataFrame(stories)
5    df.to_excel(filename, index=False, engine="openpyxl")
6    print(f"Salvas {len(stories)} histórias em {filename}")
7export_to_excel(stories)

Certifique-se de que o openpyxl esteja instalado — o pandas o usa como mecanismo para Excel. Se ele estiver faltando, você vai receber um ImportError.

Enviar para o Google Sheets (opcional)

Para fluxos automatizados, talvez você queira mandar os dados direto para o Google Sheets usando a biblioteca gspread. Isso exige configurar uma conta de serviço do Google Cloud (um processo único):

1import gspread
2gc = gspread.service_account(filename="service_account.json")
3sh = gc.open("HN Daily Digest")
4worksheet = sh.sheet1
5# Converter histórias em linhas
6header = list(stories[0].keys())
7rows = [list(s.values()) for s in stories]
8worksheet.clear()
9worksheet.update([header] + rows)
10print("Enviado para o Google Sheets")

A alternativa sem código para exportação

Se configurar contas de serviço e escrever código de exportação parece mais trabalho do que o próprio scraping, eu entendo. Na Thunderbit, criamos exportação de dados gratuita que permite enviar dados coletados diretamente para Excel, Google Sheets, Airtable ou Notion — sem código, sem credenciais, sem pipeline para manter. Para uma extração pontual, isso é realmente mais rápido. Falo mais sobre isso abaixo.

Tornando seu scraper pronto para produção: tratamento de erros, cache e agendamento

Se você vai rodar um scraper só por diversão, o código acima já resolve. Se pretende rodá-lo diariamente como parte de um fluxo, vai precisar de alguns elementos extras.

Tratamento de erros e lógica de retry

Redes falham. Servidores limitam requisições. Uma requisição ruim não deveria derrubar toda a coleta. Aqui vai uma função de retry com backoff exponencial:

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    """Busca uma URL com retries automáticos e backoff exponencial."""
6    response = requests.get(url, timeout=10)
7    response.raise_for_status()
8    return response
9# Uso:
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"Falhou após as tentativas: {e}")

A biblioteca tenacity cuida da lógica de retry de forma elegante. Ela tenta até 5 vezes com backoff exponencial com jitter — começando em 1 segundo e indo até 60 segundos. Isso lida bem com HTTP 429 (limite de requisições), 503 (serviço indisponível) e erros de rede temporários.

Cache de respostas para evitar recrawling

Durante o desenvolvimento, você vai executar o scraper várias vezes enquanto ajusta a lógica de parsing. Sem cache, cada execução volta a bater nos servidores do HN para buscar os mesmos dados. A biblioteca requests-cache resolve isso em duas linhas:

1import requests_cache
2requests_cache.install_cache("hn_cache", expire_after=3600)  # Cache por 1 hora

Depois de adicionar essas linhas no topo do script, todas as chamadas requests.get() passam a ser armazenadas automaticamente em um banco SQLite local. Rode o script 10 vezes em uma hora, e só a primeira execução realmente fará requisições na rede. Essa é uma ferramenta que , e com bons motivos.

Separar coleta de parsing

Um padrão que quem já faz scraping há tempo adora: primeiro baixe os dados brutos, depois faça o parse. Assim, se sua lógica de parsing tiver um bug, você corrige e reprocessa sem precisar baixar tudo de novo.

1import os, json
2def crawl_and_save(story_ids, output_dir="raw_data"):
3    """Busca os dados das histórias e salva o JSON bruto em disco."""
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  # Ignora itens já baixados
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.
13Essa abordagem em duas etapas é especialmente útil quando você está coletando centenas de itens e quer iterar rápido sobre a forma de processar os dados.
14### Automatizando seu scraper em um cronograma
15Para um resumo diário do HN, você precisa que o scraper rode automaticamente. Duas opções comuns:
16**Opção 1: cron (Linux/Mac)**
17```bash
18# Executar todo dia às 8:30 UTC
1930 8 * * * /usr/bin/python3 /home/user/scrape_hn.py >> /home/user/scrape.log 2>&1

Opção 2: GitHub Actions (gratuito, sem servidor)

1name: Scrape Hacker News
2on:
3  schedule:
4    - cron: '30 8 * * *'  # Diário às 8:30 UTC
5  workflow_dispatch:        # Botão para execução manual
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 "Atualiza dados do HN $(date -u +%Y-%m-%dT%H:%M:%SZ)"
21          git push

Alguns pontos de atenção com o agendamento no GitHub Actions: todos os horários do cron são em UTC, atrasos de 15 a 60 minutos são comuns (prefira horários fora da hora cheia, como :30 em vez de :00), e o GitHub pode desativar workflows agendados em repositórios sem atividade por 60 dias. Sempre inclua workflow_dispatch para poder disparar manualmente durante os testes.

Se você quiser algo mais simples, o recurso Scheduled Scraper da Thunderbit permite descrever o agendamento em linguagem natural — algo como “extrair todas as manhãs às 8h” — sem servidor e sem configuração de cron.

Quando Python é exagero: a forma sem código de fazer scraping do Hacker News

Vou ser sincero aqui, mesmo sendo fã de Python e mesmo com meu time construindo ferramentas para desenvolvedores. Se você só precisa das 100 principais histórias do HN de hoje em uma planilha — agora, uma única vez — escrever, depurar e executar um script Python é uma sobrecarga desnecessária. Só a configuração (ambiente virtual, instalação de pacotes, descoberta de seletores) leva mais tempo do que a própria coleta de dados.

É aí que a entra. O fluxo é este:

  1. Abra news.ycombinator.com no Chrome
  2. Clique no ícone da extensão Thunderbit e depois em “AI Suggest Fields”
  3. A IA lê a página e propõe colunas: Título, URL, Pontuação, Autor, Contagem de comentários, Hora da publicação
  4. Ajuste os campos se quiser (renomeie, remova ou adicione campos personalizados — você pode até incluir um prompt de IA como “Classificar como IA/DevTools/Web/Outro”)
  5. Clique em “Scrape” — os dados aparecem em uma tabela estruturada
  6. Exporte para Excel, Google Sheets, Airtable ou Notion

Dois cliques para chegar aos dados estruturados. Sem seletores, sem código, sem manutenção.

Uma vantagem real aqui: a IA da Thunderbit se adapta automaticamente a mudanças de layout. Scrapers tradicionais baseados em seletores CSS quebram quando um site muda o markup — e, embora o HTML do HN seja relativamente estável, ele já mudou (a classe class="athing submission" foi atualizada, e span.titleline substituiu o antigo a.storylink). Um scraper com IA lê a página de novo a cada execução, então não depende de nomes de classes.

python-vs-thunderbit-comparison.webp

A Thunderbit também cuida da paginação (clicando automaticamente no botão “More” do HN) e do scraping de subpáginas (visitando a página de comentários de cada história para coletar a discussão). Para o caso de uso de , isso equivale ao código recursivo da API no Método 2 — mas sem escrever uma linha sequer.

As diferenças são simples: Python é a escolha certa quando você precisa de lógica personalizada, transformações complexas de dados, pipelines automatizados em cronograma ou está aprendendo a programar. A Thunderbit é a escolha certa quando você precisa dos dados rápido, não quer manter código ou não é desenvolvedor. Escolha a ferramenta que combina com a sua situação.

Python vs. API vs. sem código: qual método você deve escolher?

Aqui está o framework completo de decisão:

CritérioBeautifulSoup (HTML)API FirebaseAPI AlgoliaThunderbit (sem código)
Nível técnico necessárioPython intermediárioPython iniciantePython inicianteNenhum
Tempo de configuração10–15 min5–10 min5–10 min2 min
Esforço de manutençãoMédio (seletores quebram)Baixo (JSON estável)Baixo (JSON estável)Nenhum
Profundidade dos dadosApenas página inicialQualquer item, usuáriosBusca + históricoPágina inicial + subpáginas
ComentáriosDifícilFácil (recursivo)Fácil (árvore aninhada)Scraping de subpáginas
Dados históricosNãoNãoSim (arquivo completo)Não
Opções de exportaçãoVocê mesmo programaVocê mesmo programaVocê mesmo programaIntegrado (Excel, Sheets etc.)
Agendamentocron / GitHub Actionscron / GitHub Actionscron / GitHub ActionsAgendador integrado
Melhor paraAprender scrapingPipelines confiáveisPesquisa e análiseExtrações rápidas

Se você está aprendendo Python ou construindo algo personalizado, vá de Método 1 ou 2. Se precisa de análise histórica, adicione a API Algolia. Se só quer os dados sem escrever código, .

Conclusão e principais aprendizados

Agora você tem no seu kit:

  • Dois métodos completos em Python para fazer scraping do Hacker News — BeautifulSoup para parsing de HTML e a API Firebase para dados JSON limpos
  • Técnicas de paginação para ir além da página 1, incluindo a API Algolia para dados históricos que remontam a 2007
  • Código de exportação para CSV, Excel e Google Sheets — porque dados parados no terminal não ajudam ninguém do seu time
  • Padrões de produção — retry, cache, separação entre coleta e parse e automação agendada com cron ou GitHub Actions
  • Uma alternativa sem código para quando Python é mais ferramenta do que você precisa

Minha recomendação: comece pela API Firebase (Método 2) para a maioria dos casos de uso. Ela é mais limpa, mais confiável e dá acesso aos comentários sem o transtorno de fazer parse de HTML aninhado. Adicione a API Algolia quando precisar de dados históricos. E mantenha nos favoritos para quando você só precisar de uma planilha rápida e não quiser criar um projeto Python inteiro.

Se quiser ir mais fundo, tente coletar comentários do HN para , monte um pipeline diário com GitHub Actions ou explore a API Algolia para acompanhar como as tendências tecnológicas mudaram ao longo da última década.

Experimente a Thunderbit para fazer scraping rápido do Hacker News

FAQs

Os dados do HN são públicos, e o Y Combinator fornece uma API oficial justamente para acesso programático. O do site permite a coleta de conteúdo apenas leitura (página inicial, páginas de itens e páginas de usuários), mas solicita um atraso de 30 segundos entre crawls. Respeite esse intervalo, não faça scraping de endpoints interativos (votação, login) e você estará em boa posição. Para saber mais sobre ética em scraping, veja nosso guia sobre .

O Hacker News tem uma API oficial?

Sim. A em hacker-news.firebaseio.com/v0/ é gratuita, não exige autenticação e dá acesso a histórias, comentários, perfis de usuário e todos os tipos de feed (top, new, best, ask, show, jobs). Ela retorna JSON limpo e não informa limite oficial de requisições, embora seja sempre recomendável manter uma frequência educada.

Como faço scraping dos comentários do Hacker News com Python?

Usando a API Firebase, busque um item de história para obter o campo kids (um array com os IDs dos comentários de nível superior). Cada comentário também é um item com seu próprio campo kids para as respostas. Percorra a árvore recursivamente com uma função que busca cada comentário e seus filhos. Veja a seção “Fazer scraping dos comentários (percurso recursivo da árvore)” acima para o código completo. Como alternativa, o endpoint /items/<id> da retorna a árvore completa de comentários aninhados em uma única requisição — muito mais rápido para histórias com muitos comentários.

Posso fazer scraping do Hacker News sem escrever código?

Sim. O funciona como uma extensão do Chrome — abra o HN, clique em “AI Suggest Fields” e ele identifica automaticamente colunas como título, URL, pontuação e autor. Clique em “Scrape” e exporte diretamente para Excel, Google Sheets, Airtable ou Notion. Ele lida com paginação e ainda pode visitar subpáginas para coletar dados de comentários. Sem Python, sem seletores, sem manutenção.

Como consigo dados históricos do Hacker News?

A é a melhor ferramenta para isso. Use o endpoint search_by_date com numericFilters=created_at_i>TIMESTAMP para filtrar por intervalo de datas. Você pode pesquisar por palavra-chave, filtrar por tipo de história e paginar até 500 páginas de resultados. Para análise histórica em grande escala, também existem conjuntos de dados públicos no (arquivo completo), (28 milhões de registros) e (4 milhões de histórias).

Saiba mais

Shuai Guan
Shuai Guan
Co-founder/CEO @ Thunderbit. Passionate about cross section of AI and Automation. He's a big advocate of automation and loves making it more accessible to everyone. Beyond tech, he channels his creativity through a passion for photography, capturing stories one picture at a time.
Sumário

Experimente a Thunderbit

Extraia leads e outros dados em apenas 2 cliques. Com tecnologia de IA.

Obter Thunderbit É grátis
Extraia dados usando IA
Transfira dados facilmente para Google Sheets, Airtable ou Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week