#!/usr/bin/env python3 """CLI для запуска парсеров источников. Использование: python run_parser.py openalex --limit 10000 --query "машинное обучение" python run_parser.py cyberleninka --limit 1000 --query "нейронные сети" python run_parser.py arxiv --limit 5000 --categories cs.AI cs.LG python run_parser.py all --limit 1000 """ import argparse import logging import os import sys from pathlib import Path # Добавить директорию парсеров в путь sys.path.insert(0, str(Path(__file__).parent / "parsers")) logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", datefmt="%Y-%m-%d %H:%M:%S", ) logger = logging.getLogger(__name__) def run_openalex(args: argparse.Namespace, output_dir: Path) -> None: from openalex import OpenAlexParser parser = OpenAlexParser() parser.run( output_dir=output_dir, query=args.query, limit=args.limit, lang=args.lang, year_from=args.year_from, year_to=args.year_to, ) def run_cyberleninka(args: argparse.Namespace, output_dir: Path) -> None: from cyberleninka import CyberLeninkaParser parser = CyberLeninkaParser() parser.run( output_dir=output_dir, query=args.query, limit=args.limit, ) def run_arxiv(args: argparse.Namespace, output_dir: Path) -> None: from arxiv import ArxivParser parser = ArxivParser() parser.run( output_dir=output_dir, query=args.query, limit=args.limit, categories=args.categories, year_from=args.year_from, ) def run_all(args: argparse.Namespace, output_dir: Path) -> None: """Запустить все парсеры последовательно.""" logger.info("Запуск всех парсеров...") run_openalex(args, output_dir) run_cyberleninka(args, output_dir) run_arxiv(args, output_dir) PARSERS = { "openalex": run_openalex, "cyberleninka": run_cyberleninka, "arxiv": run_arxiv, "all": run_all, } def main() -> None: parser = argparse.ArgumentParser( description="Запуск парсеров академических источников", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=__doc__, ) parser.add_argument( "source", choices=list(PARSERS.keys()), help="Источник для парсинга", ) parser.add_argument( "--query", "-q", default="", help="Поисковый запрос", ) parser.add_argument( "--limit", "-n", type=int, default=1000, help="Максимальное количество документов (default: 1000)", ) parser.add_argument( "--output", "-o", default="/data/processed", help="Директория для сохранения JSONL (default: /data/processed)", ) parser.add_argument( "--lang", choices=["ru", "en"], default=None, help="Язык документов", ) parser.add_argument( "--year-from", type=int, default=None, dest="year_from", help="Год публикации от", ) parser.add_argument( "--year-to", type=int, default=None, dest="year_to", help="Год публикации до", ) parser.add_argument( "--categories", nargs="*", default=None, help="arXiv категории (например: cs.AI cs.LG math.ST)", ) args = parser.parse_args() output_dir = Path(args.output) output_dir.mkdir(parents=True, exist_ok=True) logger.info(f"Парсер: {args.source}, лимит: {args.limit}, запрос: {args.query!r}") logger.info(f"Выходная директория: {output_dir}") run_fn = PARSERS[args.source] run_fn(args, output_dir) logger.info("Парсинг завершён.") if __name__ == "__main__": main()