Skip to content

Repository files navigation

Python 3.11+ Poetry Code style: ruff Type checked: mypy Docker Pydantic SQLAlchemy Structlog pre-commit License: MIT



📄 Document Crawler

A production-ready document crawler with full-text search capabilities. Extracts text from various formats, handles nested archives, and provides powerful FTS.


📋 Table of Contents


✨ Features

  • Deep Crawling: Recursive directory traversal with hidden file support
  • Archive Extraction: Automatic unpacking of ZIP, RAR, 7z (including nested archives up to 3 levels)
  • Multi-format Support: Text extraction from 10+ document formats
  • Full-Text Search: SQLite FTS5 with automatic indexing and triggers
  • Dual Output: Results saved to both SQLite (for search) and CSV (for analysis)
  • Production Ready:
    • Full type hints with mypy --strict
    • Structured logging with structlog
    • Clean Architecture with clear separation of concerns
    • Docker support

📑 Supported Formats

Format Status Library/Tool Notes
PDF ✅ PyPDF2 Text extraction from all pages
DOCX ✅ python-docx Paragraphs and tables
DOC ⚠️ antiword/catdoc Not tested. Not applicable in Docker. Requires external utilities*
XLSX ✅ openpyxl All sheets and cells
XLS ✅ xlrd Legacy Excel format
TXT ✅ built-in Auto-encoding detection
MD ✅ TextParser Markdown as plain text
JSON ✅ TextParser JSON as plain text
XML ✅ TextParser XML as plain text
HTML ✅ TextParser HTML as plain text
ZIP ✅ patool Nested archives supported
RAR ⚠️ patool + unrar Requires external unrar* or use via docker
7Z ⚠️ patool + p7zip Requires external p7zip* or use via docker

*External utilities need to be installed separately in the system (see External Dependencies).


🚀 Quick Start

Prerequisites

  • Python 3.11+
  • Poetry
  • Your files to crawl (place them in data/storage/)

Installation

# Clone the repository
git clone https://github.com/script-logic/document-crawler.git
cd document-crawler

# Create .env file from example
cp .env.example .env

# Install with poetry
poetry install

Basic Usage

# Generate sample test files (optional)
poetry run python run_crawler.py generate-samples

# Crawl storage directory
poetry run python run_crawler.py crawl

# Search indexed documents
poetry run python run_crawler.py search "your query"

📁 Project Structure

├── app/                                # Main application package
│   ├── application/                    # Use cases (business logic)
│   │   └── use_cases/
│   │       ├── crawl.py                # Crawling orchestration
│   │       └── search.py               # Search orchestration
│   ├── config/                         # Configuration
│   │   └── config.py                   # Pydantic settings
│   ├── domain/                         # Domain models
│   │   ├── entities/                   # Document entity
│   │   └── value_objects/              # FileHash value object
│   ├── infrastructure/                 # External concerns
│   │   ├── crawler/                    # File scanning & archives
│   │   ├── database/                   # SQLAlchemy models & repository
│   │   ├── logger/                     # Structured logging
│   │   └── parsers/                    # Document parsers (PDF, DOCX, etc.)
│   └── utils/                          # Helpers (Singleton)
├── data/                               # Storage and output
│   ├── storage/                        # Place your files here
│   └── output/                         # Generated CSV files
├── tests/                              # Test suite
├── .env.example                        # Example environment
├── docker-compose.yml                  # Docker setup
├── pyproject.toml                      # Project metadata
└── run_crawler.py                      # Entry point

⚙️ Configuration

Configure via .env file (copy from .env.example):

# Logging
LOGGER__APP_NAME=Document Crawler
LOGGER__DEBUG=true
LOGGER__LOG_LEVEL=INFO
LOGGER__ENABLE_FILE_LOGGING=false
LOGGER__LOGS_DIR=logs

# Storage paths
CRAWLER__STORAGE_PATH=data/storage
CRAWLER__OUTPUT_CSV_PATH=data/output/crawled_files.csv

# Crawler settings
CRAWLER__MAX_FILE_SIZE_MB=100
CRAWLER__SKIP_HIDDEN=true
CRAWLER__EXTRACT_ARCHIVES=true
CRAWLER__MAX_ARCHIVE_DEPTH=3

# Supported extensions
CRAWLER__EXTRACT_TEXT_FROM=["pdf", "docx", "xlsx", "doc", "xls", "txt", "md", "json", "xml", "html"]
CRAWLER__ARCHIVE_EXTENSIONS=["zip", "rar", "7z"]

# Database
DATABASE__PATH=db/crawler.db
DATABASE__FTS_ENABLED=true

🎯 Usage

Commands

# Crawl storage directory
python run_crawler.py crawl [OPTIONS]

Options:
  --storage PATH     Path to storage directory (default: data/storage)
  --output PATH      Path to output CSV (default: data/output/crawled_files.csv)
  --limit N          Maximum number of files to process
  --no-archives      Don't extract archives

# Search indexed documents
python run_crawler.py search QUERY [OPTIONS]

Options:
  --limit N          Maximum results to return (default: 20)
  --type TYPE        Filter by document type (pdf, docx, xlsx, txt)

# Show database statistics
python run_crawler.py stats

# Generate test files
python run_crawler.py generate-samples [OPTIONS]

Options:
  --output PATH      Output directory (default: tests/fixtures/samples)
  --count N          Number of samples per type (default: 5)

Examples

# Full crawl
poetry run python run_crawler.py crawl

# Crawl with limit (for testing)
poetry run python run_crawler.py crawl --limit 100

# Search with filters
poetry run python run_crawler.py search "financial report" --type pdf --limit 10

# Complex FTS query (phrases, NEAR operator)
poetry run python run_crawler.py search '"tax planning" NEAR/5 client'

# Database stats
poetry run python run_crawler.py stats

# Generate 10 test files
poetry run python run_crawler.py generate-samples --count 10

🏗 Architecture

  • Domain Layer: Business logic, no external dependencies (except pydantic)
  • Application Layer: Orchestrates use cases, depends on abstractions
  • Infrastructure Layer: Implements interfaces, handles external concerns
  • Dependency Injection: All components receive their dependencies
  • Repository Pattern: Abstracts data storage
  • Factory Pattern: Creates appropriate parsers based on file type

🔧 External Dependencies

Some formats require system-level utilities:

Format Required Tool Installation
RAR archives unrar Windows: Install WinRAR or 7-Zip
Linux: sudo apt-get install unrar
macOS: brew install unrar
7Z archives p7zip Windows: Install 7-Zip
Linux: sudo apt-get install p7zip-full
macOS: brew install p7zip
DOC files antiword or catdoc Windows: https://github.com/rsdoiel/antiword
Linux: sudo apt-get install antiword
macOS: brew install antiword

Note: These are external executables, not Python packages. They must be installed in your system PATH. Please note: these external tools may not be available on your system even after following the installation instructions above.


🛠 Development

Setup

# Install with dev dependencies
poetry install --with dev

# Install pre-commit hooks
pre-commit install

Available Make Commands

make run-crawl            # Run crawler
make run-search QUERY=... # Search documents
make run-stats            # Show database stats
make run-generate-samples # Generate test files
make up                   # Start Docker container
make down                 # Stop Docker container
make lint                 # Run ruff and mypy
make format               # Format code with ruff
make clean                # Clean cache files

Code Quality

  • Ruff: Fast Python linter (replaces flake8, isort)
  • mypy: Strict type checking with --strict
  • pre-commit: Automated checks before commits

Docker

# Build and run
docker-compose up

# Run with custom command
docker-compose run --rm crawler python run_crawler.py search "query"

# Rebuild
docker-compose build --no-cache

📝 License

MIT License - feel free to use and modify.





📄 Краулер документов

Продакшен-реди краулер документов с полнотекстовым поиском. Извлекает текст из различных форматов, обрабатывает вложенные архивы и предоставляет мощный FTS.


📋 Содержание


✨ Возможности

  • Глубокий обход: Рекурсивный обход директорий с поддержкой скрытых файлов
  • Извлечение из архивов: Автоматическая распаковка ZIP, RAR, 7z (включая вложенные архивы до 3 уровней)
  • Мультиформатность: Извлечение текста из 10+ форматов документов
  • Полнотекстовый поиск: SQLite FTS5 с автоматическим индексированием и триггерами
  • Двойной вывод: Сохранение в SQLite (для поиска) и CSV (для анализа)
  • Готов к продакшену:
    • Полная типизация (mypy --strict)
    • Структурированное логирование (structlog)
    • Чистая архитектура
    • Поддержка Docker

📑 Поддерживаемые форматы

Формат Статус Библиотека/Утилита Примечания
PDF ✅ PyPDF2 Извлечение текста со всех страниц
DOCX ✅ python-docx Параграфы и таблицы
DOC ⚠️ antiword/catdoc Не протестировано. Не используется в docker. Требует внешние утилиты*
XLSX ✅ openpyxl Все листы и ячейки
XLS ✅ xlrd Старый формат Excel
TXT ✅ встроенный Автоопределение кодировки
MD ✅ TextParser Markdown как plain text
JSON ✅ TextParser JSON как plain text
XML ✅ TextParser XML как plain text
HTML ✅ TextParser HTML как plain text
ZIP ✅ patool Поддержка вложенных архивов
RAR ⚠️ patool + unrar Требует внешний unrar* или используйте docker
7Z ⚠️ patool + p7zip Требует внешний p7zip* или используйте docker

*Внешние утилиты устанавливаются отдельно в систему (см. Внешние зависимости).


🚀 Быстрый старт

Требования

  • Python 3.11+
  • Poetry
  • Ваши файлы для индексации (поместите в data/storage/)

Установка

# Клонировать репозиторий
git clone https://github.com/script-logic/document-crawler.git
cd document-crawler

# Создать .env файл из примера
cp .env.example .env

# Установка с poetry
poetry install

Базовое использование

# Сгенерировать тестовые файлы (опционально)
poetry run python run_crawler.py generate-samples

# Запустить краулер
poetry run python run_crawler.py crawl

# Поиск по индексированным документам
poetry run python run_crawler.py search "ваш запрос"

📁 Структура проекта

├── app/                                # Основной пакет приложения
│   ├── application/                    # Use cases (бизнес-логика)
│   │   └── use_cases/
│   │       ├── crawl.py                # Оркестрация краулинга
│   │       └── search.py               # Оркестрация поиска
│   ├── config/                         # Конфигурация
│   │   └── config.py                   # Pydantic настройки
│   ├── domain/                         # Доменные модели
│   │   ├── entities/                   # Сущность Document
│   │   └── value_objects/              # Value object FileHash
│   ├── infrastructure/                 # Внешние зависимости
│   │   ├── crawler/                    # Сканирование и архивы
│   │   ├── database/                   # SQLAlchemy модели и репозиторий
│   │   ├── logger/                     # Структурированное логирование
│   │   └── parsers/                    # Парсеры документов
│   └── utils/                          # Вспомогательные утилиты
├── data/                               # Хранилище и вывод
│   ├── storage/                        # Сюда класть файлы
│   └── output/                         # Сгенерированные CSV
├── tests/                              # Тесты
├── .env.example                        # Пример .env
├── docker-compose.yml                  # Docker настройки
├── pyproject.toml                      # Метаданные проекта
└── run_crawler.py                      # Точка входа

⚙️ Конфигурация

Настройка через .env файл (скопируйте из .env.example):

# Логирование
LOGGER__APP_NAME=Document Crawler
LOGGER__DEBUG=true
LOGGER__LOG_LEVEL=INFO
LOGGER__ENABLE_FILE_LOGGING=false
LOGGER__LOGS_DIR=logs

# Пути к данным
CRAWLER__STORAGE_PATH=data/storage
CRAWLER__OUTPUT_CSV_PATH=data/output/crawled_files.csv

# Настройки краулера
CRAWLER__MAX_FILE_SIZE_MB=100
CRAWLER__SKIP_HIDDEN=true
CRAWLER__EXTRACT_ARCHIVES=true
CRAWLER__MAX_ARCHIVE_DEPTH=3

# Поддерживаемые расширения
CRAWLER__EXTRACT_TEXT_FROM=["pdf", "docx", "xlsx", "doc", "xls", "txt", "md", "json", "xml", "html"]
CRAWLER__ARCHIVE_EXTENSIONS=["zip", "rar", "7z"]

# База данных
DATABASE__PATH=db/crawler.db
DATABASE__FTS_ENABLED=true

🎯 Использование

Команды

# Краулинг директории
python run_crawler.py crawl [ОПЦИИ]

Опции:
  --storage PATH     Путь к директории с файлами (по умолч.: data/storage)
  --output PATH      Путь к выходному CSV (по умолч.: data/output/crawled_files.csv)
  --limit N          Максимальное количество файлов
  --no-archives      Не обрабатывать архивы

# Поиск по индексированным документам
python run_crawler.py search ЗАПРОС [ОПЦИИ]

Опции:
  --limit N          Максимум результатов (по умолч.: 20)
  --type TYPE        Фильтр по типу (pdf, docx, xlsx, txt)

# Статистика БД
python run_crawler.py stats

# Генерация тестовых файлов
python run_crawler.py generate-samples [ОПЦИИ]

Опции:
  --output PATH      Директория для сохранения (по умолч.: tests/fixtures/samples)
  --count N          Количество файлов каждого типа (по умолч.: 5)

Примеры

# Полный краулинг
poetry run python run_crawler.py crawl

# Краулинг с лимитом (для тестирования)
poetry run python run_crawler.py crawl --limit 100

# Поиск с фильтрами
poetry run python run_crawler.py search "финансовый отчет" --type pdf --limit 10

# Сложный FTS запрос (фразы, NEAR оператор)
poetry run python run_crawler.py search '"налоговое планирование" NEAR/5 клиент'

# Статистика БД
poetry run python run_crawler.py stats

# Генерация 10 тестовых файлов
poetry run python run_crawler.py generate-samples --count 10

🏗 Архитектура

  • Доменный слой: Бизнес-логика, нет внешних зависимостей (кроме pydantic для удобства валидации)
  • Слой приложения: Оркестрирует use cases, зависит от абстракций
  • Инфраструктурный слой: Реализует интерфейсы, работает с внешними системами
  • Внедрение зависимостей: Все компоненты получают зависимости через конструктор
  • Репозиторий: Абстрагирует хранение данных
  • Фабрика: Создает парсеры на основе типа файла

🔧 Внешние зависимости

Некоторые форматы требуют системных утилит:

Формат Требуемая утилита Установка
RAR архивы unrar Windows: Установите WinRAR или 7-Zip
Linux: sudo apt-get install unrar
macOS: brew install unrar
7Z архивы p7zip Windows: Установите 7-Zip
Linux: sudo apt-get install p7zip-full
macOS: brew install p7zip
DOC файлы antiword или catdoc Windows: https://github.com/rsdoiel/antiword
Linux: sudo apt-get install antiword
macOS: brew install antiword

Важно: Это внешние исполняемые файлы, а не Python-пакеты. Они должны быть установлены в системе и доступны в PATH. Примечание: эти внешние инструменты могут отсутствовать в вашей системе или быть недоступны, даже если вы следовали инструкциям по установке, приведенным выше.


🛠 Разработка

Настройка

# Установка с dev зависимостями
poetry install --with dev

# Установка pre-commit хуков
pre-commit install

Доступные Make команды

make run-crawl            # Запуск краулера
make run-search QUERY=... # Поиск документов
make run-stats            # Статистика БД
make run-generate-samples # Генерация тестовых файлов
make up                   # Запуск Docker контейнера
make down                 # Остановка Docker
make lint                 # Запуск ruff и mypy
make format               # Форматирование кода
make clean                # Очистка кеша

Качество кода

  • Ruff: Быстрый линтер Python (заменяет flake8, isort)
  • mypy: Строгая проверка типов с --strict
  • pre-commit: Автоматические проверки перед коммитами
  • pytest: Набор тестов с покрытием

Docker

# Сборка и запуск
docker-compose up

# Запуск с произвольной командой
docker-compose run --rm crawler python run_crawler.py search "запрос"

# Пересборка
docker-compose build --no-cache

📝 Лицензия

MIT License - свободно используйте и модифицируйте.


About

🔍📄🗂️ A production-ready document crawler with full-text search capabilities. Recursively scans directories, extracts text from various document formats (PDF, DOCX, XLSX, TXT, and more), handles nested archives (ZIP, RAR, 7z), and provides powerful full-text search via SQLite FTS5. Built with clean architecture and type safety.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages