Введение
В статье рассматривается парсинг/скрапинг перечня террористов юридических лиц с сайта Росфинмониторинга. Скрапинг реализуем с помощью языка Python и библиотеки Selenium.
Программа будет заходить на страницу Росфинмониторинга,
находить список юридических лиц и построчно преобразовывать информацию в табличный вид, как на картинке ниже.
Саму программу я писал, ориентируясь только на первые 12 строк, поэтому допускаю, что при обработке всего списка программа может некачественно сработать, поэтому хотел бы подчеркнуть, что статья носит образовательный характер, и не описывает разработку реальной программы.
Решение похожей задачи, но с другим подходом к решению, можно посмотреть в статье: Парсинг (скрапинг) перечня террористов физических лиц
Особенности программы:
- Извлекает первые 12 записей из перечня террористов с сайта https://www.fedsfm.ru/
- Преобразовывает информацию, для дальнейшей работы с ней
- Результат сохраняем в БД PostgreSQL, которую разворачиваем заранее
У статьи есть продолжение Нахождение террориста в перечне террористов, где будет рассматриваться интересный способ нахождения организации в черном списке, приближенный к тому, что я реализовывал в банках.
За пределами статьи:
- заранее были подготовлены файлы для работы с виртуальной средой. О том, как их подготавливать, описываю в отдельной статье: https://dzen.ru/a/aEKVHTM_GULyazKa
- стартовые исходники для статьи лежат в GitLab. В рамках статьи не объясняется, как устанавливать и настраивать git. Всё это описываю в отдельной статье: https://dzen.ru/a/aGgSbU4TnF-_7wL_
- должна быть установлена БД PostgreSQL. Установку рассматриваю в статье: https://dzen.ru/a/aEvZ9r7Yj290D80N
- должен быть установлен Google Chrome
В конце статьи есть ссылка в GitLab на финальную версию программы.
Используемые технологии
ОС: Windows 10
Язык: Python 3.12
Основные библиотеки: re, selenium, pyodbc, pydantic
Прочее: PostgreSQL 17.5, Google Chrome
План работы
- Клонируем репозиторий с GitLab
- Настраиваем виртуальную среду
- Поднимаем БД
- Планируем архитектуру программы
- Создаём программу
- Запускаем программу
Клонируем репозиторий с GitLab
Создадим папку "scrapper_ul", куда будем клонировать репозиторий
mkdir scrapper_ul
Клонируем репозиторий
git clone https://gitlab.com/pytechnotes1/scrapper_ul scrapper_ul
Заходим в папку
cd scrapper_ul/
Делаем чекаут версии коммита, который я сделал специально для статьи
git checkout 472678ecdf4a7d55f1f9bc1ce9bcbb2b464d5ea7
Настраиваем виртуальную среду
Открываем в cmd наш проект scrapper_ul и создать виртуальную среду
py -3.12 -m venv venv
Активируем среду
venv\Scripts\activate
Производим установку библиотек из файла, который я подготовил заранее
pip install -r requirements.txt
Выходим из виртуальной среды
deactivate
Поднимаем БД
Поднятие БД подробно объясняется в статье https://dzen.ru/a/aEvZ9r7Yj290D80N.
В рамках этой статьи предоставлены два готовых bat-файла, которые лежат в папке postgresql:
- 1_load_service.bat - файл поднимает БД в виде службы на Windows.
Перед запуском файла, откройте его в текстовом редакторе и замените путь к zip-файлу с postgresql
Когда запустите файл, вам необходимо будет придумать и ввести 2 раза пароль от суперюзера с именем: postgres
В результате запуска bat-файла в Диспетчере задач в Службах должна появиться служба ServPostgre17
Также в папке, где запускали bat-файл, должна появиться папка ServPostgre17. Если папка не появилась, а служба запущена, то, скорее всего, папка ServPostgre17 появилась в вашей пользовательской папке: C:\Users\ВашЮзер
- 2_create_database.bat - файл создает БД, юзера и таблицы, к которым обращается программа.
Когда запустите файл, вам будет необходимо ввести пароль от юзера postgres (который вводили при запуске 1_load_service.bat)
Планируем архитектуру программы
Заранее уже готова определенная структура программы.
- app.py - скрипт, который будет запускать нашу программу.
- settings.py- скрипт-конфиг. Его править нет необходимости, однако, если у вас своя БД для подключения, конечно, укажите свою строку для подключения.
- fedsfm.py - скрипт с нашей программой, которую мы будем реализовывать.
- dloader.py - скрипт, который занимается извлечением информации с сайта Росфинмониторинга.
- ul_parser.py - скрипт, который занимается обработкой информации, которую извлёк dloader.py
Создаём программу
Начнем реализацию с файла fedsfm.py
Реализуем конструктор __init__:
В момент создания экземпляра класса TerroristsListUL будут созданы:
- self.dloader- объект DLoader, который мы создадим позже. Основной задачей объекта будет являться извлечение информации с сайта Росфинмониторинга. DLoader будет принимать объект-конфиг, который мы создадим в этом же файле.
- self.parserUL- объект ParserUL, который мы создадим позже. Основной задачей объекта будет являться извлечение структурированной информации из списка террористов, который мы извлекли с помощью DLoader.
- self.sql_insert - sql скрипт для записи в БД
Создадим класс SFM
Укажем необходимые импорты
import pyodbc
from pydantic import BaseModel
import settings
from dloader import DLoader
from ul_parser import ParserUL
Реализуем метод run и декоратор _connection_db:
В методе run к self.dloader обращаемся через конструкцию with, для этого нам необходимо в классе DLoader реализовать методы __enter__ и __exit__.
Это мы делаем для того, чтобы, если при работе с DLoader произойдет ошибка, открытый браузер мог закрыться.
Через метод _loop_terrorists итерируем список террористов.
Декорируем метод run методом _connection_db. Таким образом планируем реализацию, когда откроется БД, выполнится содержимое метода run и закроется коннекшн к БД.
Реализуем методы _open_db и _close_db
Реализуем методы _loop_terrorists и _set_row
Метод _loop_terrorists итерируется по неструктурированным данным террористов и через метод prepare_rows класса ParserUL формируем структурированный набор данных, который построчно записывается в БД с помощью метода _set_row.
На этом реализация класса TerroristsListUL завершена, перейдем к реализации класса DLoader.
Откроем файл dloader.py
Из архитектуры класса видно, что мы должны реализовать:
- конструктор класса __init__
- и методы __enter__ и __exit__ , реализовав которые, DLoader станет менеджером контекста и сможет вызываться через оператор with
Приступим к реализации конструктора класса __init__
Конструктор забирает из конфига необходимую для себя информацию:
- config.site - ссылка на страницу Росфинмониторинга, где лежит список террористов
- config.wait - время ожидания (в секундах) отклика/прогрузки информации на странице сайта
- config.xpath - xpath, с помощью которого будет извлекаться информация.
В конструкторе указываем переменную _terrorist_list, она будет содержать неструктурированную информацию о террористах с сайта. Обращение к переменной реализуем через property.
Программа будет работать через браузер Google Chrome. Если в этом браузере открыть перечень террористов, то через меню Инструменты разработчика (Ctrl+Shift+I) можно найти теги, где лежит информация о террористах.
В конфиге уже указан готовый xpath, который нужен для извлечения информации. Запись [position()<=12] означает, что только первые 12 строк будем брать из всего списка.
//div[@id='russianUL']//ol[@class='terrorist-list']/li[position()<=12]
Реализуем методы __enter__ и __exit__
Так как это учебная программа, я эти методы реализую без try / except
Метод __enter__ открывает браузер, ожидает прогрузки контента и извлекает информацию о террористах.
Метод __exit__ закрывает браузер.
Эти методы мы не вызываем явно. Они вызываются сами, когда мы обращаемся к классу через оператор with
Импортируем класс Self
from typing import Self
Приступим к реализации методов из __enter__
Метод _open_website запускает браузер Google Chrome и открывает сайт Росфинмониторинга.
Метод _wait_content ожидает, когда на странице прогрузятся необходимые теги, для извлечения информации.
Метод _set_terrorist_list извлекает информацию и записывает ее в _terrorist_list
Укажем все необходимые импорты
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait as WDW
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
Реализуем property для переменной _terrorist_list
На этом реализацию DLoader завершаем и переходим к файлу ul_parser.py
Из архитектуры класса видно, что мы должны реализовать:
- конструктор класса __init__
- и метод prepare_rows, который будет принимать на вход строку с неструктурированной информацией и возвращать строки для записи в БД
Приступим к реализации конструктора класса __init__
В конструкторе укажем только шаблоны для регулярных выражений.
Давайте откроем конфигурационный файл и изучим регулярные выражения
Изучим устройство шаблонов на примере шаблона pattern_row_number.
Шаблон pattern_row_number имеет два последовательных шаблона поиска нужной подстроки.
Шаблон pattern_remover находит нужную информацию путем удаления лишней информации. Он сначала удаляет порядковый номер записи, потом удаляет ИНН и ОГРН, потом удаляет разные символы, такие как * и -. Как итог, предполагается, что по итогу останется только нужная
Получается предварительно обработанная строка, позже в коде уже не другими языковыми конструкциями завершается обработка строки. Однако, хочется сказать, данный подход, когда ищется информация, путем удаления лишней, ненадежный, так как всегда будет шанс, что не все удаления были предусмотрены.
Так как придется работать с регулярками, добавим импорт
import re
Реализуем методы, которые будут итерировать шаблоны с регулярными выражениями.
Реализуем метод prepare_rows
В рамках строки only_names = self._loop_ptrns(self.ptrn_remover, terrorist) мы получили предварительно обработанную строку с названиями компаний. Давайте с помощью метода _get_ter_names финализируем обработку информации.
Выделил красным строки, которые соединяют первое и второе название компаний, т.к. есть строки, где в скобках идет не отдельное название, а продолжение основного названия.
На этом реализацию программы заканчиваем.
Запускаем программу
Запускаем скрипт через "py", таким образом запустится интерпретатор из виртуальной среды.
py app.py
Откроется браузер, подождем, когда он закроется.
В результате работы программы, в БД появятся данные.
Напишем скрипт, который извлечет данные из БД
Все работает
Исходники проекта
Подписывайтесь на Дзен, а также приглашаю в мой телеграмм канал, там публикую другой, но не менее интересный контент.