Criando Feeds RSS Para Sites Que Não os Fornecem
tech rss python bash shell shell scriptQuem usa um agregador RSS como “porta de entrada” para a web hoje em dia sofre com vários sites que deveriam publicar um feed, mas não o fazem.
Resta buscar/escrever ferramentas que usem APIs ou fazer scraping para gerar os feeds.
Muitas dessas ferramentas, como a RSS-Bridge, parecem interessantes, mas nunca parei para testá-las porque elas sempre me pareceram complicadas demais. A RSS-Bridge, por exemplo, precisa de um servidor com PHP.
Uma ferramenta de linha de comando, fácil de instalar, que eu pudesse agendar a execução via cron
, que recebesse as opções em texto e “jogasse” o resultado como texto na saída padrão, seria minha ferramenta ideal.
Nunca tinha encontrado uma ferramenta assim, até recentemente. Ela chama-se newslinkrss. Citando o README, “ele funciona como um crawler ou scraper de propósito específico”.
Acho que o grande “pulo do gato” dessa ferramenta é servir como uma espécie de framework para criação de feeds RSS. Você só precisa entrar com o conhecimento específico sobre a página para a qual você está tentando criar um feed.
Opções para capturar/filtrar a URL de cada item do feed (o conteúdo de <link>
), o corpo de cada item (o conteúdo de <description>
), a data de cada item (o conteúdo de <pubDate>
), o título do feed… Estão todas presentes.
Fica mais simples de entender com um exemplo: criarei um feed RSS para as cervejas em que dei check-in no Untappd. O ponto de partida é sempre a URL da página que lista os links para o que serão os <item>
s individuais do feed. Essa URL é o único parâmetro posicional que o comando recebe.
Num blog, seria a URL da página com a lista dos posts. Num site de notícias, seria a URL da página principal de uma editoria qualquer. Nesse exemplo, é a URL da página do meu perfil no Untappd. Ela contém uma timeline com as cervejas abaixo de Guilherme’s Recent Activity.

Meu perfil no Untappd.
$ newslinkrss 'https://untappd.com/user/gmgall' -o /tmp/feed.xml
Estou usando a opção -o
para gravar o feed resultante num arquivo em /tmp/feed.xml
. O comportamento default é imprimir na saída padrão. Enquanto estou criando o feed, gosto de abri-lo com o Firefox para ter uma visualização melhor da estrutura.

A estrutura do feed sendo mostrada pelo Firefox.
Analisando o que temos até aqui, percebemos que o comando está generalista demais. Todo link virou um item no feed, até aqueles do topo da página (“Blog”, “Top Rated”, “Help”). Precisamos pegar só os links para os check-ins.
Vamos inspecionar a página do perfil para descobrirmos que padrão seguem os links para os check-ins. Usando a opção Selecionar um elemento da página (Ctrl+Shift+C) e colocando o cursor do mouse sobre os links de texto “View Detailed Check-in”, percebemos que o padrão é /user/gmgall/checkin/
seguido por um número.

Usando DevTools para descobrir o padrão dos links que apontam para a página individual de cada check-in.
A opção que usamos para capturarmos apenas os links que casam com determinada regex é -p
.
$ newslinkrss \
-p '.+/user/gmgall/checkin/[0-9]+' \
'https://untappd.com/user/gmgall' \
-o /tmp/feed.xml
Se abrirmos o feed que temos nesse ponto, veremos que cada item é um check-in. Outros links no perfil não viraram <item>
s no feed. Exemplo de um dos itens:
<item>
<title>Sat, 01 Apr 2023 04:26:44 +0000</title>
<link>https://untappd.com/user/gmgall/checkin/1260790060</link>
<description>Sat, 01 Apr 2023 04:26:44 +0000</description>
<guid isPermaLink="true">https://untappd.com/user/gmgall/checkin/1260790060</guid>
</item>
Os links estão corretos, mas o título poderia ser melhor. O conteúdo de <description>
também. Vamos usar a opção --follow
para tentarmos capturar mais informações por item.
$ newslinkrss \
-p '.+/user/gmgall/checkin/[0-9]+' \
--follow \
'https://untappd.com/user/gmgall' \
-o /tmp/feed.xml
Agora cada item está como o abaixo:
<item>
<title>Guilherme is drinking a Torobayo by Compañia Cervecera Kunstmann on Untappd</title>
<link>https://untappd.com/user/gmgall/checkin/1260790060</link>
<description>Guilherme is drinking a Torobayo by Compañia Cervecera Kunstmann on Untappd | UntappdLink text: Sat, 01 Apr 2023 04:26:44 +0000</description>
<author>The Untappd Team</author>
<guid isPermaLink="true">https://untappd.com/user/gmgall/checkin/1260790060</guid>
</item>
Melhorou bastante, mas tem uma melhora óbvia: capturar a data. A opção --follow
nos dá a capacidade de capturar a data a partir da página de cada item individual com opções específicas para isso.
Vamos usar o inspetor na página de um check-in individual para vermos onde podemos pegar a data.

Inspecionando a página de um check-in no Untappd.
A data/hora do check-in aparece num parágrafo (elemento p
) com a classe time
. Podemos capturá-la via um seletor CSS com a opção --date-from-csss
(date from CSS selector).
Vamos também usar a opção --log DEBUG
para vermos exatamente o que está sendo capturado como data.
$ newslinkrss \
-p '.+/user/gmgall/checkin/[0-9]+' \
--follow \
--date-from-csss '.time' \
--log DEBUG \
'https://untappd.com/user/gmgall' \
-o /tmp/feed.xml
A opção --log DEBUG
vai imprimir linhas como a abaixo para cada item:
INFO:__main__:Following URL https://untappd.com/user/gmgall/checkin/1260790060
DEBUG:__main__:date-from-csss found candidate text: 'Sat, 01 Apr 2023 04:26:44 +0000'
DEBUG:__main__:date regex matched: src=Sat, 01 Apr 2023 04:26:44 +0000, rx=(.+), result=Sat, 01 Apr 2023 04:26:44 +0000
DEBUG:__main__:Found date from CSS Selector 2023-04-01 04:26:44+00:00
Nesse caso específico, já temos uma data em formato utilizável, mas raramente esse é o caso. Use --log
quando for criar feeds para páginas com formatos mais complicados.
Vamos ver como está cada item no feed agora:
<item>
<title>Guilherme is drinking a Torobayo by Compañia Cervecera Kunstmann on Untappd</title>
<link>https://untappd.com/user/gmgall/checkin/1260790060</link>
<description>Guilherme is drinking a Torobayo by Compañia Cervecera Kunstmann on Untappd | UntappdLink text: Sat, 01 Apr 2023 04:26:44 +0000</description>
<author>The Untappd Team</author>
<guid isPermaLink="true">https://untappd.com/user/gmgall/checkin/1260790060</guid>
<pubDate>Sat, 01 Apr 2023 04:26:44 GMT</pubDate>
</item>
Nesse ponto, temos as datas de cada item (<pubDate>
agora está presente).
Vamos melhorar o título de cada item. A parte inicial (Guilherme is drinking a
) e a final (on Untappd
) são redundantes. A opção --title-regex
nos permite filtrar os títulos dos itens. Ela recebe uma regex com um grupo e o que casar dentro desse grupo se torna o novo título.
$ newslinkrss \
-p '.+/user/gmgall/checkin/[0-9]+' \
--follow \
--date-from-csss '.time' \
--log DEBUG \
--title-regex 'Guilherme is drinking a (.+) on Untappd' \
'https://untappd.com/user/gmgall' \
-o /tmp/feed.xml
Cada item agora tem um título melhor:
<item>
<title>Torobayo by Compañia Cervecera Kunstmann</title>
<link>https://untappd.com/user/gmgall/checkin/1260790060</link>
<description>Guilherme is drinking a Torobayo by Compañia Cervecera Kunstmann on Untappd | UntappdLink text: Sat, 01 Apr 2023 04:26:44 +0000</description>
<author>The Untappd Team</author>
<guid isPermaLink="true">https://untappd.com/user/gmgall/checkin/1260790060</guid>
<pubDate>Sat, 01 Apr 2023 04:26:44 GMT</pubDate>
</item>
Precisamos agora de um corpo melhor em cada item. Atualmente em <description>
temos apenas um texto com nome da cerveja e data/hora do check-in.
Vamos usar --with-body
para incluirmos um corpo e --body-csss
para filtrarmos o que fará parte do corpo por meio de um seletor CSS. Usando apenas --with-body
, tudo entre <body>
e </body>
será incluído no corpo de cada item do feed. Pode ser esse o comportamento desejado para páginas mais simples, mas não é o caso do Untappd.
Inspecionando a página de cada check-in, descobrimos que o card com as informações do check-in é uma div
com as classes checkin-info
e pad-it
. Podemos selecioná-la com o seletor .checkin-info.pad-it
.
$ newslinkrss \
-p '.+/user/gmgall/checkin/[0-9]+' \
--follow \
--date-from-csss '.time' \
--log DEBUG \
--title-regex 'Guilherme is drinking a (.+) on Untappd' \
--with-body \
--body-csss '.checkin-info.pad-it' \
'https://untappd.com/user/gmgall' \
-o /tmp/feed.xml
Se visualizarmos esse feed num agregador, temos um resultado bem satisfatório:

Agregador QuiteRSS mostrando o feed que acabamos de criar nesse post.
Com o comando que gera o feed pronto, podemos remover a opção --log
. Para assinarmos o feed criado podemos agendar a execução periódica do newslinkrss
via cron
e assinarmos o feed resultante ou então indicarmos no nosso agregador RSS que a origem é um comando.
Como você tem lidado com sites que não oferecem feeds? Conhece alguma ferramenta parecida com o newslinkrss
? Adoraria ouvir sobre. Faça contato se quiser conversar sobre isso.