Querido Diário - Monitorando o governo de Araraquara/SP
Um tempo atrás, escrevi um pouco sobre como tinha realizado uma contribuição para coletar os diários oficiais de Americana. Porém, tem alguns erros e imprecisões por lá e recomendo a leitura apenas para caráter informativo. Se você quiser seguir algo, este está com certeza melhor e é para a cidade de Araraquara!
Preparando o terreno
Fork do projeto
Entre no seu github e clique para fazer fork do projeto, depois disso acesse seu perfil e copie o link do seu fork, deve estar algo assim:
Clonando o projeto
É necessário instalar o git antes! Depois de realizar o fork, agora podemos puxar os dados para a nossa máquina, para isso use o comando:
Depois disso, o projeto foi clonado para seu computador, sendo assim, temos boa parte do ambiente necessário.
Agora, vamos criar um ramo dentro do nosso projeto, para que possamos separar o código e não fazer bagunça, para isso usamos o comando:
Deste modo, estamos criando um ramo que terá o nosso código para a spider que queremos criar, tendo como base o código no ramo principal. Para listar todos os ramos e ver onde estamos:
Configurando Python
É necessário [instalar o Python no Windows]! Na maioria das distribuições Linux, vem instalado por padrão. Precisamos criar nosso ambiente virtual no python, para garantir que nosso sistema operacional não seja afetado pelas bibliotecas que vamos instalar:
Agora com nosso ambiente criado e ativo (deve ter aparecido venv do lado esquerdo no seu terminal), agora podemos instalar os requerimentos do projeto, navegue até o arquivo requirements.txt.
Depois disso, você tem o ambiente completo configurado no seu computador, podendo executar qualquer spider existente no projeto. Se você for até o diretório das spiders, poderá encontrar um punhado delas!
Agora podemos executar por exemplo, a spider da cidade de Jaú, do Estado de São Paulo:
Com esse comando, a spider será executada e todos os diários oficiais da cidade serão baixados no seu computador, hoje (16 de agosto de 2022) ela está funcinal. Mas além de executar, a ideia é criar uma spider nova, então notei no arquivo CITIES.md, que tem todas as cidades e as spiders existentes, que faltam muitas cidades. Peguei uma lista das 200 maiores cidades do Estado de SP e filtrei as que estavam faltando. A cidade de Araraquara é uma delas! Vamos fazer :)
Criando a spider
Para criar nossa spider, basta usar o recurso do próprio Scrapy, ele já cria um modelo legal:
Depois disso, você pode abrir o arquivo gerado com seu editor de texto preferido, no meu caso, vou utilizar o Vim.
Você irá se deparar com um arquivo contendo uma configuração básica, vamos alterá-lo um pouco.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import datetime
from urllib.parse import urlencode
import dateparser
from gazette.items import Gazette
from gazette.spiders.base import BaseGazetteSpider
class SpAraraquaraSpider(BaseGazetteSpider):
TERRITORY_ID = "3503208"
name = "sp_araraquara"
allowed_domains = ["diariooficialcmararaquara.sp.gov.br"]
start_date = datetime.date(2021, 3, 4) # First gazette available
end_date = datetime.datetime.today()
start_urls = ["https://www.diariooficialcmararaquara.sp.gov.br"]
search_url = "https://www.diariooficialcmararaquara.sp.gov.br/diario/busca?"
base_url = "https://www.diariooficialcmararaquara.sp.gov.br"
def parse(self, response):
pass
Explicação
Linha 1 a 7: estamos importando diversas bibliotecas, referentes à manipulação de hora, bibliotecas com recursos padronizados para utilizar o Scrapy no projeto e outras;
Linha 10: é declarada a classe SpAraraquaraSpider e entre parênteses é informado que ela herda a classe BaseGazetteSpider;
Linhas 11: Define o código IBGE da cidade
Linha 12: Define o nome da nossa spider;
Linha 13: Define o domínio permitido, muito útil para garantir que nada sairá de controle;
Linhas 14 e 15: Configura o primeiro dia que foi publicado diário oficial da cidade e depois a data atual
Linha 16: Define onde nossa spider vai começar sua atuação;
Linha 17 e 18: Determina a URL que é realizada a pesquisa do diário e uma base para realizarmos os downloads
Linha 20: Criado o método parse, o qual recebe o objeto response. O objeto response contem inclusive o código fonte da página atual que a spider está;
Criando a Spider
Investigação
Acesse o site dos diários de Araraquara e pressione F12, vai aparecer um painel e lá tem uma seção de Rede, onde é possível ver (quase) todas as mensagem que seu navegador trocou com o site alvo.
No formulário à esquerda, tem como filtrar por datas, após colocar a data, clique em buscar. Podemos encontrar esta requisição:
Assim descobrimos que podemos interagir diretamente com a URL!
Desenvolvendo o método parse
Depois de alterarmos nosso arquivo base, agora devemos criar o método parse, o qual é o ponto de retorno padrão quando outros métodos não definem o callback, por isso este acaba sendo responsável também por nutrir nossa classe com links!
1
2
3
4
5
6
7
8
9
10
11
12
def parse(self, response):
initial = self.start_date.strftime("%d/%m/%Y")
end = self.end_date.strftime("%d/%m/%Y")
params = {
"data": initial,
"dataFinal": end,
"descricao": "",
"subcategoria": "",
}
url_params = urlencode(params)
yield response.follow(f"{self.search_url}{url_params}", self.parse_gazette)
Explicação
Linha 2 e 3: Definimos as datas de início e fim no formato de string;
Linha 5: Configuramos os parâmetros que o site passa via requisição na URL;
Linha 11: codificamos as informações para serem passadas na URL;
Linha 12: Usando o yield fazemos com que o comando seguinte entre para a fila de processamento e chama o método parse_gazette
Desenvolvendo o método parse_gazette
Depois de realizar a requisição com os parâmetros que passamos via URL, agora vamos extrair os dados que retornaram e salvar os diários.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def parse_gazette(self, response):
gazettes = response.css(".event-card.animated.flipInX")
for gazette in gazettes:
card = gazette.css(".event-card")
edition_number = card.css(".event-data h4 ::text").re_first(r"[0-9]+")
date = card.re_first(r"[0-9]+/[0-9]+/[0-9]+")
date = datetime.datetime.strptime(date, "%d/%m/%Y").date()
url = card.css(".row ::attr(href)").get()
url = self.base_url + url
if card.css(".event-edicao p ::text").get() == "Edição Única":
extra_edition = False
else:
extra_edition = True
yield Gazette(
date=date,
file_urls=[url],
is_extra_edition=extra_edition,
power="executive",
edition_number=edition_number,
)
Explicação
Linha 3: com este comando, extraímos o elemento da página Web utilizando os seletores de CSS, utilizamos o nome da classe do objeto para isso. Para encontrar essa informação, basta usar o botão F12 e procurar o elemento no código HTML e então jogamos essa informação na variável card que utilizaremos depois.
Linhas 5: Com este for vamos passar por todos os elementos Web que encontramos
Linha 6 a 12: Navegamos utilizando o CSS, utiliza-se Regex para extrair as informações necessárias para o diário oficial
Linha 18: Damos início à criação do nosso objeto a ser inserido no projeto, estruturando a informação no modelo do projeto, o yield adiciona isso à fila de processamento e segue realizando downloads.
Subindo o código
Precisamos dizer ao git que iremos adicionar os arquivos alterados:
Damos início ao nosso commit:
Subimos nosso código para o repositório:
Depois de fazer tudo isso, ao entrar na página do GitHub, vai aparecer o botão para realizar o Pull Request, isso encerra uma contribuição com o projeto. Se você tiver interesse em contribuir ou quiser conversar sobre, basta abrir um issue na página do GitHub do projeto.
Conclusões
Contribuindo com a extração da cidade de Americana, pude aprender bastante sobre a linguagem Python e também sobre Scrapy, quando expomos nosso código publicamente a comunidade nos ajuda a realizar o melhor. Algo que já foi aplicado na coleta da cidade de Araraquara.
Espero que este relato tenha sido útil e ajudado você que está iniciando no Scraping!