Skip to main content

A lightweight, concurrent, and robust batch file downloader for Python. Simplifies fetching multiple files from URLs by using a thread pool, checking for existing files, and reporting failures.

Project description

Grab Harvester

LinkedIn

Python License: MIT Code Style: pre-commit CI Status Codecov Last Commit

Um downloader de arquivos em lote, leve, concorrente e robusto para Python.



O Problema

Muitas vezes, projetos de software ou análise de dados precisam baixar um grande volume de arquivos de diversas URLs. Realizar essa tarefa de forma manual ou com scripts simples pode ser:

  • Lento e Ineficiente: Baixar arquivos um por um (sequencialmente) não aproveita a capacidade da rede e do processador, tornando o processo demorado.
  • Frágil: Scripts simples geralmente não lidam bem com falhas de rede, interrupções ou erros de permissão no disco, exigindo intervenção manual para reiniciar.
  • Redundante: É comum que o processo reinicie do zero, baixando novamente arquivos que já foram transferidos com sucesso, desperdiçando tempo e banda.

A Solução: Grab Harvester

O Grab Harvester foi criado para resolver exatamente esses problemas, oferecendo uma forma simplificada e poderosa de buscar múltiplos arquivos. Ele automatiza o processo com foco em performance e confiabilidade.

Principais Funcionalidades

  • Downloads Concorrentes: Utiliza um pool de threads para baixar vários arquivos simultaneamente, acelerando drasticamente o tempo total da operação.
  • Verificação de Integridade: Antes de iniciar um download, o sistema verifica se o arquivo já existe no destino. Se existir, compara o tamanho do arquivo local com o remoto (Content-Length). O download só é refeito se o arquivo local estiver incompleto, economizando recursos.
  • Tratamento Robusto de Erros: Captura e encapsula exceções comuns de rede (usando httpx) e de operações de arquivo (I/O), como NetworkDownloadError e FileOperationError. Isso permite que a aplicação que o utiliza possa tratar as falhas de forma granular, sem que o programa inteiro pare inesperadamente.
  • Simplicidade de Uso: Oferece uma interface limpa e direta para iniciar o processo de download, abstraindo toda a complexidade de gerenciamento de threads e tratamento de erros.

Como Rodar Localmente

Para executar este projeto em sua máquina, você precisará do Python 3.11+ instalado.

1. Clone o repositório

git clone https://github.com/alexcamargos/grab-harvester.git
cd grab-harvester

2. Configuração e Execução

Opção A: Usando uv (Recomendado)

O uv é um gerenciador de pacotes extremamente rápido.

  1. Instale as dependências:

    uv sync
    
  2. Execute o exemplo ou os testes:

    uv run examples/library_example.py
    uv run pytest
    

    Dica: Para atualizar o arquivo requirements.txt (usado na Opção B) com as versões travadas:

    uv export --format requirements-txt --output-file requirements.txt
    

Opção B: Usando pip

  1. Crie e ative um ambiente virtual:

    python -m venv .venv
    source .venv/bin/activate  # Linux/macOS
    # .venv\Scripts\activate   # Windows
    
  2. Instale as dependências:

    pip install -r requirements.txt
    
  3. Execute:

    python examples/library_example.py
    pytest
    

Como Usar

O Grab Harvester pode ser utilizado tanto para scripts rápidos quanto integrado em sistemas maiores.

Uso Simples (Script Rápido)

A função download é a maneira mais rápida de começar. Ela aceita uma lista de URLs (strings) ou objetos DownloadTask.

from grabharvester import download

urls = [
    "https://www.python.org/static/img/python-logo.png",
    "https://httpbin.org/image/jpeg"
]

# Baixa os arquivos usando 4 threads simultâneas
download(urls, max_threads=4, destination_dir="./downloads")

Uso Avançado (Integração em Projetos)

Para maior controle e aderência aos princípios SOLID (Injeção de Dependência), utilize as classes DownloadManager e DownloadService.

from pathlib import Path
from grabharvester import DownloadManager, DownloadService, DownloadTask

# 1. Instancie o serviço (pode ser mockado em testes)
service = DownloadService()

# 2. Inicialize o gerenciador
manager = DownloadManager(service, max_threads=2)

# 3. Defina as tarefas
tasks = [
    DownloadTask(url='https://www.python.org/static/img/python-logo.png'),
    DownloadTask(
        url='https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png',
        destination_path=Path('./google_logo.png')
    ),
]

# 4. Execute
print("Iniciando downloads...")
results = manager.run(tasks)

print(f"Sucessos: {len(results.successes)}")
print(f"Falhas: {len(results.failures)}")

Aprendizados e Arquitetura

O desenvolvimento do Grab Harvester foi uma excelente oportunidade para aplicar e aprofundar conceitos importantes de engenharia de software em Python.

  1. Programação Concorrente: A principal melhoria de performance veio do uso de concurrent.futures.ThreadPoolExecutor. A escolha por threads em vez de processos (ProcessPoolExecutor) foi estratégica, pois a tarefa de download é majoritariamente limitada por I/O (espera de rede), cenário onde threads são mais eficientes e consomem menos memória.

  2. Design Orientado a Objetos e Inversão de Dependência: A lógica de download foi encapsulada na classe DownloadService. Isso não apenas organiza o código, mas também facilita os testes. Em vez de chamar httpx.get diretamente no código principal, ele é usado dentro de um serviço, o que permite "mockar" a biblioteca httpx nos testes unitários e simular respostas de rede (sucesso, falha, etc.) sem depender de uma conexão real.

  3. Exceções Customizadas: Criar exceções específicas como NetworkDownloadError e FileOperationError em vez de propagar as exceções genéricas (httpx.RequestError, IOError) torna a API do Grab Harvester mais clara e estável. O código que utiliza a biblioteca sabe exatamente que tipo de problemas esperar, sem precisar conhecer os detalhes das dependências internas (como httpx).

  4. Testes Unitários Abrangentes com pytest e mocker: A qualidade do projeto é garantida por uma suíte de testes que cobre os principais cenários:

    • Download bem-sucedido.
    • Falhas de rede.
    • Erros de escrita em disco.
    • Lógica para pular downloads de arquivos já existentes e completos.
    • Lógica para refazer downloads de arquivos incompletos.

    O uso do mocker foi fundamental para isolar o DownloadService de sistemas externos (rede e sistema de arquivos), garantindo testes rápidos, determinísticos e confiáveis.

  5. Automação de Qualidade (Pre-commit): Integração de ferramentas de linter e formatadores automáticos via pre-commit. Isso assegura a criação de código melhor estruturado e formatado, mantendo a base de código limpa e consistente automaticamente.

Autor

Feito com :heart: por Alexsander Lopes Camargos :wave: Entre em contato!

GitHub Twitter Badge Linkedin Badge Gmail Badge

Licença

Este projeto está sob a licença MIT.

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

grab_harvester-0.0.2.tar.gz (14.9 kB view details)

Uploaded Source

Built Distribution

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

grab_harvester-0.0.2-py3-none-any.whl (11.9 kB view details)

Uploaded Python 3

File details

Details for the file grab_harvester-0.0.2.tar.gz.

File metadata

  • Download URL: grab_harvester-0.0.2.tar.gz
  • Upload date:
  • Size: 14.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for grab_harvester-0.0.2.tar.gz
Algorithm Hash digest
SHA256 2e478b3a7404737d3bf8038a6ba87b957e6c3a3bf2c846aedf7c8999f9f0b720
MD5 f44456e35b9bc0b236e1413050e53ff9
BLAKE2b-256 aa7eae7d3c8ed3e8c936a01144021d8c539d386aa54a4f3cc88234fec44978ab

See more details on using hashes here.

File details

Details for the file grab_harvester-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: grab_harvester-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 11.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for grab_harvester-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 492b5efc3d58f401ff1b1a5995a83018206b9ac591f83e848085e4fd492d29db
MD5 425f9997a0dc156deb827347115bb0af
BLAKE2b-256 973f9efa9b0709e525775dc42954f787a37f1fe1ed03838b6b225054b6d276ce

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