Por que estudo Python?

      1 comentário em Por que estudo Python?

Parece estranho ver um filósofo, cujo foco de pesquisa é a Epistemologia Genética, estudando uma linguagem de programação de computadores. Mas, apesar da estranheza é muito plausível e aqui pretendo explicar o porquê!

Uma das tarefas que temos, ao realizar uma pesquisa filosófica, é estabelecer o estado da arte, ou seja, fazer o levantamento do que já foi publicado sobre a temática em questão e averiguar quais os rumos foram dados pelos autores das publicações encontradas.

Uma das formas de se fazer esse levantamento é acessando o site do Banco de Teses e Dissertações da CAPES, órgão do governo brasileiro responsável pela expansão e consolidação da pós-graduação stricto sensu no país. Mas convenhamos, fazer isso de forma manual é, no mínimo, enfadonho e muito, mas muito demorado. Assim, seria muito mais interessante se esse processo de pesquisa pudesse ser automatizado. E, claro, com Python isso sim é possível de ser feito, e vamos explanar como implementamos essa funcionalidade em Python para nos auxiliar.

Digamos que, por conta de meus interesses de pesquisa, eu queira levantar tudo que fora produzido até hoje nas pós-graduções brasileiras com os descritores: “Epistemologia Genética”, “Psicologia Genética” e Piaget. Sem ser de forma automatizada, deveríamos entrar no site do Banco de Teses e Dissertações da CAPES, colocar esses descritores no campo de pesquisa para averigar o resultado como vemos na imagem abaixo:

Busca no site do Banco de Teses e Dissertações da CAPES

Busca no site do Banco de Teses e Dissertações da CAPES

Como podemos ver na imagem, a busca retorna um total de 1820 resultados e ficar navegando página por página e baixando um por um desses documentos e/ou informações seria uma perda de tempo considerável. Assim, vamos ver como fazer isso de uma forma automatizada com Python.

Para ser um pouco mais didático, vou apresentar parte por parte do código que escrevi, mas isso tudo fica num único arquivo que chamamos de módulo python.

O Python, como a comunidade gosta de enfatizar, tem as baterias inclusas, isto é, você instala em seu computador (nesse post mostro como instalar o Python com o Pyenv) e já pode usar pois ele já traz consigo muitas funcionalidades sem a necessidade de instalar novas coisas.

Contudo, como a comunidade Python é muito ativa, sempre existe funcionalidades que auxiliam naquilo que você precisa automatizar e, no nosso caso, vamos precisar do módulo Requests que nos auxiliará na busca das informações no site da CAPES em questão. Para isso, caso não tenha instalado basta fazer:

pip install requests

Pronto, o que mais vamos utilizar é bateria inclusa no Python, assim nosso módulo começa com a importação das seguintes baterias::

import requests
import json
import math

O módulo Requests nos auxiliará nas chamadas http, como seu slogan diz HTTP for Human (HTTP para Humanos), o módulo JSON nos auxiliará no tratamento do JavaScript Object Notation (Notação de Objetos JavaScript) e o módulo Math com operações matemáticas mais complexas.

Bom, uma das coisas que precisamos é saber qual a URL que faz a pesquisa no site da CAPES e como ela passa os parâmetros de pesquisa. Para isso, acessamos o site, fazemos uma busca para testes e, preferencialmente no Google Chrome por conta dele fornecer o Ferramentas do Desenvolvedor que pode ser acionado por F12 ou por Ctrl+Shift+I. Assim, entramos no site, abrimos o Ferramentas do Desenvolvedor, na aba Network, e fazemos nossa pesquisa. O Ferramentas do Desenvolvedor, aba Network, nos dá várias informações, as que nos interessam estão marcadas com setas vermelhas na figura abaixo:

Ferramentas do Desenvolvedor do Google Chrome, aba Network

Ferramentas do Desenvolvedor do Google Chrome, aba Network

Isso nos mostra que a requisição HTTP feita pelo navegador ao servidor é:

http://bancodeteses.capes.gov.br/banco-teses/rest/busca

E que essa requisição (que é invisível se só fizermos pelo navegaor, só o Ferramentas do Desenvolver do Chrome que nos mostra essa ação) precisa de um payload em JSON como abaixo:

{termo: "Piaget", filtros: [], pagina: 1, registrosPorPagina: 20}

Esse JSON carrega, para a requisição feita, as seguintes informações:

  • termo: o que foi digitado no campo de pesquisa (no exemplo a palavra “Piaget”);
  • filtros: caso seja selecionado algum dos filtros eles entram aqui. Por exemplo, se quisésssemos filtrar pelo ano de publicação ficaria:
filtros: [{"campo": "Ano", "valor": "2014"}]
  • pagina: que trás o número da página do resultado, no caso vem com o número 1, por ser a primeria página apresentada;
  • registrosPorPagina: que trás a quantidade de registros que são apresentados por página.

Como resposta, temos um outro JSON, ele traz bastante informação, mas o que vamos precisar para trabalhar será o que segue:

{"pagina":1,
 "registrosPorPagina":20,
 "total":1667,
 "tesesDissertacoes":[{"id":"xx",
 "instituicao":"xx",
 "nomePrograma":"xx",
 "municipioPrograma":"xx",
 "titulo":"xx",
 "autor":"xx",
 "dataDefesa":"xx",
 "volumes":"xx",
 "paginas":"xx",
 "biblioteca":"xx",
 "grauAcademico":"xx",
 "link":"xx"}]
...
}

Primeiro, os ‘xx’ nos valores dos campos é só para manter integridade, não é o retornado, claro , mas não quis deixar dados sensíveis aqui. Acredito que cada campo seja auto-explicativo o que nos dispensa de falar de item por item, vou só destacar alguns. Os três pontos ao final indicam que existem mais informações no JSON retornado, mas que não nos serão úteis nesse processo. Nos dois primeiros itens, é o que temos na payload da requisição, que são o número da página em que estamos e a quantidade de registros por página O terceiro é bem importante, pois nos dá a quantidade total de registros retornados. Lembrando que estamos com um programa-robo que está buscando as informações na página para nós, ele tem que saber quantas páginas temos no total, já que o nosso retorno é de 20 registros por página. O quarto registro é composto e nos retorna todas as informações da Tese ou Dissertação, claro que esse é que estará na quantidade de 20 por página.

Pois bem, de posse dessas informações, vamos continuar com nosso programa-robo para automatizar essa pesquisa. Como vimos mais acima, temos já três módulos importados para nosso aplicativo requests, json e math. Vamos agora montar as variáveis globais do nosso namespace, para isso fazemos as seguintes declarações:

URL = 'http://bancodeteses.capes.gov.br/banco-teses/rest/busca'
HEADERS = {'Content-type': 'application/json', 'Accept': 'text/plain'}
DATA = {'termo': '"Piaget"', 'registrosPorPágina': 20}

Nada muito complexo, mas essas são as informações que usaremos para fazer o request dos dados. A URL é o link da busca, HEADERS traz as informações de cabeçalho e DATA é nosso payload, note que não estamos informando o filtro (esse só se necessário) e nem a página, essa será adcionada mais adiante no nosso código.

Na sequência definimos uma função chamada fetch_page que recebe o número de página como parâmetro. O código da função é como segue:

def fetch_page(page_number):
    payload = DATA.copy()
    payload['pagina'] = page_number

    while True:
        response = requests.post(URL, headers = HEADERS, data = json.dumps(payload))
        if 200 <= response.status_code < 300:
            return response.json()
        else:
            print(response.status_code)
            continue

Ao ser chamada a função fetch_page primeiro faz uma cópia de nosso DATA, para poder manipulá-lo sem alterá-lo. em seguida insere nessa cópia a informação do número de página em que está trabalhando, que é o parâmetro passado à função. Agora vem o pulo do gato. Em testes realizados, sempre que fizemos várias requisições para obtermos as páginas de dados retornadas pela URL experimentávamos uma excessão. Descobrimos, nos testes, que em determinado momento a resposta retornava um HTTP Code 500, que é um erro interno do servidor. Não temos a razão disso, mas descobrimos que ao obter esse erro se refizessemos a consulta com os mesmos dados teríamos a informação solicitada. Assim, para contornar esse problema colocamos a requisição dentro de um laço de repetição while com a condição em True, isso faz um laço infinito, mas a saída do laço se dá pelo return response.json(), caso o HTTP Code estiver entre 200 ou 300, que são códigos de requisições bem sucedidas. Caso dê erro, que será HTTP Code 500, o laço continua até termos as informações que precisamos. Veja que a requisição é feita pela função requests.post (por isso importamos o módulo requests) e ela recebe um parâmetro posicional que é o URL (parâmetro posicional é aquele que é passado pela posição do mesmo na chamada da função, no nosso caso específico a URL deve ser o primeiro parâmetro passado à função requests.post) e dois parâmetros nomeados (que são os parâmetros que passamos não só seu valor como também seu nome) que no nosso caso específico são os parâmetros headers, para o qual passamos a variável HEADERS e data para a qual passamos a variável payload, note que não passamos a varíavel simplesmente, mas temos aqui que utilizar a função json.dumps que converte o dicionário python (para saber mais sobre dicionários) que é nossa variável payload para um objeto JSON, por isso importamos o módulo json.

Em seguida, definimos a função get_total_pages que recebe os dados da respsota, verifica qual é o total de Teses e Dissertações que foram retornadas e usa a função math.ceil  (é por isso que precisamos importar o módulo math) para calcular o total de páginas que temos que pesquisar, lembrando que temos sempre 20 registros por página. Apesar de nesse caso o número de registros por página ser fixo trabalhamos com variáveis para tornar o código reaproveitável.

def get_total_pages(response):
    total = response['total']
    per_page = response['registrosPorPagina']
    return math.ceil(total / per_page)

Bom, agora faremos um pequeno código para teste do que fizemos até agora, o código é o seguinte:

if __name__ == '__main__':

    total = 1
    current = 1
    output = []

    while current <= total:
        response = fetch_page(current)
        if current == 1:
            total = get_total_pages(response)
        for dissertation in response['tesesDissertacoes']:
            output.append(dissertation)
        current += 1  

    print(output[0])

Primeiro testamos se estamos executando o módulo como principal, por isso a cláusula if no início do código. Em seguida definimos nossas variáveis: total que terá o total de páginas calculados pela função get_total_pages, current que será incrementada com o valor da página atual, e a lista output que armazenará todo o resultado obtido para manipularmos.

Em seguida iniciamos um laço de repetição que executará o bloco de código enquanto current for menor que total, ou seja, da página 1 até a página final dos dados retornados. O primeiro comando a ser executado no laço de repetição é o response =  fetch_page(1), que fará a requisição na URL com a primeira página, em seguida faz a verificação e se current for igual a 1, chama a função get_total_pages, passando response para obter o total de páginas que precisaremos pesquisar. Em seguida fazemos um novo laço de repetição usando o comando for para colocar os dados em nossa variável output, em seguido incrementamos current em 1, isso fará o laço while continuar para a página seguinte, assim até alcaçar a última página e fazer a busca de todas as informações que serão armazenadas, nesse caso na nossa variável output.

Quando isso finalizar, fazemos a impressão do primeiro item armazenado em output com o comando print(output[0]) isso só para um teste.

Claro, agora após fazermos testes exaustivos, poderemos sim, em vez de só imprimir o primeiro item da variável output poderemos salvar essas informações num arquivo para consulta futura. Pode ser um arquivo texto mesmo ou até um Banco de Dados. Mas isso foge ao nosso escopo, pois só pretendemos apresentar a utilidade de se estudar Python, mesmo sendo de outra área de formação.

Quero externar meus agradecimentos ao Eduardo Cuducos que analisou e contribuiu com grandes sugestões para a melhoria do código aqui apresentado.

Espero que tenham gostado desse artigo.

 

About Prof. Vicente E. R. Marçal

Professor Adjunto do Departamento de Filosofia da Universidade Federal de Rondônia. Doutorando em Psicologia Social pelo Instituto de Psicologia da USP. Mestre em Filosofia pela Universidade Estadual Paulista/Campus Marília. Especialista em Filosofia Moderna e Contemporânea: Aspectos Éticos e Jurídicos pela Universidade Estadual de Londrina. Licenciado em Filosofia pela Universidade Estadual de Londrina. Coordenador do GEPEGRA - Grupo de Estudos e Pesquisa em Epistemologia Genética da Região Amazônica. Com experiência em Filosofia, com ênfase em Epistemologia e Teoria do Conhecimento.

1 thought on “Por que estudo Python?

  1. Iago Cavalcante

    Muito bom o post, é muito interessante ver pessoas fora da área de TI buscando um auxilio da mesma para contribuir com sua profissão de origem.

    Reply

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

This site uses Akismet to reduce spam. Learn how your comment data is processed.