Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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. Explorando Python Brasil - 2014 além do tutorial

  2. Web Scraping WAT?

  3. Existe muito conteúdo na Web

  4. Mas a gente quer dados

  5. Web Scraping em uma casca de noz

  6. POR QUÊ?

  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)
  8. Obter informações quentes é um superpoder

  9. OK, vamos falar de Python!

  10. stdlib: urllib2, re, xml Para os puristas de verdade Para

    os puristas de verdade
  11. requests BeautifulSoup lxml Para os pragmáticos de plantão Para os

    pragmáticos de plantão
  12. http://scrapy.org pip install scrapy Para os pragmáticos que querem baterias

    inclusas =) Para os pragmáticos que querem baterias inclusas =)
  13. Rápido, poderoso, extensível e customizável

  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)
  15. Synchronous requests suck! Synchronous requests suck! No Scrapy você trata

    requisições de forma assíncrona: melhor desempenho para crawlings grandes.
  16. Twisted Matrix Event-driven networking engine https://twistedmatrix.com “molho secreto” do Scrapy

    “molho secreto” do Scrapy
  17. None
  18. None
  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
  20. Requisições são tratadas em callbacks

  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
  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
  23. $ scrapy runspider arquivo.py

  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: ...
  25. Callbacks retornam um iterable de: itens com dados coletados (scrapy.Item)

    outras requisições (scrapy.Request) com possivelmente outros callbacks
  26. None
  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
  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
  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
  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
  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
  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
  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
  34. That's it!

  35. Abstrações úteis

  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:
  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:
  38. CrawlSpider Estende scrapy.Spider para seguir links usando regras definidas na

    classe no callback default
  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
  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()!
  41. Configurações e outros truques

  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
  43. DOWNLOAD_DELAY=0.5 Seja gentil com os sites = máximo de 2

    reqs/s = máximo de 2 reqs/s
  44. Só porque você pode não significa que você deva!

  45. REDIRECT_MAX_TIMES=5 Evite loops de redirecionamento

  46. TELNETCONSOLE_ENABLED=False Livre-se de bisbillhoteiros

  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
  48. Aprenda XPath! O domínio de XPath diferencia os gurus dos

    gafanhotos! =D
  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]
  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!
  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)
  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! ;)
  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
  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 =)
  55. Cool tools, bro!

  56. E o deploy?

  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!
  58. Scrapy Cloud - Dashboard

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

    superpoder 1) Obter dados quentes com Web Scraping é um superpoder
  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
  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
  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! =)
  63. Elias Dorneles @eliasdorneles @ScrapingHub Q&A