Recuperando notícias da Web com um script Python

4 de Novembro de 2009, por Desconhecido - 22 comentários

 

Eu estava planejando estudar um pouco de natural language processing, information retrieval e lingüística computacional, um assunto que eu sempre achei muito promissor e interessante. Há um pacote para Python chamado Natural Language Toolkit, com várias ferramentas supimpas e até alguns corpora de texto em português. Mas como eu sou um cara chato eu quero montar o meu próprio corpus de texto me baseando talvez em buscas específicas e poder ver como os resultados dos algoritmos variam mudando as fontes e os assuntos. 

A minha primeira tentativa bem sucedida foi tentar baixar em grande quantidade artigos da Folha de São Paulo para o meu computador. Isso me serviu para aprender a usar algumas boas bibliotecas Python que eu não conhecia: o BeautifulSoup, o feedparser e o pacote de expressões regulares.

Neste post eu queria descrever um pouco dessas bibliotecas e um pouco dos problemas de se conseguir informação desse tipo na internet - informação que a princípio está lá, é "acessível" e "pode ser usada". 

O primeiro problema é legal: eu provavelmente não posso usar esse corpus de notícias que eu baixei. Sinceramente estou pouco ligando - na minha cabeça se um texto está na web é como se estivesse jogado no meio da rua, eu posso pegar e usá-lo para o que eu quiser desde que eu não tente ganhar dinheiro vendendo o texto (posso vender o livro que contém o texto se eu quiser) sem autorização do autor.

Superado esse problema vamos aos problemas técnicos de acessar o texto:

  • A forma mais fácil de obter uma seqüencia de textos de notícia é usar um RSS, entretanto é praxe dos RSS de jornais e revistas não colocar o texto todo no feed mas apenas um sumário. Então a utilidade do RSS é apenas fornecer o link para  a notícia e eu tenho que baixar a notícia no site mesmo. Além disso o feed apenas contém as 10 ou 15 últimas entradas e não um registro histórico completo então preciso de alguma forma de acessar uma lista dos feeds dos últimos anos. 
  • Os sites de jornal são bonitos, cheios de barras, colunas, tabelas e propaganda. Isso é muito legal, mas quando você quer pegar apenas o texto da notícia é um saco. Seria muito fácil se os programadores que fizeram o site fossem muuuuito legais e marcassem direitinho o html, mas não é assim.

 

Então o roadmap é: (1) aprender a parsear um feed RSS usando um script, (2) fazer um programa que olhe um html e consiga extrair a notícia e (3) encontrar um histórico do RSS que eu quero baixar. Após muita navegação na web eu consegui resolver os três problemas usando ferramentas muito legais e simples de usar.

O problema (1) é resolvido usando o Universal Feedparser, uma biblioteca para parsear RSS automágicamente. A interface é beeeem intuitiva. Vamos a um exemplo simples com o feed da Folha.

Posso então fazer:

[code=py]

import feedparser
url_feed = "http%3A//feeds.folha.uol.com.br/folha/emcimadahora/rss091.xml"

feed = feedparser.parse(url_feed)
for post in feed.entries:
    print post.title, post.link

[/code]

Esse código vai imprimir os títulos e links de todas as notícia. O que está acontecendo é que a função feedparser.parse simplesmente olha para o XML e retorna o seu conteúdo em um objeto do tipo dict:

[code=py]

>>> print feed.keys()
['feed', 'status', 'updated', 'version', 'encoding', 'bozo', 'headers', 'etag', 'href', 'namespaces', 'entries']

[/code]

O problema número (3) (já volto para o 2) acabou sendo resolvido depois de hoooooras de busca na web. Eu sabia que devia haver solução, uma vez que o google reader é capaz de mostrar feeds antigos. Encontrei, finalmente, esse post no blog de dicas sobre o Google. O Google Reader não apenas é um leitor de RSS, mas ele também salva o histórico de todo feed que alguém já leu e esse histórico pode ser acessado em um feed no endereço:

http://www.google.com/reader/atom/feed/FEED_URL?r=n&n=NUMBER_OF_ITEMS

Onde FEED_URL deve ser substituido pela (dã) URL do feed que te interessa e NUMBER_OF_ITEMS é o número de itens que você quer recuperar. 

As duas limitações são: o número máximo de itens é 5000 (eu gostaria de ter muito mais, mas por enquanto é o que dá pra fazer) e você deve estar logado no sistema de login do Google para conseguir fazer isso. 

Isso é um saco... eu não sabia logar no Google através de um script e estava quase desistindo quando achei essa pergunta no StackOverflow (o MELHOR site para resolver dúvidas de programação de qualquer espécie).

A solução é simular um cookie na hora de acessar a página do Google Reader. A biblioteca urllib2 (que está na biblioteca padrão do Python) consegue fazer isso. Aí embaixo vai uma função para produzir um cookie para acessar qualquer página do Google:

[code=py]
import urllib
import urllib2

def getGoogleSID(user,passwd):
    # Authenticate to obtain SID
    auth_url = 'https%3A//www.google.com/accounts/ClientLogin'

    auth_req_data = urllib.urlencode({'Email': user, 'Passwd': passwd})
    auth_req = urllib2.Request(auth_url, data=auth_req_data)
    auth_resp = urllib2.urlopen(auth_req)
    auth_resp_content = auth_resp.read()
    auth_resp_dict = dict(x.split('=') for x in auth_resp_content.split('\n') if x)
    SID = auth_resp_dict["SID"]
    header = {}
    header['Cookie'] = 'Name=SID;SID=%s;Domain=.google.com;Path=/;Expires=160000000000' % SID    

    return header

def retrieveGooglePage(user,passwd, url):
    header = getGoogleSID(user,passwd)
    request = urllib2.Request(url, None, header)
    openurl= urllib2.urlopen(reader_req)
    text = reader_resp.read()
    return text

[/code]

A função getGoogleSID gera o cookie adequado que é depois usado na função retrieveGooglePage, que retorna todo o conteúdo de uma página do google com com um certo url como se você estivesse logado como o usuário fornecido. Essa função pode ser usada para obter o feed que eu me referi acima.

Então o que pode ser feito é: obtém-se o feed das últimas 5000 notícias e desse feed se obtem os links para as notícias no site da Folha. Agora é necessário parsear o html do site para obter o texto. Aí é que entra a biblioteca BeautifulSoup. Essa biblioteca é um parser de html muito bem feito e fácil de usar.

Uma página em html parseada no BeautifulSoup vira uma estrutura de dados (uma árvore) adequada para extrair conteúdo facilmente. Para dar um exemplo vou colocar abaixo uma  função que extrai a data da notícia. 

Por sorte o programador da página foi suficientemente bonzinho para marcar no html onde está a data da notícia. Aí vai um trecho do html de uma notícia:

[code=html]

<div id="articleDate">