Explorando Scrapy além do tutorial

Explorando Scrapy além do tutorial

Slides da minha palestra na Python Brasil 2014 (com anotações para ler online =)

Seguem alguns links úteis:

Tutorial do Scrapy no PythonHelp: http://pythonhelp.wordpress.com/2014/08/05/web-scraping-com-scrapy-primeiros-passos/
Versão em inglês disponível em: http://hopefulramble.blogspot.com.br/2014/08/web-scraping-with-scrapy-first-steps_30.html

Tutorial de XPath (em inglês): http://www.zvon.org/comp/r/tut-XPath_1.html

Dicas de XPath (em inglês): http://blog.scrapinghub.com/2014/07/17/xpath-tips-from-the-web-scraping-trenches/

Ferramenta para converter código JS em XML, para extrair dados do JavaScript com XPath: https://github.com/redapple/js2xml (instale com: pip install js2xml)

Documentação do Scrapy (em inglês): http://scrapy.readthedocs.org/en/latest/

Dfd7b9492f5c5e49dca373bfdd7a3b1a?s=128

Elias Dorneles

November 07, 2014
Tweet

Transcript

  1. 7.

    POR QUÊ? Descobrir o que as pessoas gostam Monitorar o

    que estão dizendo sobre seu produto Rastrear ofertas de emprego, preços, etc Acompanhar tendências de assuntos e produtos Backup de conteúdo histórico (notícias, blogs)
  2. 12.

    http://scrapy.org pip install scrapy Para os pragmáticos que querem baterias

    inclusas =) Para os pragmáticos que querem baterias inclusas =)
  3. 14.

    SpiDERS! SCRAPING && CRAWLing Um Spider, abstração central do Scrapy,

    se dedica a 2 coisas: crawling (seguir os links para as páginas que se queira) & scraping (extrair os dados da página)
  4. 15.

    Synchronous requests suck! Synchronous requests suck! No Scrapy você trata

    requisições de forma assíncrona: melhor desempenho para crawlings grandes.
  5. 17.
  6. 18.
  7. 19.

    # arquivo.py from scrapy import Spider, Request class Aranha(Spider): name

    = 'aranha' def start_requests(self): yield Request( url='http://www.python.org', callback=self.parse) def parse(self, response): self.log('Oi: %s' % response.url) SPIDERS PRECISAM DE UM NOME Eis o código dum Spider mínimo
  8. 21.

    # arquivo.py from scrapy import Spider, Request class Aranha(Spider): name

    = 'aranha' def start_requests(self): yield Request( url='http://www.python.org', callback=self.parse) def parse(self, response): self.log('Oi: %s' % response.url) ACIONA AS PRIMEIRAS REQUISIÇÕES
  9. 22.

    # arquivo.py from scrapy import Spider, Request class Aranha(Spider): name

    = 'aranha' def start_requests(self): yield Request( url='http://www.python.org', callback=self.parse) def parse(self, response): self.log('Oi: %s' % response.url) DEFAULT CALLBACK PARA TRATAR RESPOSTAS
  10. 24.

    $ scrapy runspider arquivo.py ... 2014-08-24 17:45:58-0300 [aranha] INFO: Spider

    opened 2014-08-24 17:45:58-0300 [aranha] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) 2014-08-24 17:45:59-0300 [aranha] DEBUG: Redirecting (301) to <GET https://www.python.org/> from <GET http://www.python.org> 2014-08-24 17:46:00-0300 [aranha] DEBUG: Crawled (200) <GET https://www.python.org/> (referer: None) 2014-08-24 17:46:00-0300 [aranha] DEBUG: Oi: https://www.python.org/ 2014-08-24 17:46:00-0300 [aranha] INFO: Closing spider (finished) 2014-08-24 17:46:00-0300 [aranha] INFO: Dumping Scrapy stats: ...
  11. 25.

    Callbacks retornam um iterable de: itens com dados coletados (scrapy.Item)

    outras requisições (scrapy.Request) com possivelmente outros callbacks
  12. 26.
  13. 27.

    def parse(self, response): article_links = response.xpath( "//header//h1/a/@href" ).extract() for link

    in article_links: article_url = urlparse.urljoin( response.url, link) yield scrapy.Request( article_url, self.extract_article) EXTRAI LINKS Callback gerando requisições
  14. 28.

    def parse(self, response): article_links = response.xpath( "//header//h1/a/@href" ).extract() for link

    in article_links: article_url = urlparse.urljoin( response.url, link) yield scrapy.Request( article_url, self.extract_article) MONTA URL ABSOLUTA Callback gerando requisições
  15. 29.

    def parse(self, response): article_links = response.xpath( "//header//h1/a/@href" ).extract() for link

    in article_links: article_url = urlparse.urljoin( response.url, link) yield scrapy.Request( article_url, self.extract_article) GERA REQUESTS COM OUTRO CALLBACK PARA EXTRAIR DADOS Callback gerando requisições
  16. 30.

    class Article(scrapy.Item): author = scrapy.Field() ... def extract_article(self, response): article

    = Article() article['author'] = response.css( 'div#posted-by::text' ).re(r'Posted by: (.*)') ... yield article DEFINE DADO QUE VAI EXTRAIR Callback extraindo item
  17. 31.

    class Article(scrapy.Item): author = scrapy.Field() ... def extract_article(self, response): article

    = Article() article['author'] = response.css( 'div#posted-by::text' ).re(r'Posted by: (.*)') ... yield article EXTRAI TEXTO FILTRANDO COM REGEX Callback extraindo item
  18. 32.

    class Article(scrapy.Item): author = scrapy.Field() ... def extract_article(self, response): article

    = Article() article['author'] = response.css( 'div#posted-by::text' ).re(r'Posted by: (.*)') ... yield article COLETA ITEM Callback extraindo item
  19. 33.

    $ scrapy runspider arquivo.py \ -o saida.json $ scrapy runspider

    arquivo.py \ -o saida.csv E você também pode escrever um pipeline para armazenar num banco de dados
  20. 36.

    from scrapy.contrib.linkextractors \ import LinkExtractor le = LinkExtractor( allow=["/artigos/.+"], deny=[

    "/artigos/galeria-fotos" ], ) print le.extract_links(response) [ Link(url='http://site.com/artigos/noticia-001', text=u'Lançado Py4k', fragment='', nofollow=False), Link(url='http://site.com/artigos/opiniao-002', text=u'Carta a Guido', fragment='', nofollow=False), ] LinkExtractor extraindo links baseado em padrão nas URLs Saída:
  21. 37.

    from scrapy.contrib.linkextractors \ import LinkExtractor le = LinkExtractor( restrict_xpaths=[ "//ul[@id='navlist']"

    ] ) print le.extract_links(response) [ Link(url='http://example.com/link01.html', text='Link 01', fragment='', nofollow=False), Link(url='http://example.com/link02.html', text='Link 02', fragment='', nofollow=False), ] LinkExtractor extraindo links dentro de um elemento HTML Saída:
  22. 39.

    from scrapy.contrib.spiders.crawl \ import CrawlSpider, Rule class MySpider(CrawlSpider): name =

    'myspider' rules = [ Rule(LinkExtractor(...), callback='extrai_artigo'), Rule(LinkExtractor(...), callback='extrai_video'), ] def extrai_artigo(self, response): ... def extrai_video(self, response): ... REGRAS DE CRAWLING Veja como o crawling fica como algo declarativo: você define as regras de extração de links e como tratar cada tipo de link
  23. 40.

    from scrapy.contrib.spiders.crawl \ import CrawlSpider, Rule class MySpider(CrawlSpider): name =

    'myspider' rules = [ Rule(LinkExtractor(...), callback='parse'), Rule(LinkExtractor(...), callback='extrai_video'), ] def extrai_video(self, response): ... ACIONA REGRAS NOVAMENTE Não sobrescreva o método parse()!
  24. 42.

    $ scrapy runspider arquivo.py \ -s CONFIG=VALUE Num projeto Scrapy,

    podem ser definidas no módulo settings.py $ CONFIG=VALUE scrapy \ runspider arquivo.py Scrapy Settings
  25. 47.

    Mais configurações de crawling: DOWNLOAD_TIMEOUT COOKIES_ENABLED RETRY_ENABLED DEPTH_LIMIT DEFAULT_REQUEST_HEADERS CONCURRENT_REQUESTS_PER_{DOMAIN,IP}

    consulte a documentação para mais... http://scrapy.readthedocs.org/en/latest/topics/settings.html
  26. 49.

    Expressões XPath são apenas condições encadeadas //li/a[contains(., 'Next page')]/@href //div[re:test(@id,

    'head(er)?') and ./h1] //li[a[contains(., 'Next page')]] /preceding-sibling::li[1]
  27. 50.

    Expressões XPath são apenas condições encadeadas //li/a[contains(., 'Next page')]/@href //div[re:test(@id,

    'head(er)?') and ./h1] //li[a[contains(., 'Next page')]] /preceding-sibling::li[1] XPath Axis (eixo) – existem vários!
  28. 51.

    Expressões XPath são apenas condições encadeadas //li/a[contains(., 'Next page')]/@href //div[re:test(@id,

    'head(er)?') and ./h1] //li[a[contains(., 'Next page')]] /preceding-sibling::li[1] Extensões EXSLT (regex, conjuntos)
  29. 52.

    Converter CSS para XPath? from scrapy.selector.csstranslator import ScrapyHTMLTranslator translator =

    ScrapyHTMLTranslator() def css2xpath(css): return translator.css_to_xpath(css) print css2xpath('ul.nav') NOT BAD! u"descendant-or-self::ul[@class and contains(concat(' ', normalize- space(@class), ' '), ' nav ')]" response.css() é só um atalho pra isso! ;) response.css() é só um atalho pra isso! ;)
  30. 53.

    $ scrapy shell http://example.com >>> response.url 'http://example.com' >>> response.xpath('//h1/text()') [<Selector

    xpath='//h1/text()' data=u'Example Domain'>] >>> view(response) # abre no browser >>> fetch('http://www.google.com') # vai para outra URL Use o shell para explorar sites
  31. 54.

    Código boilerplate: w3lib & scrapylib https://github.com/scrapy/w3lib pip install w3lib https://github.com/scrapinghub/scrapylib

    pip install scrapylib Use em seu próximo projeto =) Use em seu próximo projeto =)
  32. 57.

    Opções de deploy • Shell-scripts no cron de um host

    • Scrapyd - https://github.com/scrapy/scrapyd – permite agendar jobs Scrapy via API, interface Web mínima • Heroku - https://github.com/dmclain/scrapy-heroku • Scrapy Cloud - http://scrapinghub.com/scrapy-cloud – solução PaaS da ScrapingHub*, fornece API & interface Web para jobs, dados coletados, settings, stats e mais. * Full-disclosure: ScrapingHub é a empresa em que o palestrante trabalha!
  33. 59.

    Recapitulando... 1) Obter dados quentes com Web Scraping é um

    superpoder 1) Obter dados quentes com Web Scraping é um superpoder
  34. 60.

    Recapitulando... 1) Obter dados quentes com Web Scraping é um

    superpoder 1) Obter dados quentes com Web Scraping é um superpoder 2) Scrapy resolve scraping & crawling, é rápido, extensível e vem com baterias inclusas 2) Scrapy resolve scraping & crawling, é rápido, extensível e vem com baterias inclusas
  35. 61.

    Recapitulando... 1) Obter dados quentes com Web Scraping é um

    superpoder 1) Obter dados quentes com Web Scraping é um superpoder 2) Scrapy resolve scraping & crawling, é rápido, extensível e vem com baterias inclusas 2) Scrapy resolve scraping & crawling, é rápido, extensível e vem com baterias inclusas 3) Para aproveitar o Scrapy ao máximo, vasculhe os docs & aprenda XPath 3) Para aproveitar o Scrapy ao máximo, vasculhe os docs & aprenda XPath
  36. 62.

    Recapitulando... 1) Obter dados quentes com Web Scraping é um

    superpoder 1) Obter dados quentes com Web Scraping é um superpoder 2) Scrapy resolve scraping & crawling, é rápido, extensível e vem com baterias inclusas 2) Scrapy resolve scraping & crawling, é rápido, extensível e vem com baterias inclusas 3) Para aproveitar o Scrapy ao máximo, vasculhe os docs & aprenda XPath 3) Para aproveitar o Scrapy ao máximo, vasculhe os docs & aprenda XPath 4) Crie algum projeto com Scrapy, publique nas interwebs e depois me conte! =) 4) Crie algum projeto com Scrapy, publique nas interwebs e depois me conte! =)