Исходный список из 29 дисциплин был чисто вузовски-научным (экономика, право, психология и т.д.) — ни одной темы уровня СПО/колледжей (полиграфия, строительство, сварка, туризм и т.п.), хотя реальные дипломы студентов именно на них. +29 новых дисциплин, идемпотентно (старые 30 не трогает).
133 lines
7.6 KiB
Python
133 lines
7.6 KiB
Python
#!/usr/bin/env python3
|
||
"""Подготовка русскоязычной заливки корпуса — сидинг parse_sources (CyberLeninka).
|
||
|
||
Зачем: корпус на ~99% английский (0 русских источников), хотя сервис — для русских
|
||
студентов. Этот скрипт создаёт в таблице `parse_sources` набор заданий CyberLeninka
|
||
по основным студенческим дисциплинам. Он НЕ запускает заливку — только готовит
|
||
задания; их затем триггерят (кнопка «Запустить» в админке или Celery-задача
|
||
`index.run_parser(source_id)`).
|
||
|
||
Идемпотентно: источник с таким `name` повторно не создаётся.
|
||
|
||
Запуск:
|
||
# dry-run — показать план, ничего не писать:
|
||
python scripts/seed_ru_sources.py
|
||
# создать источники в БД (лимит на каждую дисциплину):
|
||
python scripts/seed_ru_sources.py --apply --limit 500
|
||
|
||
Креды PG берутся из .env (POSTGRES_HOST/PORT/DB/USER/PASSWORD) или окружения.
|
||
ВНИМАНИЕ: локальный .env может указывать на старый PG — для прода используйте
|
||
POSTGRES_HOST=192.168.1.38 (см. вывод по наполненности базы).
|
||
"""
|
||
|
||
import argparse
|
||
import os
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
# Студенческие дисциплины → поисковый запрос в CyberLeninka (русскоязычный).
|
||
DISCIPLINES = [
|
||
"экономический анализ", "менеджмент организации", "бухгалтерский учёт",
|
||
"финансы и кредит", "маркетинг", "гражданское право", "уголовное право",
|
||
"конституционное право", "трудовое право", "педагогика", "психология личности",
|
||
"социология", "философия науки", "история России", "политология",
|
||
"информационные технологии", "программирование", "базы данных",
|
||
"математический анализ", "физика", "химия", "биология", "медицина",
|
||
"экология", "лингвистика", "литературоведение", "государственное управление",
|
||
"международные отношения", "журналистика", "культурология",
|
||
# Прикладные/техникумовские темы — оригинальный список был вузовски-научным,
|
||
# тут реальные дипломы СПО/колледжей, которых там не было вовсе.
|
||
"полиграфия и печать", "издательское дело", "дизайн", "строительство",
|
||
"архитектура", "машиностроение", "электротехника", "логистика", "туризм",
|
||
"гостиничное дело", "сестринское дело", "ветеринария", "агрономия",
|
||
"пищевая промышленность", "транспорт", "дорожное строительство",
|
||
"сварочное производство", "метрология и стандартизация", "реклама и PR",
|
||
"физическая культура и спорт", "дошкольное образование", "дефектология",
|
||
"банковское дело", "таможенное дело", "документоведение",
|
||
"телекоммуникации", "нефтегазовое дело", "энергетика",
|
||
"пожарная безопасность", "социальная работа",
|
||
]
|
||
|
||
|
||
def _load_env() -> None:
|
||
"""Подтянуть переменные из .env репозитория, если файл есть."""
|
||
env = Path(__file__).resolve().parent.parent / ".env"
|
||
if not env.exists():
|
||
return
|
||
for line in env.read_text(encoding="utf-8").splitlines():
|
||
line = line.strip()
|
||
if not line or line.startswith("#") or "=" not in line:
|
||
continue
|
||
key, _, val = line.partition("=")
|
||
os.environ.setdefault(key.strip(), val.strip())
|
||
|
||
|
||
def _pg_dsn() -> dict:
|
||
return {
|
||
"host": os.environ.get("POSTGRES_HOST", "localhost"),
|
||
"port": int(os.environ.get("POSTGRES_PORT", "5432")),
|
||
"dbname": os.environ.get("POSTGRES_DB", "antiplagiator"),
|
||
"user": os.environ.get("POSTGRES_USER", "antiplagiator"),
|
||
"password": os.environ.get("POSTGRES_PASSWORD", ""),
|
||
}
|
||
|
||
|
||
def main() -> None:
|
||
ap = argparse.ArgumentParser(description=__doc__,
|
||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||
ap.add_argument("--apply", action="store_true", help="реально записать в БД (иначе dry-run)")
|
||
ap.add_argument("--limit", type=int, default=500, help="лимит документов на дисциплину")
|
||
ap.add_argument("--source-type", default="cyberleninka", help="тип парсера (по умолчанию cyberleninka)")
|
||
args = ap.parse_args()
|
||
|
||
_load_env()
|
||
rows = [(f"ru:{d}", args.source_type, d) for d in DISCIPLINES]
|
||
|
||
print(f"Дисциплин: {len(rows)} | тип: {args.source_type} | лимит/шт: {args.limit}")
|
||
print(f"Потенциальный объём: ~{len(rows) * args.limit} документов")
|
||
if not args.apply:
|
||
print("\n[dry-run] будут созданы источники (name → query):")
|
||
for name, _, q in rows:
|
||
print(f" {name:38} → {q!r}")
|
||
print("\nЗапустите с --apply, чтобы записать в parse_sources.")
|
||
return
|
||
|
||
try:
|
||
import psycopg2
|
||
except ImportError:
|
||
sys.exit("Нужен psycopg2 (есть в образах воркеров). Запускайте на app-хосте/в контейнере.")
|
||
|
||
dsn = _pg_dsn()
|
||
print(f"\nПодключение к PG {dsn['host']}:{dsn['port']}/{dsn['dbname']} ...")
|
||
conn = psycopg2.connect(**dsn)
|
||
conn.autocommit = True
|
||
created, skipped, ids = 0, 0, []
|
||
with conn.cursor() as cur:
|
||
for name, stype, query in rows:
|
||
cur.execute("SELECT id FROM parse_sources WHERE name = %s", (name,))
|
||
existing = cur.fetchone()
|
||
if existing:
|
||
skipped += 1
|
||
continue
|
||
cur.execute(
|
||
'INSERT INTO parse_sources '
|
||
'(source_type, name, query, lang, "limit", enabled, last_status, docs_added) '
|
||
"VALUES (%s, %s, %s, 'ru', %s, TRUE, 'idle', 0) RETURNING id",
|
||
(stype, name, query, args.limit),
|
||
)
|
||
ids.append(cur.fetchone()[0])
|
||
created += 1
|
||
conn.close()
|
||
|
||
print(f"Создано: {created}, пропущено (уже были): {skipped}")
|
||
if ids:
|
||
print(f"ID новых источников: {ids}")
|
||
print("\nЗапуск заливки (после проверки источников):")
|
||
print(" • Админка → раздел «Источники» → «Запустить» у каждого, ЛИБО")
|
||
print(" • Celery: for i in ids: index.run_parser.delay(i)")
|
||
print("Рекомендация: сначала запустить 1-2 для проверки темпа/качества, потом остальные.")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|