- Para baixar fotos, vídeos, arquivos, textos.
Definir o que se quer baixar.
- scrapy.Spider
- CrawlSpider
- XMLFeedSpider
- CSVFeedSpider
- SitemapSpider
- Sequência de manipução de dados. Manipular dados e salvar.
- Request/Response
- Injectin custom header
- Proxying
- Coordena as ações
- Preserva a ordenação das ações, resquests
- Spider - resquest
- Engine - resquest
- Scheduler - resquest
- Engine - resquest
- Middleware - Downloader Middleware - response
- Spider - Spider Middleware - extract data
- Engine
- Pipeline
Instrução do que pode ou não pode ser baixado, exemplo: https://www.facebook.com/robots.txt
- User-Agent
- Allow
- Disallow - Páginas proibidas
- conda install -c conda-forge scrapy==1.6
- pylint
- autopep8
- Outra alternativa
- python3 -m pip install scrapy==1.6 pylint autopep
- scrapy - Abre a ferramenta
- scrapy bench - Benchmark test
- scrapy fetch http://google.com
- scrapy version - Versão do scrapy
- scrapy startproject nomedoprojeto
- shell - Para fazer experimentos
- runspider - Usado para executar spider sem criar projeto, bom para projetos rápidos e testes
Scrap da página https://www.worldometers.info/world-population/population-by-country/
-
scrapy startproject worldometers - Criar projeto worldometers
-
Ir para pasta worldometers
-
Criar spider
- scrapy genspider countries www.worldometers.info/world-population/population-by-country
- Precisa apagar a última barra(/) porque o scrapy adiciona automaticamente e também apagar o https://
- Countries é o nome do spider, o nome deve ser único
-
Alterar de http para https em spider/country.py
-
conda install ipython
- Instalar ipython ou pip install ipython
-
scrapy shell
- Dentro do scrapy shell o comando shelp() mostra o help
- Abre o shell para fazer alguns testes
- scrapy shell site - Se fosse informado o site já baixaria a página com apenas 1 passo.
-
fetch("https://www.worldometers.info/world-population/population-by-country/")
- Digitar dentro do shell
- No caso não achou o robots.txt então não há restrição alguma.
-
r = scrapy.Request(url = "https://www.worldometers.info/world-population/population-by-country/")
- Cuidado com o nome da variável no shell, escolha algo simples.
- com esse objeto é possível passar para o fetch, dessa forma, existem duas formas para informar o indereço para o fetch, para o 'buscador'.
-
fetch(r)
-
response.body
- Vai carregar toda html
-
view(response)
- Abre uma página da página baixada. Não é a forma mais recomendada para visualizar a página.
- O recomendável é abrir a página e desativar o javascript. No inspetor e desativar o javascript para observar como o scrapy baixa página.
- Ctrl + shift + i
- Ctrl + shilt + p
- Desabilitar javascript - Obs: Spiders não renderizam javascript.
-
Scrap do título
- Ctrl + F dentro da janela inspecionar
- Dentro do navegador buscar o título usando xpath: "//h1"
-
De volta ao terminal.
- title = response.xpath('//h1') - Retorna o texto com a tag h1
- title = response.xpath('//h1/text()') - Usando a função text() retira o texto da tag
- title.get() - Mostra o conteúdo da tag h1
- usando css
- title_css = response.css('h1::text')
- title_css.get() - Mostra o conteúdo da tag h1
-
Agora buscar os países. Aqui no caso é usado .getall() porque é uma lista de dados
- countries = response.xpath('//td/a/text()').getall()
- countries_css = response.css('td a::text').getall()
-
Alterar o spider countries.py
class CountriesSpider(scrapy.Spider):
name = 'countries' # Esse nome é único, é possível ter diversas spiders mas cada uma tem que ter um nome diferente caso contrário criará um conflito
#allowed_domains = ['www.worldometers.info/world-population/population-by-country']
allowed_domains = ['www.worldometers.info'] #limita o escopo do spider, não pode ter o http://
#start_urls = ['http://www.worldometers.info/world-population/population-by-country/']
start_urls = ['https://www.worldometers.info/world-population/population-by-country/'] #Todos os links que queremos buscar, mudei para https por causa do site
#### É bom lembrar que o padrão name, allowed_domains, start_urls, parse são nomes padrões, se forem trocados não irá funcionar
def parse(self, response):
#pass
title = response.xpath('//h1/text()').get()
countries = response.xpath('//td/a/text()').getall()
# retornar como dicionário
yield {
'title':title,
'countries':countries
}
- No terminal - rodar o spider countries, precisa ser no mesmo nível que está o arquivo scrapy.cfg
- scrapy crawl countries
Site para testes - https://try.jsoup.org/
Usa "." busca por atributos das classes.
<div class ='intro'>
.nomedaclasse
.intro
Usa "#" busca por atributos das ids.
<div id ='location'>
#nomedaid
#location
Para acessar tag dentro de uma tag específica, por exemplo, uma div.
tag.atributo
tag#location
.bold.italic
<p class="bold italic">Hi, I have two classes</p>
Para múltiplas classes e ids
.class.class
#id#id
Se a class nao é padrão do html e foi criada, para selecionar é um pouco diferente:
li[data-identifier=7] ou [data-identifier=7]
<li data-identifier="7">Item 1</li>
Para selecionar apenas atributos de classe que começam com https, usando ^.
a[href^='https']
<a href="https://www.google.com">
Aqui os atributos que terminam com algum texto, usando $. Lembre-se de regex.
a[href$='fr']
<a href="http://www.google.fr">
É possível buscar qualquer atributos em tag que começam com outros parametros também, por exemplo:
[class^='in']
É possível achar a parte do meio de um atributo de classe também, usando *.
a[href*='google']
<a href="http://www.google.fr">
Se não quer selecionar algo aparece no início e nem no final, usando ~.
a[href~='fr'] obs: Não funcionou no teste.
Selecionar dos os p dentro da div e da classe intro. Não pega os descendentes das tags que estão dentro:
div.intro p
Se for necessário pegar um descente específico, basta informar:
div.intro p, span#location
Se for necessário pegar todos os descentes da div, classe intro e tag p:
div.intro > p
Para pegar a tag p imidiatamente depois da div com classe intro, só serve se estiver imediatamente depois da div, caso contrário não retornará nada. + span não retornará nada.
div.intro + p
Seleciona item da lista que está no índice 1.
li:nth-child(1)
Seleciona os índices ímpares.
li:nth-child(odd)
Seleciona os índices ímpares.
li:nth-child(even)
Xpath é melhor que permite ir para frente e para trás em um texto html
Site para testes: https://scrapinghub.github.io/xpath-playground/
Para selecionar tags com Xpath é necessário dupla barra na frente primeiro
Procura todas h1 na html
//h1
//div[@class='intro']
//div[@class='intro']/p
//div[@class='intro' or @class='outro']/p
//div[@class='intro' or @class='outro']/p/text()
//a/@href
//a[starts-with(@href, 'https')]
//a[ends-with(@href, 'fr')] Vai retornar erro porque só suporta a partir da versão 2.0. Não vai funcionar nos browsers.
//a[contains(@href, 'google')]
//a[contains(text(), 'France')] Busca no texto e não na tag. É case sensitive.
li[1]
//ul[@id='items']/li[position() = 1 or position() =4 ]
//ul[@id='items']/li[position() = 1 or position() =last() ]
//ul[@id='items']/li[position() > 1 ]
//p[@id='unique']/parent::div
//p[@id='unique']/parent::node()
//p[@id='unique']/ancestor::node()
//p[@id='unique']/ancestor-or-self::node()
//p[@id='unique']/preceding::node()
//p[@id='unique']/preceding::h1
//p[@id='outside']/preceding-sibling::node()
//div[@class='intro']/p
//div[@class='intro']/child::p
//div[@class='intro']/child::node()
//div[@class='intro']/following::node()
//div[@class='intro']/following-sibling::node()
//div[@class='intro']/descendant::node()
In [41]: response.xpath('//tbody/tr/td/a[@href]/text()')[0] Out[41]:
In [42]: response.css('tbody tr td a[href]::text')[0] Out[42]:
-
Para exportar
scrapy crawl countries -o population_dataset.json No vscode alt+shift+f formata o json automaticamente. scrapy crawl countries -o population_dataset.csv scrapy crawl countries -o population_dataset.xml
spider cigabuy
https://www.cigabuy.com/consumer-electronics-c-56_75-pg-1.html
scrapy startproject cigabuy scrapy genspider special_offers www.cigabuy.com/specials.html
Alterar para https
- testes:
scrapy shell https://www.cigabuy.com/consumer-electronics-c-56_75-pg-1.html
response.xpath("//div[@class='r_b_c']").xpath(".//div[@class='p_box_wrapper']").css("div").xpath("a[@class='p_box_title']/text()").getall()
response.xpath("//div[@class='r_b_c']").xpath(".//div[@class='p_box_wrapper']").css("div").css("a.p_box_title::text").getall()
response.xpath("//div[@class='r_b_c']").xpath(".//div[@class='p_box_wrapper']").css("div").css("a.p_box_title::attr(href)").getall()
response.xpath("//div[@class='r_b_c']").xpath(".//div[@class='p_box_wrapper']").css("div").xpath("a[@class='p_box_title']/@href").getall()
scrapy crawl special_offers -o dataset_encoding.json
-
Pode har problemas de encoding no json por isso, alterar em settings.py:
FEED_EXPORT_ENCODING = 'utf-8'
-
Alterar user-agent no spider cigabuy tem algumas formar como solução.
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36
scrapy parse --spider=countries -c parse_country --meta='{"country_name":"China"}' https://www.worldometers.info/world-population/china-population/
- Possibilidade para salvar arquivo.csv sem linha de comando:
- FEED_FORMAT
- FEED_URI
import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from worldometers.spiders.countries import CountriesSpider
#process = CrawlerProcess(settings=get_project_settings())
process = CrawlerProcess({
'USER_AGENT': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)',
'FEED_FORMAT': 'CSV',
'FEED_URI': '~/export_vscode.csv',
})
process.crawl(CountriesSpider)
process.start()