Skip to main content

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.

Metadata

Release files for grab-harvester 0.0.2

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

Source distribution (sdist)

Source distribution for grab-harvester 0.0.2
File Size Uploaded
grab_harvester-0.0.2.tar.gz 14.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for grab-harvester 0.0.2
File Interpreter ABI Platform
grab_harvester-0.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 26.8 kB

Release files / grab_harvester-0.0.2.tar.gz

Download URL grab_harvester-0.0.2.tar.gz
Size 14.9 kB
Tags Source
SHA-256 checksum
How to use checksums
2e478b3a7404737d3bf8038a6ba87b957e6c3a3bf2c846aedf7c8999f9f0b720
BLAKE2b-256 checksum
How to use checksums
aa7eae7d3c8ed3e8c936a01144021d8c539d386aa54a4f3cc88234fec44978ab
Upload date
Uploaded using Trusted Publishing?
What is 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}

Release files / grab_harvester-0.0.2-py3-none-any.whl

Download URL grab_harvester-0.0.2-py3-none-any.whl
Size 11.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
492b5efc3d58f401ff1b1a5995a83018206b9ac591f83e848085e4fd492d29db
BLAKE2b-256 checksum
How to use checksums
973f9efa9b0709e525775dc42954f787a37f1fe1ed03838b6b225054b6d276ce
Upload date
Uploaded using Trusted Publishing?
What is 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}

Release history Release notifications | RSS feed

This release

0.0.2 This release

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