Skip to main content

HTTP automation package for DTP and DAMSP portals.

Project description

botdtp

Pacote de automacao para os portais SGPT e DAMSP da Prefeitura de Sao Paulo.

O que o projeto entrega

  • SGPTBot: login, alteracao de senha, comprovante de inspecao, aprovacao/reprovacao e relatorios.
  • DAMSPBot: fluxos CPF/CNPJ, emissao de licenca PF/PJ e guia PF/PJ.
  • HTTPClient + HTTPConfig: retry, timeout, proxy, sleep entre requests, sessao e echo de payloads.
  • Persistencia de sessao em arquivo (SessionStore) com TTL (SGPT).
  • Janela de acesso configuravel por dia/hora/fuso (SGPT).

Arquitetura (serie 0.5.x)

A arquitetura foi separada por camadas para facilitar manutencao, testes e evolucao:

  • botdtp.core: contrato central ResultadoOperacao, erros compartilhados e politica de acesso SGPT.
  • botdtp.sgpt: autenticacao, operacoes de inspecao e relatorios do SGPT.
  • botdtp.damsp: fluxos CPF/CNPJ, regras de servico/modalidade e resolucao de captcha.
  • http_ops: transporte HTTP generico (session, retry, timeout, proxy e persistencia opcional).
  • aspx_ops: operacoes ASPX reutilizaveis (__VIEWSTATE, postback, timeline e navegacao).

Essa separacao permite evoluir fluxos de negocio sem acoplar com detalhes de transporte e WebForms.

Requisitos

  • Python >=3.11

Instalacao

pip install botdtp

Dependencias

Dependencias diretas do pacote (em pyproject.toml):

  • requests>=2.32.0
  • beautifulsoup4>=4.12.0
  • lxml>=5.2.0
  • pillow>=10.0.0
  • langchain-core>=0.3.0
  • langchain-openai>=0.2.0
  • validate-docbr>=1.11.1
  • xhtml2pdf>=0.2.17

Contrato padrao de retorno

Toda operacao retorna ResultadoOperacao:

  • ok: bool
  • mensagem: str
  • data: dict

Comportamento em falha:

  • Operacoes publicas de Bot e Client retornam ResultadoOperacao(ok=False, ...).
  • Nao ha propagacao de excecao para o chamador nesse contrato padrao.
  • Em erros, data inclui operacao, classe e detalhe.

Uso de alto nivel (recomendado)

SGPTBot

from botdtp import SGPTBot
from botdtp.sgpt import (
    SGPTLoginInput,
    SGPTAlterarSenhaInput,
    SGPTComprovanteInspecaoInput,
    SGPTAprovacaoEscolarAnualInput,
    SGPTAprovacaoEscolarSemestralInput,
    SGPTAprovacaoTaxiInput,
    SGPTReprovacaoEscolarAnualInput,
    SGPTReprovacaoEscolarSemestralInput,
    SGPTReprovacaoTaxiInput,
    SGPTItemReprovacaoInput,
    SGPTRelatorioInput,
)

login = SGPTLoginInput(
    codigo_empresa="CODIGO_DA_EMPRESA",
    usuario="USUARIO",
    senha="SUA_SENHA",
)

sgpt = SGPTBot(login=login, reautenticar=True)

sgpt.autenticar(login)

sgpt.alterar_senha(
    SGPTAlterarSenhaInput(
        codigo_empresa="0035",
        usuario="123456",
        senha_atual="SENHA_ATUAL",
        nova_senha="SENHA_NOVA",
        confirmacao_nova_senha="SENHA_NOVA",
    )
)

sgpt.gerar_comprovante_inspecao(
    SGPTComprovanteInspecaoInput(
        numero_guia="055721",
        ano_guia="2026",
        resultado="APROVADA",
    ),
    destino="tmp",
    nome_arquivo="comprovante_guia_055721.pdf",
    echo_post=True,
    echo_get=False,
)

sgpt.aprovar_escolar_anual(
    SGPTAprovacaoEscolarAnualInput(
        placa="ABC1234",
        licenca="12345678",
        inspetor_codigo="111",
        inspetor_nome="INSPETOR",
        rt_codigo="222",
        rt_nome="RESPONSAVEL TECNICO",
        ano_guia="0000",
        numero_guia="00000",
        validade_extintor="00/0000",
        sn_tacografo="S",
    ),
    destino="tmp",
    nome_arquivo="comprovante_escolar_anual.pdf",
)

sgpt.aprovar_escolar_semestral(
    SGPTAprovacaoEscolarSemestralInput(
        placa="ABC1D23",
        licenca="12345678",
        inspetor_codigo="111",
        inspetor_nome="INSPETOR",
        rt_codigo="222",
        rt_nome="RESPONSAVEL TECNICO",
        validade_extintor="12/2026",
        sn_tacografo="S",
    ),
    destino="tmp",
    nome_arquivo="comprovante_escolar_semestral.pdf",
)

sgpt.aprovar_taxi(
    SGPTAprovacaoTaxiInput(
        placa="ABC1234",
        licenca="12345678",
        inspetor_codigo="111",
        inspetor_nome="INSPETOR",
        rt_codigo="222",
        rt_nome="RESPONSAVEL TECNICO",
        ano_guia="2026",
        numero_guia="055721",
        radio_taxi_cod="",
        radio_taxi_nome="",
    ),
    destino_comprovante="tmp",
    nome_arquivo="comprovante_taxi.pdf",
)

itens = [
    SGPTItemReprovacaoInput(
        grupo="X",
        item="X",
        subitem="X",
        valor="X",
        opcao="X",
        descricao="XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    )
]

sgpt.reprovar_escolar_anual(
    SGPTReprovacaoEscolarAnualInput(
        placa="ABC1234",
        licenca="12345678",
        inspetor_codigo="111",
        inspetor_nome="INSPETOR",
        rt_codigo="222",
        rt_nome="RESPONSAVEL TECNICO",
        ano_guia="2026",
        numero_guia="055721",
        itens_reprovacao=itens,
    )
)

sgpt.reprovar_escolar_semestral(
    SGPTReprovacaoEscolarSemestralInput(
        placa="ABC1D23",
        licenca="12345678",
        inspetor_codigo="111",
        inspetor_nome="INSPETOR",
        rt_codigo="222",
        rt_nome="RESPONSAVEL TECNICO",
        itens_reprovacao=itens,
    )
)

sgpt.reprovar_taxi(
    SGPTReprovacaoTaxiInput(
        placa="ABC1234",
        licenca="12345678",
        inspetor_codigo="111",
        inspetor_nome="INSPETOR",
        rt_codigo="222",
        rt_nome="RESPONSAVEL TECNICO",
        ano_guia="2026",
        numero_guia="055721",
        itens_reprovacao=itens,
    )
)

sgpt.gerar_relatorio_inspecoes(
    SGPTRelatorioInput(
        mes=5,
        ano=2026,
        modalidade="E",  # C, E, F, T ou M
        resultado="",     # "", A, P ou R
    ),
    destino="tmp",
    nome_arquivo="relatorio_sgpt_maio_2026",
    salvar_html=True,
)

Retorno das aprovacoes SGPT:

ResultadoOperacao(
    ok=True,
    mensagem="Inspeção escolar semestral concluída com sucesso.",
    data={
        "arquivo": "inspecao.pdf",
        "caminho_arquivo": "C:/destino/inspecao.pdf",
        "data": {
            "licenca": "03414100",
            "placa": "CZZ1700",
            "modalidade": "ESCOLAR",
            "periodicidade": "SEMESTRAL",
            "resultado": "APROVADA",
            "inspetor": {"codigo": "3903967", "nome": "NOME DO INSPETOR"},
            "responsavel_tecnico": {"codigo": "5316804", "nome": "NOME DO RT"},
            "validade_extintor": "08/2026",
            "numero_tacografo": "00852092",
        },
    },
)

Quando a aprovacao nao gera comprovante, arquivo e caminho_arquivo retornam None. Nas reprovacoes, os dados normalizados ficam em data["data"], incluindo a lista completa em itens_reprovacao e sua contagem em itens_enviados.

As URLs do portal SGPT sao resolvidas internamente pelo modulo botdtp.sgpt.params.

Politica de autenticacao SGPT:

  • Login obrigatorio: passe login=SGPTLoginInput(...) ao instanciar o bot.
  • Manual: use sgpt.autenticar(...) para renovar explicitamente a sessao.
  • Gerenciada: com reautenticar=True, o bot tenta reautenticar ao detectar SGPTAutenticacaoError.
  • Sessao: SGPTBot restaura/salva cookies via SessionStore.
  • Echo HTTP: todos os metodos operacionais aceitam echo_post e echo_get; uma reautenticacao executada durante a operacao usa as mesmas flags.
  • Login inicial: para rastrear a autenticacao feita no construtor, configure HTTPConfig(echo_post=..., echo_get=...).

DAMSPBot

from botdtp import DAMSPBot
from botdtp.damsp import (
    DAMSPLicencaPFInput,
    DAMSPGuiaPFInput,
    DAMSPLicencaPJInput,
    DAMSPGuiaPJInput,
    DAMSPModalidadeVeiculoEnum,
    DAMSPServicoEscolarEnum,
    DAMSPServicoTaxiEnum,
    DAMSPOpenAICaptchaSolver,
)

damsp = DAMSPBot(
    captcha_solver=DAMSPOpenAICaptchaSolver(api_key="SUA_OPENAI_KEY"),
    max_tentativas=3,
)

# 1) Iniciar fluxo CPF
damsp.iniciar_fluxo_cpf(
    DAMSPLicencaPFInput(
        cpf="529.982.247-25",
        licenca="123.456-78",
        modalidade=DAMSPModalidadeVeiculoEnum.TAXI,
    )
)

# 2) Iniciar fluxo CNPJ
damsp.iniciar_fluxo_cnpj(
    DAMSPLicencaPJInput(
        cpf_responsavel="529.982.247-25",
        numero_empresa="123456",
        licenca="123.456-78",
        modalidade=DAMSPModalidadeVeiculoEnum.ESCOLAR,
    )
)

# 3) Gerar licenca PF
damsp.gerar_licenca_pf(
    DAMSPLicencaPFInput(
        cpf="529.982.247-25",
        licenca="123.456-78",
        modalidade=DAMSPModalidadeVeiculoEnum.TAXI,
    ),
    destino="tmp",
)

# 4) Gerar licenca PJ
damsp.gerar_licenca_pj(
    DAMSPLicencaPJInput(
        cpf_responsavel="529.982.247-25",
        numero_empresa="123456",
        licenca="123.456-78",
        modalidade=DAMSPModalidadeVeiculoEnum.ESCOLAR,
    ),
    destino="tmp",
)

# 5) Gerar guia PF
damsp.gerar_guia_pf(
    DAMSPGuiaPFInput(
        cpf="529.982.247-25",
        licenca="123.456-78",
        codigo_servico=DAMSPServicoTaxiEnum.RENOVACAO_ALVARA,
        modalidade=DAMSPModalidadeVeiculoEnum.TAXI,
    ),
    destino="tmp",
)

# 6) Gerar guia PJ
damsp.gerar_guia_pj(
    DAMSPGuiaPJInput(
        cpf_responsavel="529.982.247-25",
        numero_empresa="123456",
        licenca="123.456-78",
        codigo_servico=DAMSPServicoEscolarEnum.RENOVACAO_CRM,
        modalidade=DAMSPModalidadeVeiculoEnum.ESCOLAR,
    ),
    destino="tmp",
)

Retorno DAMSP de guias:

ResultadoOperacao(
    ok=True,
    mensagem="Guia do DAMSP para PF gerada com sucesso.",
    data={
        "arquivo": "guia_01024700.pdf",
        "caminho_arquivo": "C:\\Users\\...\\guia_01024700.pdf",
        "data": {
            "licenca": "01024700",
            "marca_modelo": "CITROEN/JUMP GREENCAR ES",
            "placa": "FJP5G96",
            "validade": "2026-06-19",
            "situacao": "ATIVO",
        },
        "servico": {
            "codigo": "712",
            "radio_value": "a1",
            "descricao": "RENOVACAO C.R.M.",
        },
        "reemissao": False,
    },
)

Nas operacoes que geram PDF, arquivo contem somente o nome do arquivo e caminho_arquivo contem o caminho absoluto salvo em disco.

Uso de baixo nivel (infra)

import requests

from botdtp import HTTPClient, HTTPConfig, DAMSPBot

http = HTTPClient(config=HTTPConfig(), session=requests.Session())
damsp = DAMSPBot(http=http)

Nos metodos publicos de SGPTBot e DAMSPBot, use echo_post=True para imprimir no terminal as URLs e payloads enviados por POST. Use echo_get=True para imprimir tambem as chamadas GET. Os parametros sao independentes, ficam desligados por padrao e valem somente durante a operacao:

resultado = damsp.gerar_guia_pf(
    payload,
    destino="tmp",
    nome_arquivo="guia_01024700",
    echo_post=True,
    echo_get=False,
)

Campos sensiveis conhecidos sao mascarados no log.

Captcha DAMSP

botdtp.damsp.captcha contem:

  • DAMSPOpenAICaptchaSolver (automatico via OpenAI/LangChain)
  • DAMSPManualCaptchaSolver (entrada manual)
  • DAMSPOpenAICaptchaConfig
  • converter_para_bytes_png

Configuracao recomendada:

  • Forneca api_key explicitamente em DAMSPOpenAICaptchaSolver.
  • Use max_tentativas no DAMSPBot para controlar novas tentativas quando o portal recusar o captcha.
  • Ajuste preset do modelo via DAMSPOpenAICaptchaConfig(model=..., max_tokens=..., temperature=...).
  • Se usar env, resolva no bootstrap da aplicacao e injete os valores no construtor.

Janela de acesso (SGPT) e sessao

Janela padrao: segunda a sabado (1,2,3,4,5,6), 07:00 ate 20:00, fuso America/Sao_Paulo.

Personalizacao via codigo:

  • Janela: passe ControleAcessoConfig(...) ao criar SGPTBot.
  • Persistencia em arquivo: disponivel no SGPTBot via SessionPersistenceConfig(...).
  • DAMSPBot: sem persistencia em disco; cada operacao refaz o fluxo de identificacao do perfil (PF/PJ).
  • HTTP: use HTTPConfig(...) com timeout, retry e proxy; em SGPTBot e DAMSPBot, ligue rastreio por operacao com echo_post e echo_get.

Scripts de runtime e testes

Exemplos de runtime:

  • examples/runtime_sgpt_smoke.py
  • examples/runtime_sgpt_alterar_senha_smoke.py
  • examples/runtime_sgpt_relatorio_smoke.py
  • examples/runtime_damsp_licenca_pf_smoke.py
  • examples/runtime_damsp_licenca_pj_smoke.py
  • cli/sgpt_menu_cli.py
  • cli/sgpt_menu_config.example.json
  • cli/damsp_menu_cli.py
  • cli/damsp_menu_config.example.json
  • examples/django_adapter_example.py

Testes:

pytest -q

Publicacao da versao 0.5.0

Checklist recomendado para publicar a 0.5.0:

  1. Atualize versao e metadados no pyproject.toml (version = "0.5.0").
  2. Garanta que este README reflita a API publica atual e a divisao por camadas.
  3. Registre nos release notes que SGPTBot e DAMSPBot expõem rastreio por operacao com echo_post/echo_get, mantendo as flags desligadas por padrao.
  4. Execute a suite local:
    • pytest -q
  5. Gere os artefatos:
    • python -m build
  6. Valide distribuicoes:
    • python -m twine check dist/*
  7. Publique (preferencialmente validando antes no TestPyPI):
    • python -m twine upload dist/*
  8. Crie tag e release:
    • git tag v0.5.0
    • git push origin v0.5.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

botdtp-0.5.0.tar.gz (78.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

botdtp-0.5.0-py3-none-any.whl (75.9 kB view details)

Uploaded Python 3

File details

Details for the file botdtp-0.5.0.tar.gz.

File metadata

  • Download URL: botdtp-0.5.0.tar.gz
  • Upload date:
  • Size: 78.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for botdtp-0.5.0.tar.gz
Algorithm Hash digest
SHA256 f0eeeee31996630bfebdf6d6383f1b2d588114a3b97aee1c017e6c3c1b246944
MD5 d9cdba2e4f0c78de0a4f10df6ed3cdb9
BLAKE2b-256 2f8d61495b61982358ea9283ae5128c634d6a2688464ef44cb1fcdf2c7b42e91

See more details on using hashes here.

File details

Details for the file botdtp-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: botdtp-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 75.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for botdtp-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 be4360a5fc43b88d995e03fa2a3b526716a6f95a2c6992dc1d1e39ee9786f1e7
MD5 b3a5f4651c38269873f6ede2a73f92a3
BLAKE2b-256 da483c8b95b18be4143268cdff39c2004423f840073936969761fc40e22a414e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page