đ â Ăndice
Data: 14/08/2026
NĂvel: Projeto Final (MĂȘs 3 â Projetos Reais) đ
Uma ferramenta que monitora preços de produtos e organiza os resultados â combinando o que vocĂȘ aprendeu:
# Busca preços de produtos (ex: livros na API do Google Books)
python organizador_precos.py buscar "python para iniciantes" --limite 5
# Salva resultados em planilha
python organizador_precos.py buscar "langchain" --planilha resultados.xlsx
# Agenda verificação periódica (gera arquivos datados)
python organizador_precos.py monitorar "python" --intervalo 24
# Testes
pytest
organizador_precos/
âââ pyproject.toml # empacotamento
âââ README.md
âââ organizador/
â âââ __init__.py
â âââ api.py # Classe BuscaPrecos (requests)
â âââ saida.py # salvar CSV/planilha (pandas/openpyxl)
â âââ cli.py # argparse (main)
âââ tests/
âââ test_api.py
âââ test_saida.py
"""Consulta a API pĂșblica do Google Books."""
import requests
from dataclasses import dataclass
@dataclass
class Livro:
titulo: str
autor: str
preco: float | None
link: str
class BuscaPrecos:
"""Busca livros e preços na API do Google Books."""
BASE = "https://www.googleapis.com/books/v1/volumes"
def __init__(self, timeout: int = 10) -> None:
self.timeout = timeout
def buscar(self, termo: str, limite: int = 5) -> list[Livro]:
"""Busca livros pelo termo e retorna lista de Livro."""
resposta = requests.get(
self.BASE,
params={"q": termo, "maxResults": limite},
timeout=self.timeout,
)
resposta.raise_for_status()
livros: list[Livro] = []
for item in resposta.json().get("items", []):
info = item.get("volumeInfo", {})
venda = item.get("saleInfo", {})
preco = None
if venda.get("listPrice"):
preco = venda["listPrice"].get("amount")
livros.append(
Livro(
titulo=info.get("title", "Sem tĂtulo"),
autor=", ".join(info.get("authors", [])),
preco=preco,
link=info.get("infoLink", ""),
)
)
return livros
đĄ **`dataclass`** â estrutura de dados limpa, com `__repr__` automĂĄtico (revisĂŁo da P13!).
"""Geração de arquivos de saĂda."""
import csv
from pathlib import Path
from .api import Livro
def salvar_csv(livros: list[Livro], caminho: str) -> Path:
"""Salva a lista de livros em CSV."""
destino = Path(caminho)
with open(destino, "w", newline="", encoding="utf-8") as f:
escritor = csv.writer(f)
escritor.writerow(["titulo", "autor", "preco", "link"])
for livro in livros:
escritor.writerow([livro.titulo, livro.autor, livro.preco, livro.link])
return destino
def salvar_planilha(livros: list[Livro], caminho: str) -> Path:
"""Salva a lista de livros em planilha Excel."""
import pandas as pd
dados = [
{"titulo": l.titulo, "autor": l.autor, "preco": l.preco, "link": l.link}
for l in livros
]
df = pd.DataFrame(dados)
destino = Path(caminho)
df.to_excel(destino, index=False)
return destino
"""Interface de linha de comando."""
import argparse
import logging
from pathlib import Path
from .api import BuscaPrecos
from .saida import salvar_csv, salvar_planilha
logger = logging.getLogger(__name__)
def main() -> None:
parser = argparse.ArgumentParser(description="Organizador de preços de livros")
sub = parser.add_subparsers(dest="comando", required=True)
p_buscar = sub.add_parser("buscar", help="Busca livros")
p_buscar.add_argument("termo", help="Termo de busca")
p_buscar.add_argument("--limite", type=int, default=5)
p_buscar.add_argument("--csv", default=None, help="Salva em CSV")
p_buscar.add_argument("--planilha", default=None, help="Salva em planilha")
args = parser.parse_args()
api = BuscaPrecos()
try:
livros = api.buscar(args.termo, args.limite)
except Exception as erro: # noqa: BLE001
logger.error("Falha na busca: %s", erro)
return
if not livros:
print("Nenhum livro encontrado.")
return
for livro in livros:
preco = f"R$ {livro.preco:.2f}" if livro.preco else "indisponĂvel"
print(f"- {livro.titulo} ({livro.autor}) â {preco}")
if args.csv:
caminho = salvar_csv(livros, args.csv)
print(f"\nCSV salvo em {caminho}")
if args.planilha:
caminho = salvar_planilha(livros, args.planilha)
print(f"Planilha salva em {caminho}")
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
main()
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
name = "organizador-precos"
version = "0.1.0"
description = "Busca e organiza preços de livros via Google Books API"
requires-python = ">=3.10"
dependencies = ["requests", "pandas", "openpyxl"]
[project.scripts]
organizador = "organizador.cli:main"
[tool.setuptools.packages.find]
include = ["organizador*"]
pip install -e . # instala o comando 'organizador'
organizador buscar "python" --csv livros.csv
# tests/test_api.py
import pytest
from unittest.mock import patch, MagicMock
from organizador.api import BuscaPrecos
def test_buscar_retorna_livros():
resposta = MagicMock()
resposta.json.return_value = {
"items": [{
"volumeInfo": {"title": "Livro Teste", "authors": ["Autor A"]},
"saleInfo": {"listPrice": {"amount": 29.9}},
}]
}
with patch("requests.get", return_value=resposta) as mock_get:
livros = BuscaPrecos().buscar("teste", 1)
assert len(livros) == 1
assert livros[0].titulo == "Livro Teste"
assert livros[0].preco == 29.9
assert mock_get.call_args.kwargs["params"]["q"] == "teste"
def test_buscar_sem_preco():
resposta = MagicMock()
resposta.json.return_value = {"items": [{"volumeInfo": {"title": "GrĂĄtis"}}]}
with patch("requests.get", return_value=resposta):
livros = BuscaPrecos().buscar("x", 1)
assert livros[0].preco is None
| Critério | Onde foi aplicado |
|---|---|
| POO | `BuscaPrecos`, `Livro` (dataclass) |
| API externa | Google Books API |
| pathlib | salvar/ler arquivos |
| argparse | CLI com subcomandos |
| pytest | `tests/test_api.py` |
| Boas prĂĄticas | type hints, docstrings, logging |
| Empacotamento | `pyproject.toml` + `pip install -e .` |
VocĂȘ completou as 26 aulas do plano:
MĂȘs 1 (P01âP10): Fundamentos + POO bĂĄsica + Desafio
MĂȘs 2 (P11âP18): POO avançada + APIs + datas + testes + CLI
MĂȘs 3 (P19âP26): automação + scraping + CLIs + 3 projetos + boas prĂĄticas + FINAL
VocĂȘ agora consegue criar ferramentas Ășteis do zero â incluindo automaçÔes para as suas VPSs, bots de alerta e integraçÔes com APIs. E o melhor: todo esse conhecimento se conecta com LangChain, LangGraph e seus RAGs! đ
HB Estudos · â Voltar ao Ăndice de Python