mirror of
https://github.com/ada-dmitry/CourseWork_IRFM.git
synced 2026-09-24 01:10:18 +00:00
Remove outdated documentation and improve comments in main and crawler modules
This commit is contained in:
@@ -1,24 +0,0 @@
|
|||||||
## Обработка УК РФ
|
|
||||||
|
|
||||||
Источник данных: https://www.consultant.ru/document/cons_doc_LAW_10699/
|
|
||||||
|
|
||||||
Запуск:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
uv run python main.py
|
|
||||||
```
|
|
||||||
|
|
||||||
Скрипт загружает страницы статей УК РФ с Consultant, оставляет только содержательный текст статей, убирает заголовки, номера пунктов, редакционные и заключительные блоки, затем выполняет лемматизацию, удаление пунктуации, стоп-слов, числительных и имен собственных.
|
|
||||||
|
|
||||||
Подробные описания модулей:
|
|
||||||
|
|
||||||
- [LOADER_README.md](LOADER_README.md) — загрузка HTML;
|
|
||||||
- [CRAWLER_README.md](CRAWLER_README.md) — обход страниц ConsultantPlus и извлечение текста;
|
|
||||||
- [PROCESSOR_README.md](PROCESSOR_README.md) — подготовка текста и построение предметного указателя.
|
|
||||||
|
|
||||||
Результаты сохраняются в `output/`:
|
|
||||||
|
|
||||||
- `uk_rf_original.txt` — исходный содержательный текст до лемматизации;
|
|
||||||
- `uk_rf_prepared.txt` — подготовленный текст для анализа без числительных, цифровых единиц и имен собственных;
|
|
||||||
- `uk_rf_subject_index.csv` — предметный указатель на 100 основных лемм с частотой, строкой и символом первого появления;
|
|
||||||
- `uk_rf_subject_index.json` — тот же указатель в JSON.
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
## Как работает crawler
|
|
||||||
|
|
||||||
Crawler находится в `modules/crawler.py`. Его задача простая: пройти по страницам статей УК РФ на ConsultantPlus и вернуть только содержательный текст статей.
|
|
||||||
|
|
||||||
В коде используются: `urllib`/`curl` для загрузки, `lxml` и `XPath` для разбора HTML, регулярные выражения для очистки строк.
|
|
||||||
|
|
||||||
## Общий алгоритм
|
|
||||||
|
|
||||||
1. Загружаем стартовую страницу УК РФ:
|
|
||||||
|
|
||||||
```python
|
|
||||||
START_URL = "https://www.consultant.ru/document/cons_doc_LAW_10699/"
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Ищем ссылки на статьи вида `УК РФ Статья 1...`.
|
|
||||||
3. Берем первую статью.
|
|
||||||
4. Загружаем страницу статьи.
|
|
||||||
5. Извлекаем текст из блока `document-page__content`.
|
|
||||||
6. Удаляем заголовки, служебные блоки и редакционные пометки.
|
|
||||||
7. Переходим к следующей странице по ссылке `pages__right`.
|
|
||||||
8. Повторяем, пока не дойдем до последней статьи или до лимита `max_pages`.
|
|
||||||
|
|
||||||
Главная функция:
|
|
||||||
|
|
||||||
```python
|
|
||||||
pages = crawl_document()
|
|
||||||
```
|
|
||||||
|
|
||||||
Она возвращает список словарей:
|
|
||||||
|
|
||||||
```python
|
|
||||||
{
|
|
||||||
"url": "адрес страницы",
|
|
||||||
"title": "заголовок статьи",
|
|
||||||
"text": "очищенный текст статьи",
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Загрузка страницы
|
|
||||||
|
|
||||||
Загрузка вынесена в `modules/loader.py`.
|
|
||||||
|
|
||||||
Для обычных сайтов используется `urllib`, а для ConsultantPlus сначала пробуется `curl`, потому что сайт иногда нестабильно отдает большие HTML-страницы.
|
|
||||||
|
|
||||||
В crawler используется функция:
|
|
||||||
|
|
||||||
```python
|
|
||||||
download_document_page(url)
|
|
||||||
```
|
|
||||||
|
|
||||||
Она делает несколько попыток с таймаутами `8`, `30`, `30` секунд. Для страниц статей проверяется, что HTML полный и содержит `</html>`.
|
|
||||||
|
|
||||||
Для стартовой страницы допускается частичный HTML:
|
|
||||||
|
|
||||||
```python
|
|
||||||
download_document_page(start_url, allow_partial=True)
|
|
||||||
```
|
|
||||||
|
|
||||||
Это нужно потому, что оглавление может успеть прийти даже тогда, когда сайт оборвал конец HTML.
|
|
||||||
|
|
||||||
## Определение страницы статьи
|
|
||||||
|
|
||||||
Страница считается статьей, если ее заголовок подходит под регулярное выражение:
|
|
||||||
|
|
||||||
```python
|
|
||||||
ARTICLE_RE = re.compile(r"^\s*(?:УК РФ,?\s+)?Статья\s+\d+(?:\.\d+)?\.")
|
|
||||||
```
|
|
||||||
|
|
||||||
То есть подходят такие варианты:
|
|
||||||
|
|
||||||
```text
|
|
||||||
УК РФ Статья 1. ...
|
|
||||||
УК РФ, Статья 53.1. ...
|
|
||||||
Статья 361. ...
|
|
||||||
```
|
|
||||||
|
|
||||||
Проверка выполняется функцией:
|
|
||||||
|
|
||||||
```python
|
|
||||||
is_article_page(page_html)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Извлечение текста статьи
|
|
||||||
|
|
||||||
Текст достается функцией:
|
|
||||||
|
|
||||||
```python
|
|
||||||
extract_page_text(page_html)
|
|
||||||
```
|
|
||||||
|
|
||||||
Она делает четыре шага:
|
|
||||||
|
|
||||||
1. Парсит HTML через `lxml.html.fromstring`.
|
|
||||||
2. Находит основной блок:
|
|
||||||
|
|
||||||
```text
|
|
||||||
document-page__content
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Удаляет служебные элементы:
|
|
||||||
|
|
||||||
- `h1`;
|
|
||||||
- `doc-style`;
|
|
||||||
- `doc-insert`;
|
|
||||||
- `doc-roll`.
|
|
||||||
|
|
||||||
4. Берет текст из абзацев `p`.
|
|
||||||
|
|
||||||
Дополнительно функция `clean_text()`:
|
|
||||||
|
|
||||||
- заменяет неразрывные пробелы;
|
|
||||||
- схлопывает лишние пробелы;
|
|
||||||
- убирает номера пунктов вроде `1.`, `2.`, `а)`.
|
|
||||||
|
|
||||||
## Удаление служебных строк
|
|
||||||
|
|
||||||
Функция:
|
|
||||||
|
|
||||||
```python
|
|
||||||
service_line(line)
|
|
||||||
```
|
|
||||||
|
|
||||||
убирает строки, которые не относятся к содержанию статьи:
|
|
||||||
|
|
||||||
```text
|
|
||||||
(в ред. Федерального закона ...)
|
|
||||||
(см. текст в предыдущей редакции)
|
|
||||||
(часть третья введена ...)
|
|
||||||
Президент
|
|
||||||
Б.ЕЛЬЦИН
|
|
||||||
13 июня 1996 года
|
|
||||||
N 63-ФЗ
|
|
||||||
```
|
|
||||||
|
|
||||||
## Переход к следующей статье
|
|
||||||
|
|
||||||
Основной способ перехода:
|
|
||||||
|
|
||||||
```python
|
|
||||||
extract_next_document_url(page_html, current_url)
|
|
||||||
```
|
|
||||||
|
|
||||||
Функция ищет правую ссылку ConsultantPlus:
|
|
||||||
|
|
||||||
```text
|
|
||||||
pages__right
|
|
||||||
```
|
|
||||||
|
|
||||||
Если такой ссылки нет, crawler использует запасной список `known_urls`. В него заранее складываются все найденные ссылки на статьи. Это помогает продолжить обход, если нижняя навигация не попала в загруженный HTML.
|
|
||||||
|
|
||||||
## Защита от лишних ссылок
|
|
||||||
|
|
||||||
Crawler проверяет, что каждая ссылка относится именно к УК РФ:
|
|
||||||
|
|
||||||
```python
|
|
||||||
is_same_document(url, prefix)
|
|
||||||
```
|
|
||||||
|
|
||||||
Для УК РФ правильный префикс:
|
|
||||||
|
|
||||||
```text
|
|
||||||
/document/cons_doc_LAW_10699/
|
|
||||||
```
|
|
||||||
|
|
||||||
Поэтому crawler не уходит в новости, другие кодексы, комментарии и внешние документы.
|
|
||||||
|
|
||||||
## Где используется результат
|
|
||||||
|
|
||||||
В `main.py` результат объединяется в один текст:
|
|
||||||
|
|
||||||
```python
|
|
||||||
pages = crawl_document(SOURCE_URL)
|
|
||||||
original_text = "\n".join(page["text"] for page in pages)
|
|
||||||
```
|
|
||||||
|
|
||||||
После этого `original_text` передается в `modules/processor.py`, где строятся подготовленный текст и предметный указатель.
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
## Как работает index
|
|
||||||
|
|
||||||
Index находится в `modules/index.py`. Его задача: взять исходный текст УК РФ и построить предметный указатель — топ-N наиболее частотных лемм с позицией первого вхождения.
|
|
||||||
|
|
||||||
Модуль использует `good_words_from_line` из `modules/processor.py` и ничего не знает о загрузке или обходе страниц.
|
|
||||||
|
|
||||||
## Что делает index
|
|
||||||
|
|
||||||
1. Обходит текст построчно и извлекает «хорошие» слова через `processor.py`.
|
|
||||||
2. Считает частоту каждой леммы.
|
|
||||||
3. Запоминает, где лемма встретилась впервые.
|
|
||||||
4. Возвращает топ-N по частоте.
|
|
||||||
5. Сохраняет результат в CSV и JSON.
|
|
||||||
|
|
||||||
## Генератор prepared_terms
|
|
||||||
|
|
||||||
```python
|
|
||||||
prepared_terms(text)
|
|
||||||
```
|
|
||||||
|
|
||||||
Обходит текст построчно и для каждого слова, прошедшего фильтрацию, выдаёт кортеж:
|
|
||||||
|
|
||||||
```python
|
|
||||||
(лемма, номер_строки, позиция_символа, исходное_слово)
|
|
||||||
```
|
|
||||||
|
|
||||||
Нумерация строк начинается с `1`, позиция символа — 1-based, как в `processor.py`.
|
|
||||||
|
|
||||||
## Построение предметного указателя
|
|
||||||
|
|
||||||
```python
|
|
||||||
build_subject_index(text, top_n=100)
|
|
||||||
```
|
|
||||||
|
|
||||||
Алгоритм:
|
|
||||||
|
|
||||||
1. Проходит по всем словам через `prepared_terms`.
|
|
||||||
2. Считает частоты через `Counter`.
|
|
||||||
3. Запоминает первое вхождение каждой леммы через `setdefault` — первый вызов выигрывает, последующие игнорируются.
|
|
||||||
4. Берёт `top_n` самых частотных лемм.
|
|
||||||
|
|
||||||
Одна запись результата:
|
|
||||||
|
|
||||||
```python
|
|
||||||
{
|
|
||||||
"word": "срок",
|
|
||||||
"count": 3342,
|
|
||||||
"line": 34,
|
|
||||||
"char": 151,
|
|
||||||
"source_word": "срок",
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Запись результатов
|
|
||||||
|
|
||||||
Для сохранения индекса есть две функции.
|
|
||||||
|
|
||||||
```python
|
|
||||||
write_subject_index_csv(entries, path)
|
|
||||||
```
|
|
||||||
|
|
||||||
Сохраняет CSV с разделителем `;`:
|
|
||||||
|
|
||||||
```text
|
|
||||||
word;count;line;char;source_word
|
|
||||||
срок;3342;34;151;срок
|
|
||||||
```
|
|
||||||
|
|
||||||
```python
|
|
||||||
write_subject_index_json(entries, path)
|
|
||||||
```
|
|
||||||
|
|
||||||
Сохраняет JSON с отступами и без ASCII-экранирования кириллицы (`ensure_ascii=False`).
|
|
||||||
|
|
||||||
## Где используется index
|
|
||||||
|
|
||||||
В `main.py`:
|
|
||||||
|
|
||||||
```python
|
|
||||||
subject_index = build_subject_index(original_text, top_n=100)
|
|
||||||
write_subject_index_csv(subject_index, output_dir / "uk_rf_subject_index.csv")
|
|
||||||
write_subject_index_json(subject_index, output_dir / "uk_rf_subject_index.json")
|
|
||||||
```
|
|
||||||
|
|
||||||
Входные данные — исходный текст статей до лемматизации (`original_text`), а не подготовленный. Лемматизация происходит внутри через `processor.py`.
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
## Как работает loader
|
|
||||||
|
|
||||||
Loader находится в `modules/loader.py`. Его задача одна: скачать HTML-страницу и вернуть ее как строку.
|
|
||||||
|
|
||||||
Есть загрузка через `curl`, загрузка через `urllib` и общая функция `download_html()`, которая выбирает порядок попыток.
|
|
||||||
|
|
||||||
## Заголовки запроса
|
|
||||||
|
|
||||||
В начале файла задан словарь:
|
|
||||||
|
|
||||||
```python
|
|
||||||
HEADERS
|
|
||||||
```
|
|
||||||
|
|
||||||
Он содержит HTTP-заголовки:
|
|
||||||
|
|
||||||
```text
|
|
||||||
User-Agent
|
|
||||||
Accept
|
|
||||||
Accept-Language
|
|
||||||
```
|
|
||||||
|
|
||||||
Они нужны, чтобы сайт отдавал обычную HTML-страницу, как браузеру.
|
|
||||||
|
|
||||||
## Загрузка через curl
|
|
||||||
|
|
||||||
Функция:
|
|
||||||
|
|
||||||
```python
|
|
||||||
download_with_curl(url, timeout)
|
|
||||||
```
|
|
||||||
|
|
||||||
запускает системную команду `curl` через `subprocess.run`.
|
|
||||||
|
|
||||||
Используются параметры:
|
|
||||||
|
|
||||||
```text
|
|
||||||
-L переходить по редиректам
|
|
||||||
--compressed принимать сжатый ответ
|
|
||||||
--silent не печатать лишний прогресс
|
|
||||||
--show-error показать ошибку, если она есть
|
|
||||||
--max-time ограничить время загрузки
|
|
||||||
-A передать User-Agent
|
|
||||||
```
|
|
||||||
|
|
||||||
Если `curl` что-то скачал в `stdout`, функция декодирует байты как UTF-8 и возвращает HTML-строку.
|
|
||||||
|
|
||||||
Для ConsultantPlus этот способ оказался надежнее, чем чистый `urllib`, потому что сайт иногда нестабильно отдает большие страницы.
|
|
||||||
|
|
||||||
## Загрузка через urllib
|
|
||||||
|
|
||||||
Функция:
|
|
||||||
|
|
||||||
```python
|
|
||||||
download_with_urllib(url, timeout)
|
|
||||||
```
|
|
||||||
|
|
||||||
использует стандартную библиотеку Python:
|
|
||||||
|
|
||||||
```python
|
|
||||||
urllib.request
|
|
||||||
```
|
|
||||||
|
|
||||||
Алгоритм:
|
|
||||||
|
|
||||||
1. Создается SSL-контекст.
|
|
||||||
2. Создается `Request` с заголовками `HEADERS`.
|
|
||||||
3. Вызывается `urlopen`.
|
|
||||||
4. Ответ читается и декодируется как UTF-8.
|
|
||||||
|
|
||||||
SSL-проверка отключена:
|
|
||||||
|
|
||||||
```python
|
|
||||||
context.check_hostname = False
|
|
||||||
context.verify_mode = ssl.CERT_NONE
|
|
||||||
```
|
|
||||||
|
|
||||||
Это сделано для учебной устойчивости загрузки, чтобы сертификаты сайта не мешали выполнению задания.
|
|
||||||
|
|
||||||
## Главная функция
|
|
||||||
|
|
||||||
Основная функция модуля:
|
|
||||||
|
|
||||||
```python
|
|
||||||
download_html(url, retries=3, timeout=30.0)
|
|
||||||
```
|
|
||||||
|
|
||||||
Она возвращает HTML-код страницы.
|
|
||||||
|
|
||||||
Логика выбора загрузчика:
|
|
||||||
|
|
||||||
- всегда сначала пробуется `curl`, затем `urllib`.
|
|
||||||
|
|
||||||
`curl` надёжнее обходит защиты ConsultantPlus, поэтому стоит первым для любых URL.
|
|
||||||
|
|
||||||
## Повторные попытки
|
|
||||||
|
|
||||||
В `download_html()` есть цикл:
|
|
||||||
|
|
||||||
```python
|
|
||||||
for _ in range(retries):
|
|
||||||
```
|
|
||||||
|
|
||||||
На каждой попытке функция пробует все доступные загрузчики. Если оба способа не сработали, программа ждет `0.5` секунды и пробует еще раз.
|
|
||||||
|
|
||||||
Если после всех попыток страница не загрузилась, выбрасывается ошибка:
|
|
||||||
|
|
||||||
```python
|
|
||||||
RuntimeError
|
|
||||||
```
|
|
||||||
|
|
||||||
Эту ошибку затем обрабатывает crawler.
|
|
||||||
|
|
||||||
## Где используется loader
|
|
||||||
|
|
||||||
Crawler вызывает loader через функцию:
|
|
||||||
|
|
||||||
```python
|
|
||||||
download_html(url, retries=1, timeout=timeout)
|
|
||||||
```
|
|
||||||
|
|
||||||
То есть loader ничего не знает про УК РФ, статьи или обработку текста. Он только скачивает HTML, а вся логика обхода находится в `modules/crawler.py`.
|
|
||||||
@@ -1,216 +0,0 @@
|
|||||||
## Как работает processor
|
|
||||||
|
|
||||||
Processor находится в `modules/processor.py`. Он получает уже очищенный исходный текст УК РФ и готовит его к анализу.
|
|
||||||
|
|
||||||
В коде используются простые инструменты: регулярные выражения, списки стоп-слов, `pymorphy3` для лемматизации, `Counter` для подсчета частот, `csv` и `json` для записи результата.
|
|
||||||
|
|
||||||
## Что делает processor
|
|
||||||
|
|
||||||
Основные задачи:
|
|
||||||
|
|
||||||
1. Найти слова в тексте.
|
|
||||||
2. Привести каждое слово к нормальной форме.
|
|
||||||
3. Удалить лишние слова: стоп-слова, служебные слова структуры закона, числительные, единицы измерения после чисел, имена собственные и названия объектов.
|
|
||||||
4. Собрать подготовленный текст.
|
|
||||||
5. Построить предметный указатель на 100 самых частых слов.
|
|
||||||
|
|
||||||
## Поиск слов
|
|
||||||
|
|
||||||
Слова ищутся регулярным выражением:
|
|
||||||
|
|
||||||
```python
|
|
||||||
WORD_RE = re.compile(r"[А-Яа-яЁё]+(?:-[А-Яа-яЁё]+)?")
|
|
||||||
```
|
|
||||||
|
|
||||||
Оно находит русские слова, в том числе слова с дефисом:
|
|
||||||
|
|
||||||
```text
|
|
||||||
уголовно-правовой
|
|
||||||
социально-опасный
|
|
||||||
```
|
|
||||||
|
|
||||||
Цифры и пунктуация этим выражением не выбираются.
|
|
||||||
|
|
||||||
## Лемматизация
|
|
||||||
|
|
||||||
Лемматизация выполняется через `pymorphy3`.
|
|
||||||
|
|
||||||
Функция:
|
|
||||||
|
|
||||||
```python
|
|
||||||
parse_word(word)
|
|
||||||
```
|
|
||||||
|
|
||||||
возвращает:
|
|
||||||
|
|
||||||
```python
|
|
||||||
lemma, tag
|
|
||||||
```
|
|
||||||
|
|
||||||
Например:
|
|
||||||
|
|
||||||
```text
|
|
||||||
преступлений -> преступление
|
|
||||||
лишением -> лишение
|
|
||||||
осужденного -> осудить
|
|
||||||
```
|
|
||||||
|
|
||||||
`tag` нужен для фильтрации числительных и имен собственных. Чтобы одно и то же слово не разбирать много раз, используется `lru_cache`.
|
|
||||||
|
|
||||||
## Стоп-слова
|
|
||||||
|
|
||||||
Стоп-слова лежат в множестве:
|
|
||||||
|
|
||||||
```python
|
|
||||||
STOP_WORDS
|
|
||||||
```
|
|
||||||
|
|
||||||
Туда входят обычные служебные слова:
|
|
||||||
|
|
||||||
```text
|
|
||||||
и, в, на, что, этот, который
|
|
||||||
```
|
|
||||||
|
|
||||||
и структурные слова закона:
|
|
||||||
|
|
||||||
```text
|
|
||||||
статья, часть, глава, раздел, пункт, кодекс
|
|
||||||
```
|
|
||||||
|
|
||||||
Они часто встречаются, но не являются полезными терминами предметного указателя.
|
|
||||||
|
|
||||||
## Удаление числительных
|
|
||||||
|
|
||||||
Числительные удаляются двумя способами.
|
|
||||||
|
|
||||||
Первый способ: по списку слов:
|
|
||||||
|
|
||||||
```python
|
|
||||||
NUMERAL_WORDS
|
|
||||||
```
|
|
||||||
|
|
||||||
Например:
|
|
||||||
|
|
||||||
```text
|
|
||||||
один, два, три, пятьсот, тысяча, миллион
|
|
||||||
```
|
|
||||||
|
|
||||||
Второй способ: по морфологическим тегам `pymorphy3`:
|
|
||||||
|
|
||||||
```python
|
|
||||||
NUMR
|
|
||||||
Anum
|
|
||||||
```
|
|
||||||
|
|
||||||
Так удаляются формы вроде:
|
|
||||||
|
|
||||||
```text
|
|
||||||
трех
|
|
||||||
пяти
|
|
||||||
первой
|
|
||||||
второго
|
|
||||||
```
|
|
||||||
|
|
||||||
## Удаление единиц после чисел
|
|
||||||
|
|
||||||
Есть слова, которые сами по себе могут быть полезными, но после числа обычно являются частью числительного выражения.
|
|
||||||
|
|
||||||
Например:
|
|
||||||
|
|
||||||
```text
|
|
||||||
до трех лет
|
|
||||||
500 рублей
|
|
||||||
на срок шесть месяцев
|
|
||||||
```
|
|
||||||
|
|
||||||
Для этого используется список:
|
|
||||||
|
|
||||||
```python
|
|
||||||
NUMBER_UNITS
|
|
||||||
```
|
|
||||||
|
|
||||||
Туда входят:
|
|
||||||
|
|
||||||
```text
|
|
||||||
год, месяц, день, час, рубль, процент, метр
|
|
||||||
```
|
|
||||||
|
|
||||||
Если такое слово стоит после числительного или после цифры, оно удаляется.
|
|
||||||
|
|
||||||
## Удаление имен собственных
|
|
||||||
|
|
||||||
Имена собственные удаляются тремя способами.
|
|
||||||
|
|
||||||
Первый способ: по морфологическим тегам:
|
|
||||||
|
|
||||||
```python
|
|
||||||
Name, Surn, Patr, Geox, Orgn
|
|
||||||
```
|
|
||||||
|
|
||||||
Так удаляются имена, фамилии, отчества, географические названия и организации, если их распознал `pymorphy3`.
|
|
||||||
|
|
||||||
Второй способ: по списку отдельных слов:
|
|
||||||
|
|
||||||
```python
|
|
||||||
PROPER_WORDS
|
|
||||||
```
|
|
||||||
|
|
||||||
Например:
|
|
||||||
|
|
||||||
```text
|
|
||||||
москва, россия, рф, ельцин, интернет
|
|
||||||
```
|
|
||||||
|
|
||||||
Третий способ: по устойчивым словосочетаниям:
|
|
||||||
|
|
||||||
```python
|
|
||||||
PROPER_PHRASES
|
|
||||||
```
|
|
||||||
|
|
||||||
Например:
|
|
||||||
|
|
||||||
```text
|
|
||||||
российская федерация
|
|
||||||
государственная дума
|
|
||||||
федеральный закон
|
|
||||||
уголовный кодекс
|
|
||||||
центральный банк
|
|
||||||
```
|
|
||||||
|
|
||||||
Сначала слова в строке лемматизируются, затем функция `find_phrase_positions()` ищет такие фразы среди лемм и помечает их позиции как лишние.
|
|
||||||
|
|
||||||
## Фильтрация одной строки
|
|
||||||
|
|
||||||
Основная функция для одной строки:
|
|
||||||
|
|
||||||
```python
|
|
||||||
good_words_from_line(line)
|
|
||||||
```
|
|
||||||
|
|
||||||
Она делает следующее:
|
|
||||||
|
|
||||||
1. Разбивает строку на слова.
|
|
||||||
2. Для каждого слова находит лемму и морфологические теги.
|
|
||||||
3. Находит позиции слов, которые входят в имена собственные из нескольких слов.
|
|
||||||
4. Проверяет каждое слово функцией `is_bad_word()`.
|
|
||||||
5. Возвращает только подходящие слова.
|
|
||||||
|
|
||||||
## Подготовленный текст
|
|
||||||
|
|
||||||
Функция:
|
|
||||||
|
|
||||||
```python
|
|
||||||
prepare_text(text)
|
|
||||||
```
|
|
||||||
|
|
||||||
проходит по строкам исходного текста, оставляет только хорошие леммы и склеивает их обратно в строки.
|
|
||||||
|
|
||||||
Результат записывается в:
|
|
||||||
|
|
||||||
```text
|
|
||||||
output/uk_rf_prepared.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
## Где используется processor
|
|
||||||
|
|
||||||
`good_words_from_line` экспортируется в `modules/index.py`, где используется для построения предметного указателя. Логика подсчёта частот и записи результатов находится в `index.py`, а не здесь.
|
|
||||||
@@ -22,7 +22,7 @@ def main():
|
|||||||
subject_index = build_subject_index(original_text, top_n=100) # Строим предметный указатель
|
subject_index = build_subject_index(original_text, top_n=100) # Строим предметный указатель
|
||||||
|
|
||||||
(output_dir / "uk_rf_original.txt").write_text(original_text, encoding="utf-8") # Вывод исходного текста в файл
|
(output_dir / "uk_rf_original.txt").write_text(original_text, encoding="utf-8") # Вывод исходного текста в файл
|
||||||
(output_dir / "uk_rf_prepared.txt").write_text(prepared_text, encoding="utf-8") # Вывод токенизированного и обработанного текста в файл
|
(output_dir / "uk_rf_prepared.txt").write_text(prepared_text, encoding="utf-8") # Вывод обработанного текста в файл
|
||||||
|
|
||||||
write_subject_index_csv(subject_index, output_dir / "uk_rf_subject_index.csv") # Вывод предметного указателя в csv
|
write_subject_index_csv(subject_index, output_dir / "uk_rf_subject_index.csv") # Вывод предметного указателя в csv
|
||||||
write_subject_index_json(subject_index, output_dir / "uk_rf_subject_index.json") # Предметные указатель в json
|
write_subject_index_json(subject_index, output_dir / "uk_rf_subject_index.json") # Предметные указатель в json
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ START_URL = "https://www.consultant.ru/document/cons_doc_LAW_10699/" # Базо
|
|||||||
FIRST_ARTICLE_URL = START_URL + "e8ecf933c52a85d9223094e0e7fbf52f0128d399/" # Первая статья (для детерминированности обхода)
|
FIRST_ARTICLE_URL = START_URL + "e8ecf933c52a85d9223094e0e7fbf52f0128d399/" # Первая статья (для детерминированности обхода)
|
||||||
|
|
||||||
ARTICLE_RE = re.compile(r"^\s*(?:УК РФ,?\s+)?Статья\s+\d+(?:\.\d+)?\.", re.IGNORECASE)
|
ARTICLE_RE = re.compile(r"^\s*(?:УК РФ,?\s+)?Статья\s+\d+(?:\.\d+)?\.", re.IGNORECASE)
|
||||||
STRUCTURE_PREFIX_RE = re.compile(r"^\s*(?:\d+(?:\.\d+)*|[а-яё])[\.)]\s+", re.IGNORECASE)
|
STRUCTURE_PREFIX_RE = re.compile(r"^\s*(?:\d+(?:\.\d+)*|[а-яё])[\.)]\s+", re.IGNORECASE) # Строки, начинающиеся с нумерованного или буквенного маркера списка.
|
||||||
SPACE_RE = re.compile(r"[ \t\r\f\v]+")
|
SPACE_RE = re.compile(r"[ \t\r\f\v]+")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user