sexta-feira, 27 de fevereiro de 2015

Tutorial Scrapy

Fala pessoal, nesse post vou tentar repassar um pouco do que aprendi estudando Scrapy (Python) nos últimos dias.

O post vai descrever um spider básico que lista em um JSON todos os tópicos criados nas duas primeiras páginas do site guj.com.br.

Ambiente:

- Ubuntu 14.04
- Sublime text

Ferramentas utilizadas:
- Scrapy
- Python
- virtualenv


# Instalando e criando ambiente virutalenv

Para quem não conhece, virtualenv é uma ferramenta que isola seu ambiente. Muito útil para quem trabalha com mais de um projeto na mesma máquina ou para resolver problemas de permissões.

* Instalando virtualenv
$sudo pip install virtualenv

* Criando um novo ambiente
$virtualenv NomeDoAmbiente

* Ativando ambiente
$source ./NomeDoAmbiente/bin/activate




# Instalando scrapy no ambiente virtualenv

$sudo apt-get install libxml2-dev libxslt-dev

$sudo apt-get install python-lxml

$pip install scrapy

* Verificando instalação do scrapy, o comando abaixo deve exibir o caminho para o seu virtualenv
$which scrapy

Caso o comando não exiba o scrapy do virtualenv, você pode forçar a execução do scrapy apontando para bin/scrapy

# Criando novo projeto com scrapy
$scrapy startproject nomedoprojeto




# Criando spider com template basico
$scrapy genspider java guj.com.br


# Adicionando alguns parâmetros ao arquivo de settins.py

#para nao sobre carregar o site

DOWNLOAD_DELAY = 5

# evitar looping de recursividade

REDIRECT_MAX_TIMES = 5

#para evitar acesso remoto

TELNETCONSOLE_ENABLED = False

#definindo os pipelines

ITEM_PIPELINES = {

    'guj.pipelines.GujPipeline': 300,

    'guj.pipelines.JsonWithEncodingPipeline': 800

}

# Abaixo vamos alterar a classe de parser chamada pelo scrapy para extrair título dos posts do Guj

# -*- coding: utf-8 -*-

import scrapy

from guj.items import GujItem

#from scrapy.contrib.spiders import CrawlSpider, Rule

#from scrapy.contrib.linkextractors import LinkExtractor



class JavaSpider(scrapy.Spider):

    name = "java"

    allowed_domains = ["guj.com.br"]

    #navega pelas duas primeiras páginas do guj

    start_urls = ['http://www.guj.com.br/?p=%s' % page for page in xrange(0,2)]

    #rules = (Rule(LinkExtractor(allow=('/?p=', )), callback='parse_item'),)

   





    def parse(self, response):

        self.log('url: %s' % response.url)

        for a in response.xpath('/html/body/div/section/ol/li/div/div/h3/a/text()'):

            item = GujItem()

            item['title'] = a.extract()

            yield item

# Agora vamos definir os pipelines de tratamento após a captura do Item

# -*- coding: utf-8 -*-



# Define your item pipelines here

#

# Don't forget to add your pipeline to the ITEM_PIPELINES setting

# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html



import json

import codecs



class GujPipeline(object):

    def process_item(self, item, spider):

        #remove os caracteres \n e \t

        item['title'] = item['title'].replace('\n','')

        item['title'] = item['title'].replace('\t','')

        return item





class JsonWithEncodingPipeline(object):



    def __init__(self):

        self.file = codecs.open('scraped_data_utf8.json', 'w', encoding='utf-8')



    #pipeline para codificar o JSON extraido do scrapy para UTF-8, pois o scrapy cria

    #o json no padrão unicode

    def process_item(self, item, spider):

        line = json.dumps(dict(item), ensure_ascii=False) + "\n"

        self.file.write(line)

        return item



    def spider_closed(self, spider):

        self.file.close()



# Rodando nosso scrapy passando o parâmetro -o e o nome do json de destino. O comando deve ser executado na pasta do arquivo scrapy.cfg:
$scrapy crawl java -o items.json


GitHub com o source completo do projeto


2 comentários:

  1. Olá!
    Legal o tutorial, bela iniciativa! :)
    Um detalhezinho: o arquivo de configuração é settings.py (Python), e não XML. ;)

    Acredito que você possa não precisar do pipeline se mudar um pouquinho a expressão XPath, tipo:

    response.xpath('normalize-whitespace(//section//h3/a)')

    Valeu, happy scraping! ;)

    ResponderExcluir
    Respostas
    1. Muito obrigado pelas dicas e por comentar Elias :)

      Abraço!

      Excluir