/ python3-programming

Python3 e mineração de dados na web

Pois é, vamos falar um pouco de uma linguagem de programação que parece muito com Nim, porém com uma verbrosidade e sintaxe completamente diferentes, além do próprio sistema de execução, vamos tratar aqui assuntos de web scraping e web crawling.

Em primeiro momento é interessante você entender de fato as diferênças entre essas partes da extração de informações da internet. Quando falamos em scraping, temos uma abordagem direta e de nicho, totalmente oposto a crawling, onde temos uma approach mais genérica das estruturas de dados e data sources da indexação de informações.

Baixando uma página

Como de padrão aqui no blog, vamos começar caminhando devagar para depois ir avançando em tópicos mais complexos que derivam da mesma ideia, por enquanto, vamos nos cercar somente em scraping, escrevendo um script em Py3K que permite baixar o conteúdo de uma página web em sua maquina.

Vamos consumir o módulo urllib para começar a brincar, em seu editor de textos, crie um novo arquivo com extensão .py e vamos começar a brincar. Para começo de conversa, vamos definir uma função responável por baixar uma página:

def download(target):
    print('Baixando:', target)
    try:
        source = urllib.request.urlopen(target).read()
    except (URLError, HTTPError, ContentTooShortError) as e:
        print('Erro na parada:', e.reason)
        html = None
    return source

Lembre-se de usar o import corretamente, perceba que consumimos urllib.request.

Bom, nesse snipet de função extramamente simples, já podemos brincar com ele, você pode importar seu arquivo em um terminal interativo do Python, eu particularmente prefiro o ipython3, e brincar com a função:

No meu caso, criei um arquivo de exemplo, mas fica a sua opção viu!

Execução do script

Otimizando o download

Não tem muito sentido em fazer algo que não persista em finalizar uma ação necessária para conclusão de uma tarefa, por esse motivo, ainda mais no campo de sraping é interessante que você tente algumas vezes o acesso em determinado alvo, isso acontece por politicas de acesso mal projetadas ou por pura sorte.

def download(target, num_retries=2):
    print('Baixando:', target)
    try:
        source = urllib.request.urlopen(target).read()
    except (URLError, HTTPError, ContentTooShortError) as e:
        print('Erro na parada:', e.reason)
        html = None
        if hassattr(e, 'code') and 500 <= e.code < 600:
            return download(target, num_retries - 1)
    return source

Claro que temos uma lógica para tentar indexar a página novamente, de nada adianta efetuar dequisições para códigos de respostas fixos, que por serem imutáveis só vai consumir tempo de execução, sem gerar nenhum resultado útil para você.

A importância de alguns headers

É importante frisar que muitos serviços bloqueam por padrão (403) o agente de usuário do módulo, por esse motivo, você sempre deve procurar parametrizar nele, a parametrização do seu devido header:

def download(target, user_agent='wswp', num_retries=2):
    print('Baixando:', target)
    request = urllib.request.Request(target)
    request.add_header('User-Agent', user_agent)
    try:
        source = urllib.request.urlopen(target).read()
    except (URLError, HTTPError, ContentTooShortError) as e:
        print('Erro na parada:', e.reason)
        html = None
        if hassattr(e, 'code') and 500 <= e.code < 600:
            return download(target, num_retries - 1)
    return source

E agora sim, temos um indexador de conteúdos válido, que realmente funciona. Vou terminando por aqui essa postagem, em breve retornarei falando mais sobre o assunto, especificamente na serialização de robots.txt e sitemaps.