Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cria spider para Duque de Caxias RJ no padrão atual do projeto #1333

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

slfabio
Copy link
Collaborator

@slfabio slfabio commented Dec 15, 2024

AO ABRIR uma Pull Request de um novo raspador (spider), marque com um X cada um dos items da checklist abaixo. Caso algum item não seja marcado, JUSTIFIQUE o motivo.

Layout do site publicador de diários oficiais

Marque apenas um dos itens a seguir:

  • O layout não se parece com nenhum caso da lista de layouts padrão
  • É um layout padrão e esta PR adiciona a spider base do padrão ao projeto junto com alguns municípios que fazem parte do padrão.
  • É um layout padrão e todos os municípios adicionados usam a classe de spider base adequada para o padrão.

Código da(s) spider(s)

  • O(s) raspador(es) adicionado(s) tem os atributos de classe exigidos.
  • O(s) raspador(es) adicionado(s) cria(m) objetos do tipo Gazette coletando todos os metadados necessários.
  • O atributo de classe start_date foi preenchido com a data da edição de diário oficial mais antiga disponível no site.
  • Explicitar o atributo de classe end_date não se fez necessário.
  • Não utilizo custom_settings em meu raspador.

Testes

  • Uma coleta-teste da última edição foi feita. O arquivo de .log deste teste está anexado na PR.
  • Uma coleta-teste por intervalo arbitrário foi feita. Os arquivos de .loge .csv deste teste estão anexados na PR.
  • Uma coleta-teste completa foi feita. Os arquivos de .log e .csv deste teste estão anexados na PR.
    completa.csv
    completa.log
    intervalo.csv
    intervalo.log
    ultima.csv
    ultima.log

Verificações

  • Eu experimentei abrir alguns arquivos de diários oficiais coletados pelo meu raspador e verifiquei eles conforme a documentação não encontrando problemas.
  • Eu verifiquei os arquivos .csv gerados pela minha coleta conforme a documentação não encontrando problemas.
  • Eu verifiquei os arquivos de .log gerados pela minha coleta conforme a documentação não encontrando problemas.

Descrição

Resolve #616

Atualiza o código do PR #705 para o padrão atual do projeto, coletando todos os atributos do gazette.

Obs. Foi utilizada a data inicial de 02/01/2017, pois as versões anteriores não disponibilizam a data da edição. Os diários anteriores a 2017 exibem apenas a data de modificação do arquivo, que não tem relação com a data de publicação do diário.

Obs2. Revisar esse PR anrtes do #1323, pois se for integrada a função extract_date no utils, eu modificarei o código do spider de Campos-RJ para usar o método do utils.

Adiciona a função extract_date no utils do projeto para fazer o parse das datas escritas por extenso, corrigindo eventuais erros de digitação no mês.

O código utiliza a biblioteca fuzzywuzzy, que usa o algoritmo de distância Levenshtein para medir a semelhança entre duas strings e, a partir da lista de meses, selecionar o mês com a grafia correta antes de fazer o dateparser.

Para usar o fuzzywuzzy, é necessário instalar 2 bibliotecas ao projeto: fuzzywuzzy e python-Levenshtein

@firefueled firefueled mentioned this pull request Dec 17, 2024
5 tasks
Copy link

@firefueled firefueled left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valeu @slfabio .
Tem algumas coisinhas para fazermos antes de aceitar.
Favor ver comentários.

Outra coisa, em relação ao que disse aqui:

Foi utilizada a data inicial de 02/01/2017, pois as versões anteriores não disponibilizam a data da edição. Os diários anteriores a 2017 exibem apenas a data de modificação do arquivo, que não tem relação com a data de publicação do diário.

Apesar da data da edição de diários antigos não estar explicita na página que contém os links para baixar, é possível extraí-la atraéz da url final para o diário.
Por exemplo: https://duquedecaxias.rj.gov.br/portal/boletim-oficial/2014/07-Julho/6148-15.pdf
O ano, mês, e dia estão aí. O dia é o número após a edição.

Isso não implica na não aceitação desta PR, mas significa que teremos que escrever outro raspador para pegar aqueles restantes.

Comment on lines 46 to 70
def extract_date(text):
"""Extract a date from a text. This method attempts to correct typing errors in the month.

Args:
text: A text containing a date with the name of the month full version (%B)
Returns:
The date, if match. Otherwise, returns None.
"""

text = re.sub(" +", " ", text).strip()
match_date = re.search(r"\d{1,2}º?(\sde)? +(\w+)(\sde)? +\d{4}", text)
if not match_date:
return None

raw_date = match_date.group(0)
raw_date = raw_date.replace("º", "").replace("°", "")
month = match_date.group(2)
if month.lower() not in MONTHS:
match_month, score = process.extractOne(month, MONTHS)
if score < 70:
return None
raw_date = raw_date.replace(month, match_month)

parsed_datetime = dateparser.parse(raw_date, languages=["pt"])
return parsed_datetime.date() if parsed_datetime else None

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gostei da ideia.
O formato de data que definiu é genérico o suficiente para que seja útil para outros.

Seria bom saber se existe uma necessidade real. Quantas ocorrências de erros de digitação na data você encontrou na base inteira de diários deles?

Eu mudaria o nome do método para deixar claro exatamente o que ele faz. Indicando que ele recebe um texto por extenso E utiliza um fuzzy match para evitar erros de digitação.
Algo como date_from_text_with_fuzzy_match?

Copy link
Collaborator Author

@slfabio slfabio Feb 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Esse é um problema recorrente em municípios que utilizam data por extenso (Ex: Duque de Caxias/RJ, Barra Mansa/RJ, Campos/RJ)

Até deixei esse comentário na issue de Campos/RJ (#1323 (comment)) para saber o que vocês acham da solução.

Sobre a quantidade de ocorrências, eu posso testar novamente nesses 3 municípios para saber, acho que não chega a 10 edições para cada município, mas pra mim o principal é que mesmo que seja pontual, o problema ocorre em diversos municípios e a há uma solução simples de contorno.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vou aguardar a definição desse item para corrigir os outros apontamentos.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Entendido.
Concordo que vale a pena implementar essa estratégia.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alterado nome da função alterado.

import re

import dateparser
from fuzzywuzzy import process

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Todas as novas bibliotecas precisam ser adicionadas no requirements.in para que outros dev tenham acesso.
Inclusive a que mencionou na descrição: python-Levenshtein

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alterações realizadas nos arquivos de requirements.



class RjDuqueCaxiasSpider(BaseGazetteSpider):
name = "rj_duque_caxias"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Colocamos o nome inteiro do município no nome do arquivo. 😛
Adicione o _de_ que faltou para ficar duque_de_caxias.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrigido.


def parse(self, response):
pdf_divs = response.xpath(
"//i[contains(@class, 'fa-file-pdf')]/ancestor::div[1]"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Boa sacada de buscar por um filho para pegar o pai.

return

raw_gazette_edtion = pdf_div.xpath("./preceding-sibling::div[2]/text()")
is_extra_edition = bool(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@slfabio Eu vi vários diários com o termo "vol2". Não parece que eles são edições extra porque isso não está explícito no seu conteúdo.
Você conseguiu entender o que eles são? Será que são uma continuação?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exatamente. São a continuação de uma mesma edição.

@firefueled
Copy link

Tarefa criada para os diários antigos, caso aceitemos esta PR sem fazer isso.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obrigado pelas mudanças! Faltou só modificar o nome do arquivo em si. Para rj_duque_de_caxias.py

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feito!

Cria spider para Duque de Caxias / RJ
Copy link

@firefueled firefueled left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bala!

@firefueled
Copy link

@trevineju pode juntar essa!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: novo
Development

Successfully merging this pull request may close these issues.

Duque de Caxias-RJ
2 participants