Skip to main content

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

Metadata

Release files for botdtp 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for botdtp 0.5.0
File Size Uploaded
botdtp-0.5.0.tar.gz 78.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for botdtp 0.5.0
File Interpreter ABI Platform
botdtp-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 154.5 kB

Release files / botdtp-0.5.0.tar.gz

Download URL botdtp-0.5.0.tar.gz
Size 78.6 kB
Tags Source
SHA-256 checksum
How to use checksums
f0eeeee31996630bfebdf6d6383f1b2d588114a3b97aee1c017e6c3c1b246944
BLAKE2b-256 checksum
How to use checksums
2f8d61495b61982358ea9283ae5128c634d6a2688464ef44cb1fcdf2c7b42e91
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release files / botdtp-0.5.0-py3-none-any.whl

Download URL botdtp-0.5.0-py3-none-any.whl
Size 75.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
be4360a5fc43b88d995e03fa2a3b526716a6f95a2c6992dc1d1e39ee9786f1e7
BLAKE2b-256 checksum
How to use checksums
da483c8b95b18be4143268cdff39c2004423f840073936969761fc40e22a414e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page