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

Explorando Scrapy além do tutorial

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

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/

Avatar for Elias Dorneles

Elias Dorneles

November 07, 2014
Tweet

More Decks by Elias Dorneles

Other Decks in Programming

Transcript

  1. 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. http://scrapy.org pip install scrapy Para os pragmáticos que querem baterias

    inclusas =) Para os pragmáticos que querem baterias inclusas =)
  3. 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. Synchronous requests suck! Synchronous requests suck! No Scrapy você trata

    requisições de forma assíncrona: melhor desempenho para crawlings grandes.
  5. # 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
  6. # 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
  7. # 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
  8. $ 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: ...
  9. Callbacks retornam um iterable de: itens com dados coletados (scrapy.Item)

    outras requisições (scrapy.Request) com possivelmente outros callbacks
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. $ 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
  17. 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:
  18. 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:
  19. 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
  20. 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()!
  21. $ 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
  22. 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
  23. 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]
  24. 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!
  25. 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)
  26. 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! ;)
  27. $ 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
  28. 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 =)
  29. 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!
  30. Recapitulando... 1) Obter dados quentes com Web Scraping é um

    superpoder 1) Obter dados quentes com Web Scraping é um superpoder
  31. 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
  32. 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
  33. 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! =)