Extração e Download de Livros Didáticos em PDF via Python com tchMaterial-parser

O acesso a materiais didáticos digitais em plataformas educacionais governamentais muitas vezes é restrito à visualização online. O tchMaterial-parser é uma ferramenta de código aberto desenvolvida em Python que contorna essa limitação, parseando a estrutura de URLs e consumindo APIs internas para obter e baixar arquivos PDF de livros didáticos de forma automatizada.

Configuração do Ambiente e Instalação

Para executar o parser, é necessário um ambiente Python 3.x. Recomenda-se o uso de um ambiente virtual para isolar as dependências do projeto e evitar conflitos de pacotes.

python -m venv venv_parser
source venv_parser/bin/activate  # No Windows: venv_parser\Scripts\activate
git clone https://github.com/exemplo/tchMaterial-parser.git extrator_livros
cd extrator_livros
pip install -r requirements.txt

A interface gráfica da aplicação é construída utilizando a biblioteca nativa tkinter. Para iniciar o aplicativo localmente, execute o script principal:

python main_gui.pyw

Arquitetura do Motor de Parseamento

O núcleo da ferramenta analisa a URL da plataforma para extrair metadados essenciais. Abaixo está uma representação refatorada da lógica de extração de parâmetros e requisição à API:

import re
import requests
from urllib.parse import urlparse, parse_qs

class BookExtractor:
    BASE_API_URL = "https://api.smartedu.cn/material/detail"

    def __init__(self, target_url: str):
        self.target_url = target_url
        self.content_id = self._extract_id()

    def _extract_id(self) -> str:
        parsed = urlparse(self.target_url)
        query_params = parse_qs(parsed.query)
        return query_params.get('contentId', [None])[0]

    def fetch_pdf_metadata(self) -> dict:
        if not self.content_id:
            raise ValueError("ID do conteúdo não encontrado na URL fornecida.")

        payload = {"id": self.content_id, "type": "assets_document"}
        response = requests.get(self.BASE_API_URL, params=payload, timeout=10)
        response.raise_for_status()

        data = response.json()
        return {
            "title": data.get("title", "documento_sem_nome"),
            "pdf_url": data.get("fileUrl")
        }

Otimização com Multithreading

Para processamento em lote, a ferramenta implementa um pool de threads. Isso permite o download simultâneo de múltiplos livros, gerenciando filas e evitando bloqueios de rede causados por operações I/O síncronas.

from concurrent.futures import ThreadPoolExecutor, as_completed

def download_batch(url_list: list, max_workers: int = 5):
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        future_to_url = {executor.submit(process_single_download, url): url for url in url_list}
        for future in as_completed(future_to_url):
            url = future_to_url[future]
            try:
                future.result()
            except Exception as exc:
                print(f"Falha no download de {url}: {exc}")

Tratamento de Erros e Configurações Avançadas

A robustez do script é garantida por mecanismos de retentativa e validação. É possível personalizar a estratégia de salvamento modificando o diretório de saída e aplicando sanitização nos nomes dos arquivos, além de implementar backoff exponencial para lidar com instabilidades de rede.

import os
import time

def safe_download(file_url: str, save_dir: str, retries: int = 3):
    os.makedirs(save_dir, exist_ok=True)
    filename = sanitize_filename(os.path.basename(file_url))
    filepath = os.path.join(save_dir, filename)

    for attempt in range(retries):
        try:
            with requests.get(file_url, stream=True, timeout=15) as r:
                r.raise_for_status()
                with open(filepath, 'wb') as f:
                    for chunk in r.iter_content(chunk_size=8192):
                        f.write(chunk)
            return True
        except requests.RequestException:
            if attempt == retries - 1:
                return False
            time.sleep(2 ** attempt)  # Backoff exponencial

Recursos Técnicos Principais

  • Parseamento de URL: Extração automática de parâmetros contentId e contentType para montagem de requisições válidas.
  • Filtragem de Metadados: Suporte a queries estruturadas por nível escolar, disciplina e edição do material através de menus suspensos na GUI.
  • Gerenciamento de Sessão: Manutenção de cabeçalhos HTTP para simular requisições de navegador e evitar bloqueios por user-agent.
  • Resiliência de Rede: Implementação de retentativas automáticas e verificação de integridade de aqruivos após o download.

Tags: Python WebScraping Multithreading API Tkinter

Publicado em 8-9 10:28