1. Introdução

O presente texto é o primeiro módulo da nossa abordagem sobre a coleta de dados, que está dividida em três etapas:

  1. Elaboração de um Extrator Básico, programa capaz de buscar conteúdos em HTML. Desenvolveremos um extrator dos dados da Página de Controle Concentrado do STF, chamado Extrator_STF_ControleConcentrado.py.
  2. Elaboração de um Módulo de Organização de Dados, capaz de lidar com quaisquer conteúdos que você tiver extraído;
  3. Elaboração de um Módulo Extrator avançado, capaz de lidar com javascript (este módulo não será trabalhado no presente curso, mas em um módulo avançado)

Neste texto, daremos o primeiro desses três passos, que é a elaboração do extrator que eu chamo de básico porque ele utiliza estratégias voltadas apenas para a extração de conteúdos que estão em HTML, no Código Fonte da página. Isso faz com que as estratégias exploradas neste momento não sejam suficiente para coletar alguns dados muito relevantes, como os andamentos processuais das ações no STF, que exigem abordagens capazes de lidar com  javascript.

Embora essa abordagem não resolva todos os problemas, as ferramentas que desenvolveremos podem ser usadas de forma muito produtiva para extrair parte relevante dos dados do STF e de outros tribunais. Além disso, o desenvolvimento de estratégias mais complexas depende do domínio adequado de vários dos elementos tratados no presente texto, como as técnicas para lidar com URLs e para gravar os dados.

Este módulo é voltado a pessoas que nunca elaboraram extratores de dados, mas a devida compreensão de todos os elementos aqui utilizados é muito facilitada pela realização dos 4 módulos do Curso de Programação para Juristas, em que você tem uma orientação minuciosa sobre os tipos de variáveis, sobre os comandos básicos de Python e sobre as estratégias de iteração. De fato, o objetivo deste curso preliminar era preparar os estudantes da disciplina Data Science e Direito para poderem enfrentar os desafios de programação envolvidos na elaboração dos algoritmos de extração e organização de dados. Por isso, embora a devida compreensão deste texto não dependa de conhecimentos avançados de informática, não nos dedicaremos a oferecer explicações minuciosas sobre alguns elementos básicos de programação em Python, cujo domínio é pressuposto.

2. Extração simples

2.1 Passo 1: Identificação das informações relevantes

Para a extração dos dados, você não precisa contar ainda com um modelo de dados completo, visto que esse modelo pode ser construído posteriormente. Porém, você precisa contar, desde o início, com uma definição clara da sua unidade de análise e da população de objetos que você pretende mapear.

A relação população/objeto estabelece o centro da sua coleta, pois é preciso coletar dados referentes a objetos específicos, cuja consolidação permitirá fazer afirmações sobre o universo. Um dos binômios mais comuns é fazer uma coleta de dados sobre processos (que são a unidade), para fazer afirmações sobre certas populações de processos (que são o universo). Porém, você pode fazer levantamento sobre pautas de julgamento para falar da agenda de julgamento do Tribunal. Você pode fazer um levantamento sobre decisões específicas (que serão a unidade) para tratar de uma população de decisões (independentemente dos processos em que ocorrem).

Apesar de serem muitas as possibilidades, o fato é que as pesquisas disponíveis nos tribunais normalmente disponibilizam os dados agregados em termos de processos, o que limita um pouco as nossas possibilidades. A vantagem é que costuma haver páginas processuais com informações bastante ricas. A desvantagem é que essas páginas não são estruturadas, o que gera desafios complexos no momento da categorização e organização dos dados.

Mas existem também outras possibilidades. O STF, por exemplo, tem páginas que são designadas como pautas de julgamento, mas que na prática trazem listas dos processos que foram analisados em cada sessão, o que possibilita fazer buscas pela sessão de julgamento, e não pelo número do processo, o que gera um conjunto de dados diferente.

Assim, o primeiro desafio é entrar na página do STF e buscar, pelos instrumentos de busca disponíveis, páginas que contenham os dados que nos interessam. As três possibilidades que me parecem mais ricas (mas há outras) são:

  1. Pesquisa de jurisprudência, centrada em termos que ocorrem nas decisões;
  2. Pesquisa de processos, a partir do número e classes;
  3. Pesquisa de "pautas", a partir da data das sessões.

Assim, o primeiro passo é localizar as informações relevantes e explorá-las a partir do seu navegador.

2.2 Análise do código fonte: HTML

Uma vez que você conseguiu acessar os dados relevantes pelo seu navegador, é preciso entender um pouco do modo pelo qual o servidor do STF envia para o seu computador as informações que você lê na tela.

Como toda informação computacional, os dados enviados ao seu computador são codificados em uma determinada linguagem, e a linguagem padrão da internet se chama HTML (Hypertext Markup Language).

Quando você usa processadores de texto como o Word, você tem grande liberdade para definir tanto o conteúdo quanto o formato do seu texto. Esse tipo de editor é chamado normalmente de WYSIWYG (What You See Is What You Get), pois o texto que você vê na tela enquanto escrever é idêntico ao que resultará de sua impressão.

Por estar ligado ao documento impresso, esse tipo de editor respeita uma regra implícita: você precisa trabalhar nos limites de uma folha de papel (real ou virtual), cujo tamanho você define no próprio documento.

Quando você escreve para a internet, essa moldura predefinida não existe. O que existe é uma multiplicidade de tamanhos de janelas de exibição. Experimente modificar a largura desta tela que você está lendo e você verá que o texto se adapta, mudando de forma, para que ele tenha um formato equilibrado em molduras de qualquer tamanho.

Essa plasticidade é fundamental para toda publicação na internet e, obviamente, ela demanda um planejamento exaustivo dos modos pelos quais a exibição será adaptada à tela do usuário. A programação dessa exibição flexível é feita utilizando uma linguagem computacional específica: o HTML, na qual é possível definir com comandos relativamente simples os modos pelos quais um texto será exibido nas mais variadas janelas.

O custo da plasticidade oferecida pelo HTML é que, diversamente do que ocorre com os editores WYSIWYG, o texto que você vê quando escreve não é o texto que vai aparecer para o leitor, pois a formatação final depende das configurações do site no qual o texto será publicado. Este é o texto que eu estou vendo enquanto escrevo no editor do Ghost, que é diferente do texto que você vê agora, pois ele não envolve nenhum dos formatos definidos no site da disciplina.

Para ver o  HTML desta página basta clicar nela com o botão direito do mouse e escolher a opção "Exibir Código Fonte" (ou use Ctrl-U), que é o conjunto de códigos que o seu navegador precisa receber para que seja capaz de exibir a tela que você vê exatamente dessa forma.

Uma forma ainda mais interessante é utilizar o HTML viwer do Code Beautify. Entre em um jornal de grande circulação (como a Folha, o El País ou o NYT), escolha uma reportagem e copie o url (endereço) da página. Depois, entre no HTML viewer (veja a imagem abaixo), clique no Load Url, insira o endereço que você copiou, e clique em Load.

Esse programa então carregará, lado a lado, o código fonte (o HTML input, que são as informações enviadas pelo servidor do jornal, com todos os códigos que definem a formatação que deverá aparecer na tela) e o output, que é o modo pelo qual um navegador deve exibir as informações codificadas em HTML.

O HTML é uma Markup Language porque ela une, na mesma string, os conteúdos do seu texto e as marcações de formatação. Se você observar o código fonte no HTML Viewer, notará que há partes em texto, entremeado por códigos que indicam o modo de exibição que é mostrado na janela da direita.

As informações que vamos buscar na internet com o Python são aquelas que estão no código fonte. Para se familiarizar com o tipo de informações que obteremos, abra no seu navegador (e não no HTML Viwer) este endereço, que tem as informações da ADI 333, na página específica de Controle Concentrado (STF/Processos/ADI, ADC, ADO e ADPF). Com base nesses dados, faça o exercício abaixo.

Se você correu os olhos pelo Código Fonte, deve ter notado que ele é dividido em linhas, que a primeira parte do documento contém uma série de informações sobre o cabeçalho da página (até a linha 217), depois aparecem informações sobre a barra lateral (da linha 218 até a 258), seguidas por outros códigos e links até uma parte em verde chamada "codigo teste rybena" (linhas 471 a 497) e que os dados propriamente sobre a ADI 333 começam na linha 633, já próximo ao final do documento.

Se você der um Ctrl-F, pode buscar diretamente as informações, mas também pode encontrá-las lendo o documento a partir da linha 633. Observe, nas duas imagens abaixo, a comparação entre um texto exibido no Chrome e o código fonte subjacente.

Exibição do Chrome

Código fonte em HTML

Cotejando as duas imagens acima, você pode notar que a segunda contém os mesmos textos da primeira, mas incopora também alguns códigos, sempre entre <>, que dão aos seu navegador as informações necessárias para exibir corretamente os conteúdos. Na primeira linha, por exemplo, <h3> indica que o texto "ACAO DIRETA DE INCONSTITUCIONALIDADE - 333" será exibido no formato Header3 e o <FONT COLOR=RED> indica que o "333" será exibido em vermelho.

Você logo se acostumará com o fato de que <h3> marca o início da formatação Header3, enquanto </h3> marca o final dessa formatação, assim como <FONT COLOR=RED> marca o início dessa formatação, enquanto </FONT> marca o final. Toda vez que você tiver um <h3> ou <pre> ou <strong>, necessariamente você terá um </h3> ou </pre> ou </strong>: toda marcação de início precisa de uma marcação de fim e toda marcação do HTML é uma indicação de formatação.

Familiarizar-se com o HTML é o começo do seu itinerário para extrair as informações, visto que você não trabalhará com a primeira visualização, mas com os dados subjacentes, que estão no Código Fonte.

No primeiro momento, isso parece ser um problema, pois aparecem muitos códigos que nós não entendemos e podemos ter a tentação de limpar os códigos. Porém, quando você começar a construir os módulos de organização de dados (ou seja, os geradores de tabela) essa multiplicidade de códigos será vista como uma grande vantagem, pois os marcadores de formatação do HTML nos mostram muito da estrutura do documento e eles nos servem como ótimos marcadores para localizar as informações que desejamos extrair.

2.3. Requisições do código fonte - HTTP

No processo de construção dos extratores, você vai ser acostumar a consultar o Código Fonte porque é esse o conteúdo que os servidores enviam para o seu computador. Nos servidores do STF, estão armazenados esses conteúdos HTML, e eles enviam esse conteúdo a qualquer computador que requisita as informações referentes a um determinado localizador que chamamos de URL (Uniform Resourse Locator) e metaforicamente chamamos de endereço.

Quando falamos que uma página está hospedada em um servidor (server), indicamos que esse host (computador que hospeda páginas), ao receber requisições que apontem para esse localizador, enviará como resposta os conteúdos armazenados nesse "endereço".

Esse processo de Requisição/Resposta é feito mediante um protocolo de comunicação entre computadores, que define as formas de solicitação e de resposta. O protocolo mais usado na internet é o HTTP (Hypertext Transfer Protocol), que possibilita que você faça vários tipos de requisições, das quais você precisa aprender apenas uma: a solicitação de tipo get, que busca o conteúdo da página e retorna uma string com o conteúdo de um documento de tipo HTML.

Para operar essas requisições, nós utilizamos a biblioteca requests, que tem uma função especialmente desenhada para realizar esse pedido: a função requests.get(). A utilização dessa função dentro do seu programa exige a importação da biblioteca requests, que pode ser feita pelo comando:

import requests

As importações de bibliotecas costumam vir em bloco no início dos nossos programas. Uma vez importado o pacote (package), você pode utilizar as suas funções por meio do nome composto NomeDaBiblioteca.NomeDaFunção, que no nosso caso resulta em requests.get().

Note que você também pode importar individualmente a função get, por meio do comando:

from requests import get

Usada essa fórmula, a função get é importada para o seu programa, o que possibilita utilizá-la diretamente pelo nome get(). Em nossos programas, utilizaremos o nome completo requsets.get() porque essa abordagem deixa clara a origem dessa função.

O HTTP também define vários tipos de retorno, inclusive os códigos 400 (que indica requisições impossíveis de serem processadas) e 500 (que indica que o servidor não conseguiu processar uma requisição aparentemente válida). Outro protocolo comum é o HTTPS, que de fato é o mesmo HTTP, mas com uma camada a mais de dados, que permite o uso de criptografia (daí o S, de secure).

Quando navegamos pela internet, esse processo de requisições e retornos é intermediado pelos nossos navegadores (browsers), como o Chrome, o Firefox e o Edge. Cada resposta bem sucedida que esses programas recebem é processada por eles, que exibem em nossas telas as imagens devidamente formatadas. Assim, a função dos navegadores é:

  1. solicitar as informações referentes ao conteúdo hospedado em um servidor;
  2. receber as respostas enviadas pelo servidor onde a página está hospedada;
  3. processar essas informações para que elas sejam exibidas de acordo com os parâmetros de formatação contido no HTML.

No nosso processo de extração de dados, não utilizaremos os navegadores para processar as requisições e respostas, mas utilizaremos o próprio Python, que tem bibliotecas capazes de gerir esses pedidos de forma direta, utilizando-se do protocolo HTTP. Com isso, é dispensável o aprendizado específico das minúcias desse protocolo, bastando apenas saber que a função request.get() solicita como resposta o conteúdo hospedado em um URL.

2.4 Módulo de extração do código fonte com a biblioteca requests

Para começar o seu trajeto hacker, escolha uma ADI e busque o seu endereço por meio de uma pesquisa na página STF/Processos/ADI, ADC, ADO e ADPF. Eu escolhi a adi 6058, mas você pode optar por qualquer ADI.

O que nos interessa é localizar o url que está na barra de endereços do seu navegador (neste caso, o Chrome), no alto da figura acima.

import requests

url = 'Insira o URL do processo que você escolheu'
html = requests.get(url).text
print (html)
Extrator1. Módulo básico de extração

Quando você rodar esse programa, ele deve imprimir no console o Código Fonte da página, além definir esse conteúdo como valor da variável html. Como isso é feito exatamente?

A linha 1 importa a biblioteca requests, que você não precisa instalar porque ela já faz parte dos recursos do Anaconda. Para facilitar a visualização, é comum deixar uma linha em branco depois dessa parte inicial de importação das bibliotecas.

A linha 3 define uma variável url, atribuindo a ela o valor do URL do processo que você escolheu. Lembre-se que é preciso colocar o endereço entre aspas (tanto faz se simples ou duplas), pois trata-se de uma variável do tipo string.

A linha 4 usa o comando get da biblioteca requests, que por isso deve ser inserido como requests.get. Esse comando envia uma requisição HTTP de tipo GET, o que significa que essa solicitação pede ao servidor o envio do conteúdo contido no url. Ao acrescentar o ".text", você indica que deseja atribuir à variável html o conteúdo do Código Fonte da página.

Por fim, a linha 5 determina a impressão no console do conteúdo da variável html, que contém o texto do código fonte.

Para aprofundar:
Se você esquecer de colocar o ".text", o requests.get(url) retornará apenas a indicação de que houve uma resposta de tipo 200, que indica um retorno com sucesso. Isso ocorre proque, de fato, o comando requests.get(url) não retorna um texto, mas um objeto do tipo models.Response, que envolve todos os elementos do retorno dado pelo servidor, segundo o protocolo HTTP. Já se você trocar o ".text" por ".encoding", você obterá o tipo de codificação que a biblioteca requests identificou como sendo o encode da resposta do STF (no caso, será o encoding iso-8859-1). Se você quiser ver todos esses elementos, cole no Spyder o código abaixo e observe a tabela de valores.
import requests 

url = 'Insira o URL do processo que você escolheu'

response = requests.get(url)
codigo = response.encoding
html = response.text

print (html)
print (codigo)
print (response)
Módulo de extração expandido

2.5. Módulo de gravação de dados

Agora que você tem um módulo básico de extração de dados, é preciso aprender a gravá-los. A gravação em Python é um procedimento que exige a realização de 4 etapas:

  1. definir o nome do arquivo a ser gravado;
  2. abrir o arquivo a ser gravado;
  3. escrever os dados no arquivo aberto;
  4. fechar o arquivo.
import requests 

# Módulo básico de extração
url = 'Insira o URL que você escolheu'
html = requests.get(url).text

# Módulo básico de gravação
nomedoarquivo = 'ADI.html'
arquivoaberto = open(nomedoarquivo, 'w', encoding='utf-8')
arquivoaberto.write(html)
arquivoaberto.close()

O módulo de gravação realiza exatamente as 4 operações acima descritas:

  1. atribui à variável nomedoarquivo um valor que servirá como nome do arquivo a ser criado, o qual deve ser encerrado pela extensão ".html", para indicar que se trata de um arquivo de html. Você também pode gravá-lo como ".txt", o que fará com que você o abra mais facilmente com o bloco de notas. Porém, ao gravar como .html, você poderá abri-lo no Spyder ou no Pycharm, que vão mostrar as formatações em cores diferentes, seguindo o modelo de exibição dos códigos HTML;
  2. abre o arquivo no modo de escrever ('w' de write), utilizando a codificação  utf-8 (que reconhece acentos e cedilhas);
  3. escreve a string correspondente ao código fonte no arquivo aberto. Como foi escolhido o modo 'w', essa operação  sobrescreve qualquer conteúdo anteriormente gravado nesse arquivo. Se fosse utilizada a opção 'a', de add, o novo conteúdo seria acrescentado ao final.
  4. fecha o arquivo, o que é importante porque arquivos abertos consomem memória e estão sujeitos a serem sobrescritos.

2.6 Ajustando o diretório para gravação

Antes de seguir adiante, porém, é preciso fazer um pequeno polimento no seu extrator. Do modo como ele está feito, ele grava os arquivos com os dados extraídos no mesmo diretório em que estão os programas, o que vai gerar problemas para você, especialmente quando você tiver algumas extrações diferentes no mesmo diretório.

Para saber qual é o seu working directory, basta você observar o caminho que indica onde estão sendo gravados os seus programas, indicado pela seta na imagem abaixo.

Você também pode ver essa informação no Tools/Preferences/Current Working Directory, onde você também pode alterar o diretório de trabalho padrão do Spyder.

Para organizar adequadamente os dados, o melhor é que os seus programas fiquem no working directory, mas que os dados fiquem em diretórios específicos, que você precisa criar fora do Spyder, usando o programa de exploração de arquivos do seu sistema operacional.

Para que o algoritmo funcione adequadamente, é preciso atentar para dois detalhes. O primeiro é que você precisa incluir o caminho (path) para o diretório no nome do arquivo a ser gravado.  

Um detalhe que não pode ser descuidado é que o Python tem uma notação muito particular para a definição da árvore de diretórios. O DOS e o Windows usam o símbolo "\" para definir os ramos dessa árvore, gerando um path que tem um formato como o seguinte (que é o do arquivo na árvore do meu PC):

F:\Dropbox\Spyder\ADIhtml\ADI.html

Já o Python usa uma barra normal dupla, no lugar da barra invertida:

F://Dropbox//Spyder//ADIhtml//ADI.html

Você pode usar um caminho absoluto, como o path acima,  que comece indicando o nome do disco em que você pretende gravar (normalmente o drive C:, embora o meu working directory fique no drive F:) e indica o nome do arquivo juntamente com todo o caminho da árvore de diretórios.

Porém, é comum optarmos por uma saída mais simples: usar um caminho relativo (relative path), que indica apenas o caminho a partir do working directory (observe que começamos pelo nome do subdiretório e não pelas barras).

ADIhtml//ADI.html
import requests 

# Módulo básico de extração
url = 'Insira o URL que você escolheu'
html = requests.get(url).text

# Módulo básico de gravação
nomedoarquivo = 'ADIhtml//ADI.html'
arquivoaberto = open(nomedoarquivo, 'w', encoding='utf-8'))
arquivoaberto.write(html)
arquivoaberto.close()

Pronto, agora você tem o seu primeiro extrator! Com ele, você pode extrair dados de qualquer página da internet que você queira, e não apenas de URLs do STF. Basta tomar o cuidado de definir adequadamente o nome dos arquivos, para evitar que novas extrações apaguem os arquivos gravados por operações anteriores.

Para que esse extrator seja propriamente chamado de robô, ele deve ser capaz não apenas de extrair os dados das páginas que você define individualmente (objetivo que você poderia conseguir com os navegadores comuns), mas também deve ser capaz de repetir seguidas vezes essa operação de extração de dados, coletando informações de várias páginas em sequência. Com isso, saímos do campo dos extratores básicos para os robôs, que são extratores que operam mediante iteração.

3. Extração iterativa

Uma vez que você identificar que estão disponíveis informações que te interessam e que você é capaz de extrair as informações relevantes da página relativa a um dos objetos a serem analisados, você poder partir para a atividade que realmente interessa para a extração dos dados: iterar a sua busca, de modo que o seu programa seja capaz de extrair os dados de todos os objetos que compõem o seu universo de pesquisa.

Para que seja possível realizar essa iteração, você precisa compreender o modo como o site organiza as informações disponíveis, para que você possa criar um padrão de requisições que seja capaz de:

  1. buscar os dados de cada página, para depois
  2. gravá-los de modo organizado, permitindo que você crie um banco de dados relacional a partir dos dados não-estruturados que você vai obter com as requests.

3.1 Análise da estrutura de endereços

Iterar as buscas de páginas significa buscar várias páginas, uma de cada vez. Se o órgão judiciário disponibilizasse uma API, seria possível que ele criasse um sistema de busca que permitisse uma resposta agregada, que consolidasse os dados disponíveis em uma tabela. Essa, porém, não tem sido a prática do judiciário brasileiro, que disponibiliza apenas as buscas em suas páginas de acompanhamento processual e de jurisprudência.

Nesse contexto, criar um algoritmo que busque os dados de uma série de páginas exige que você desvende, inicialmente, o padrão de organização do site, possibilitando que você desenhe um algoritmo capaz de buscar todas as páginas de interesse para o seu universo.

Cada página da internet tem um url. A devida compreensão dos endereços é fundamental porque a nossa capacidade de extrair dados da internet vem, em grande medida, do fato de que os sites adotam sistemas bem definidos de endereçamento dos dados.

Para construir extratores, você precisa analisar cuidadosamente o site em que os dados a serem "raspados" estão disponíveis, para entender o sistema de ordenação dos dados utilizados pelo site. Cada site adota uma organização particular, cuja compreensão exige uma análise detida.

3.1.1 Elementos do URL

Tomemos, por exemplo o endereço da ADI 6000. Se você buscar por esse processo na pesquisa processual, chegará ao endereço:

http://portal.stf.jus.br/processos/detalhe.asp?incidente=5536310

Para entender esse endereço, primeiro é necessário segmentá-lo nas partes que os constituem.

Protocolo
http://portal.stf.jus.br/processos/detalhe.asp?incidente=5536310

Esquema de troca de informações, correspondente ao código que será utilizado na comunicação entre o seu computador e o servidor. HTTP (Hypertext Transfer Protocol) é o protocolo típico de páginas sem criptografia.

Domínio
http://portal.stf.jus.br/processos/detalhe.asp?incidente=5536310

O domínio indica o endereço do servidor no qual estão as informações. Servidor é o computador onde estão rodando os programas que oferecem publicamente as páginas da internet. São computadores ligados 24h por dia e conectados sempre à rede, para que os conteúdos hospedados neles sejam sempre visíveis.

Subdomínio
http://portal.stf.jus.br/processos/detalhe.asp?incidente=5536310

Essa parte antes do domínio indica um subdomínio, que é uma subdivisão do endereço do servidor.

Caminho (Path)
http://portal.stf.jus.br/processos/detalhe.asp?incidente=5536310

O caminho indica o local do servidor em que estão as informações buscadas.

Consulta (Querry)

http://portal.stf.jus.br/processos/detalhe.asp?incidente=5536310

Consulta: conjunto de parâmetros que possibilitam ao servidor identificar a página solicitada, entre as várias páginas alojadas naquele caminho.

A soma de todos esses elementos constitui um endereço que leva à página da ADI 6000 no STF.

Se você olhar o endereço desta página na barra de endereços, acima, verá uma conformação semelhante:

https://dsd.arcos.org.br/extraindodadosstf/

O protocolo muda de HTTP para HTTPS, que é um protocolo idêntico ao HTTP, mas com uma camada a mais de informação, permitindo a circulação de informações criptografadas. Por esse motivo, as páginas HTTPS aparecem com uma imagem de cadeado fechado ao lado.

O domínio é "arcos.org.br", sendo que o subdomínio "dsd" completa o endereço deste site, em que foi designado um subdomínio diferente para cada curso alojado nele.

Para chegar a este post, não se usa uma querry, pois basta indicar o seu caminho exato, sendo que esse caminho é chamando no Ghost de slug. É ele que definimos quando customizamos o endereço do post na aba de Post setting.

Para informações mais detalhadas sobre os URLs, bem como para a sua conexão com os IPs e os servidores DNS, consulte a página da UFSCar de conceitos básicos de Internet.

Os quatro primeiros endereços não te oferecem elementos para fazer uma querry com base nas informações classe e número, pois eles utilizam apenas uma consulta baseada na variável incidente, que é o indicador utilizado pelo sistema do STF para conferir um código numérico para cada processo.

Porém, o fato de que a ADO 333 não existe nos oferece uma chave adequada, visto que o URL da resposta a essa consulta reflete a querry feita na request:

?classe=ADO&numeroProcesso=333

Esse formato de querry nos oferece uma estrutura que podemos adaptar para outras classes processuais, substituindo ADO por ADI (ou por outro código de classe), e substituindo 333 por 444 (ou por qualquer outro número).

Esse exercício oferece um modelo de um URL que pode ser utilizado para buscar processos por meio da pesquisa de acompanhamento processual, que usa o path "/processos/detalhe.asp".

No caso das ADIs, ADPFs, ADCs e ADOs, existe uma outra página de informações, relativas unicamente às ações de controle concentrado e abstrato, contida no path: "/portal/peticaoInicial/pesquisarPeticaoInicial.asp".

Você deve ter notado que o padrão do URL deste path é diferente do padrão de endereçamento da pesquisa de acompanhamento processual:

http://www.stf.jus.br/portal/peticaoInicial/verPeticaoInicial.asp?base=ADI&documento=&s1=6058&numProcesso=6058

Essa querry é feita unindo (por meio do &) quatro parâmetros de consulta:

  1. base=ADI
  2. documento=
  3. s1=6058
  4. numProcesso=6058

Se você explorar um pouco esses parâmetros verá algumas coisas interessantes. Se você inserir o valor 1 no parâmetro documento (documento=1), a resposta trará um link para a petição inicial, o que seria interessante se o link funcionasse (ao menos as minhas tentativas não me levaram a links válidos).

Após algumas tentativas, você deve ter percebido que o s1 indica o processo que foi pesquisado na consulta da página. Alterá-lo não muda a página exibida (que é definda pelo parâmetro numProcesso), mas excluir esse parâmetro s1 conduz a erro no sistema.

Esses testes sugerem que você pode acessar qualquer ADI que tiver uma página própria nesse sistema por meio da alteração dos parâmetros 1 (base) e 4 (numProcesso).

3.2 Módulo gerador de URLs

Se você tiver alguma dificuldade com o Exercício 8, siga a leitura e veja se as sugestões feitas a seguir podem te ajudar a voltar ao exercício e completá-lo.

A primeira coisa a ter em mente é que esse algoritmo pode ser feito de várias formas. Você pode usar diferentes funções de iteração, mas a minha preferida é a for. E o modo pelo qual eu tenho construído esses extratores é definir duas variáveis que podemos alterar facilmente: NumeroInicial e NumeroFinal. O resultado da minha estratégia é:

Classe = "ADI"
NumeroInicial = 1
NumeroFinal = 10

for n in range (NumeroFinal-NumeroInicial+1):
    url = ('http://www.stf.jus.br/portal/peticaoInicial/verPeticaoInicial.asp?base='
           + Classe 
           + '&documento=&s1=1&numProcesso=' 
           + str(NumeroInicial+n))
    
    print (url)

Veja que colocamos o conteúdo da variável url entre parênteses, pois isso permite quebrar as linhas sem afetar a continuidade do texto (desde que você não quebre a linha dentro de uma string). Esse mesmo formato será adotado para outros campos com um código longo.

Para que essa construção funcione bem, é preciso estar atento a alguns detalhes. A Classe é uma variável string, então podemos somá-la com as strings que contém a parte inalterada da URL, e isso gera uma concatenação. Porém, precisamos que NumeroInicial e NumeroFinal sejam variáveis integer, pois necessitamos delas para definir o  operações matemáticas com elas, sem as quais o iterador não funciona.

Inclusive, você notará que o fato de o Python considerar o valor inicial de "n" como 0, e não como 1, tem uma vantagem em nosso algoritmo: podemos usar "NumeroInicial + n" como sendo a fórmula para definir o número do processo a ser inserido no URL. Nesse caso, é preciso apenas ter o cuidado de transformar o int em str, para poder usar esse número como um nome (que de fato é a função do número na designação dos processos).

O outro cuidado a tomar é que, na definição do range, é preciso somar 1 à diferença entre o NumeroFinal e o NumeroInicial, pois queremos incluir o número final no intervalo a ser buscado (que é de 10 ações e não de 9).

Por fim, devo ressaltar que existem formas mais elegantes de definir a URL (por exemplo, usando {} para entremear a string com as variáveis), mas creio que é mais interessante começar pelo uso do conector +, que deixa muito claro qual é a operação realizada nessa construção e facilita a compreensão da necessidade de converter em string o último valor.

3.3 Módulo de Geração de URLs + Módulo de Gravação

Unindo os módulos de geração de URLs e de Gravação, você terá um resultado semelhante ao algoritmo abaixo. Note que, nesse caso, eu criei uma variável específica para conter uma string com o Número do Processo (calculada com a soma de NumeroInicial + n), para facilitar a sua inserção no URL e no nome do arquivo.

import requests 

# Definição dos parâmetros de busca
Classe = "ADI"
NumeroInicial = 1
NumeroFinal = 10

for n in range (NumeroFinal-NumeroInicial+1):
    
    # Módulo de geração de URLs
    NumProcesso = str(NumeroInicial+n)
    url = ('http://www.stf.jus.br/portal/peticaoInicial/verPeticaoInicial.asp?base=' 
           + Classe 
           + '&documento=&s1=1&numProcesso=' 
           + NumProcesso)
    print (url)
    
    # Módulo básico de extração
    html = requests.get(url).text
    
    # Módulo básico de gravação
    nomedoarquivo = 'ADIhtml\\' + Classe + NumProcesso + '.html'
    arquivoaberto = open(nomedoarquivo, 'w', encoding='utf-8')
    arquivoaberto.write(url + ", " + html)
    arquivoaberto.close()

3.4 Finalmente o Extrator completo!

Agora que você tem todos os módulos em mãos (Gerador de URL, Extração de dados e Gravação), basta acoplá-los e fazer os últimos ajustes.

No código abaixo, que realiza essa função, você notará que foi mantido o print(url), porque esse print nos dá a exata dimensão do andamento do trabalho, o que é especialmente útil quando você buscar 1000 processos, em vez de 10. Porém, não faz sentido manter um print(html), visto que essa impressão onera a capacidade de processamento sem trazer benefícios.

A ordem da extração também foi invertida, começando do NumeroFinal, pois normalmente a nossa prioridade é alcançar os processos mais recentes.

Também foi adicionado um código para inserir zeros antes do número, a depender de quantos dígitos tem o NumProcesso. Isso é feito para que a ordem alfabética dos nomes dos arquivos seja a mesma ordem dos números. Quando não tomamos essa precaução, a ADI59 viria antes da ADI9, o que gera problemas para identificar os processos nos diretórios.

Uma inovação desse código, com relação aos anteriores, foi a definição do que deve ser escrito no arquivo: o conteúdo da variável string url + o conteúdo da variável string html, separados por uma vírgula. No lugar da vírgula, você pode usar outros separadores (veja que, na versão final, uso >>>> seguidos de uma quebra de linha (cujo símbolo é \n).

Outra inovação foi inserir a classe no nome do arquivo, para que você possa explorar novas classes sem precisar alterar o código.

import requests 

# Definição dos parâmetros de busca
Classe = "ADI"
NumeroInicial = 1
NumeroFinal = 10

for n in range (NumeroFinal-NumeroInicial+1):
    
    # Módulo de geração de URLs
    NumProcesso = str(NumeroFinal-n)
    url = ('http://www.stf.jus.br/portal/peticaoInicial/verPeticaoInicial.asp?base=' 
           + Classe 
           + '&documento=&s1=1&numProcesso=' 
           + NumProcesso)
    print (url)
    
    # Módulo básico de extração
    html = requests.get(url).text
    
    # Módulo básico de gravação
    nomedoarquivo = ('ADIhtml\\' 
                     + Classe 
                     + str(0)*(4-len(NumProcesso)) 
                     + NumProcesso 
                     + '.html')
    arquivoaberto = open(nomedoarquivo, 'w', encoding='utf-8')
    arquivoaberto.write(url + ", " + html)
    arquivoaberto.close()

Pronto! Agora você tem um extrator funcional e pode fazer buscas que não se limitam a 10 processos.

Para completar, basta alterar o nome de gravação para inserir zeros antes dos números das primeiras ADIs, de forma a que a ordem alfabética corresponda à ordem numérica das ações.

Quando você faz extrações maiores, de centenas de processos, é comum que o STF derrube a sua conexão em algum ponto. Assim, você precisará acompanhar quais foram as ações já processadas para o NumeroInicial, a cada vez que tiver de retomar os trabalhos. O próximo passo é aprender a transformar essa sua base de dados não-estruturados em uma base de dados relacional, o que faremos no próximo módulo.

Mas, antes disso, faremos um último ajuste: você já tinha notado que os dados referentes ao processo começam por volta da linha 1260. Antes disso, há códigos ligados ao formato geral da página (cabeçalhos, barras laterais, menus...), que são idênticos para todos os processos e que, por isso, não nos interessam enquanto elementos a serem analisados.

Entendo que faz sentido você ter um banco de dados não relacional, composto pela série de arquivos com as informações de cada processo, pois você poder tratá-las de formas diferentes. Porém, não há sentido em você gravar a mesma informação milhares de vezes, motivo pelo qual a versão final do extrator insere um ponto de corte, gravando somente as informações posteriores à linha 1252, onde ocorre a primeira informação relevante: o número do incidente, que é o identificador individual usado pelo STF.

Com isso, a versão final do extrator, disponível também no menu de Códigos (na parte superior das páginas do site) fica sendo o algoritmo abaixo.

4. Código do Extrator Básico

import requests 

# Definição dos parâmetros de busca
Classe = "ADI"
NumeroInicial = 5500
NumeroFinal = 6000

for n in range (NumeroFinal-NumeroInicial+1):
    
    # Módulo de geração de URLs
    NumProcesso = str(NumeroFinal-n)
    
    url = ('http://www.stf.jus.br/portal/peticaoInicial/'
           + 'verPeticaoInicial.asp?base='
           + Classe 
           + '&documento=&s1=1&numProcesso=' 
           + NumProcesso)
    
    print (url)
    
    # Módulo básico de extração
    html = requests.get(url).text

    
    # redução do texto às variáveis
    inicio = html.find('processo/verProcessoAndamento.asp?')
    html = html[inicio:]
    
    # Módulo básico de gravação
    nomedoarquivo = ('ADIhtml\\' 
                     + Classe 
                     + str(0)*(4-len(NumProcesso)) 
                     + NumProcesso 
                     + '.html')
    
    arquivo = open(nomedoarquivo, 'w', encoding='utf-8')
    arquivo.write(url + ">>>> \n" + html)
Código para extração de dados das páginas de metadados do controle concentrado

O código acima deixa os andaimes à mostra, para que você possa compreendê-lo totalmente. Uma vez entendido, podemos polir um pouco esse código para deixá-lo mais legível e apropriável por pessoas que não têm o domínio total da programação.

Para fazer isso, vamos modificar alguns pontos do código, criando duas funções com nomes intuitivos.

  1. Função de solicitar os dados ao servidor do STF
  2. Função de gravar o arquivo com os dados
import requests 

# Definição dos parâmetros de busca
Classe = "ADI"
NumeroInicial = 5500
NumeroFinal = 6000

# define as funções    
def solicitar_dados_CC (classe, numero):
    url = ('http://www.stf.jus.br/portal/peticaoInicial/verPeticaoInicial.asp?base=' 
           + classe 
           + '&documento=&s1=1&numProcesso=' 
           + numero)
    print (url)
    # Módulo básico de extração
    string = requests.get(url).text
    inicio = string.find('processo/verProcessoAndamento.asp?')
    return (url + ">>>>> \n" + string[inicio:])
 
def gravar_dados_no_arquivo (classe, numero, path, dados):
    nomedoarquivo = (path + classe + str(0)*(4-len(numero)) + numero+ '.html')
    arquivo = open(nomedoarquivo, 'w', encoding='utf-8')
    arquivo.write(dados)

# realiza a extração dos dados e a gravação    
for n in range (NumeroFinal-NumeroInicial+1):
    
    # define número do processo a ser buscado
    NumProcesso = str(NumeroFinal-n)
    
    # busca dados do processo definido por classe e número, no banco do CC
    dados = solicitar_dados_CC (Classe, NumProcesso)
       
    # grava dados no arquivo definido
    gravar_dados_no_arquivo(Classe, NumProcesso,'ADIhtml//teste', dados)

Esse código realiza exatamente as mesmas operações do anterior, mas ele permite o isolamento das funções, que podem ser então gravadas em um módulo específico para as funções, que chamei de dsd.py.

Esse é um módulo de funções que deve estar gravado no diretório em que estiver gravado o arquivo com o extrator (normalmente será o seu diretório de trabalho). Com esse arquivo devidamente gravado no seu diretório de trabalho, o seu código pode ter o seguinte formato:


# Definição dos parâmetros de busca
Classe = "ADI"
NumeroInicial = 5500
NumeroFinal = 6000

# Definição do diretório para gravar os dados
path = 'ADIhtml//'

# realiza a extração dos dados e a gravação    
for n in range(NumeroFinal-NumeroInicial):
    
    # define número do processo a ser buscado
    NumProcesso = str(NumeroFinal-n)
    print(NumProcesso)
    
    # busca dados do processo definido por classe e número, no banco do CC
    dados = dsd.solicitar_dados_CC (Classe, NumProcesso)
       
    # grava dados no arquivo definido
    dsd.gravar_dados_no_arquivo(Classe, NumProcesso, path, dados)

Se você conseguiu compreender este código, pode avançar para o Gerador de CSV Básico , onde você aprenderá algumas funções que serão necessárias para seguir para o Extrator de HTML Intermediário. Se você não o entendeu totalmente, as chaves para essa compreensão estão neste texto e no curso Python para Juristas.