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 centralResultadoOperacao, 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.0beautifulsoup4>=4.12.0lxml>=5.2.0pillow>=10.0.0langchain-core>=0.3.0langchain-openai>=0.2.0validate-docbr>=1.11.1xhtml2pdf>=0.2.17
Contrato padrao de retorno
Toda operacao retorna ResultadoOperacao:
ok: boolmensagem: strdata: dict
Comportamento em falha:
- Operacoes publicas de
BoteClientretornamResultadoOperacao(ok=False, ...). - Nao ha propagacao de excecao para o chamador nesse contrato padrao.
- Em erros,
dataincluioperacao,classeedetalhe.
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 detectarSGPTAutenticacaoError. - Sessao:
SGPTBotrestaura/salva cookies viaSessionStore. - Echo HTTP: todos os metodos operacionais aceitam
echo_posteecho_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)DAMSPOpenAICaptchaConfigconverter_para_bytes_png
Configuracao recomendada:
- Forneca
api_keyexplicitamente emDAMSPOpenAICaptchaSolver. - Use
max_tentativasnoDAMSPBotpara 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 criarSGPTBot. - Persistencia em arquivo: disponivel no
SGPTBotviaSessionPersistenceConfig(...). DAMSPBot: sem persistencia em disco; cada operacao refaz o fluxo de identificacao do perfil (PF/PJ).- HTTP: use
HTTPConfig(...)com timeout, retry e proxy; emSGPTBoteDAMSPBot, ligue rastreio por operacao comecho_posteecho_get.
Scripts de runtime e testes
Exemplos de runtime:
examples/runtime_sgpt_smoke.pyexamples/runtime_sgpt_alterar_senha_smoke.pyexamples/runtime_sgpt_relatorio_smoke.pyexamples/runtime_damsp_licenca_pf_smoke.pyexamples/runtime_damsp_licenca_pj_smoke.pycli/sgpt_menu_cli.pycli/sgpt_menu_config.example.jsoncli/damsp_menu_cli.pycli/damsp_menu_config.example.jsonexamples/django_adapter_example.py
Testes:
pytest -q
Publicacao da versao 0.5.0
Checklist recomendado para publicar a 0.5.0:
- Atualize versao e metadados no
pyproject.toml(version = "0.5.0"). - Garanta que este README reflita a API publica atual e a divisao por camadas.
- Registre nos release notes que
SGPTBoteDAMSPBotexpõem rastreio por operacao comecho_post/echo_get, mantendo as flags desligadas por padrao. - Execute a suite local:
pytest -q
- Gere os artefatos:
python -m build
- Valide distribuicoes:
python -m twine check dist/*
- Publique (preferencialmente validando antes no TestPyPI):
python -m twine upload dist/*
- Crie tag e release:
git tag v0.5.0git 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)
| File | Size | Uploaded | |
|---|---|---|---|
| botdtp-0.5.0.tar.gz | 78.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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
|