Парсим сайт для получения УДК иерархии

от автора

Последнее редактирование — 12 марта 2025 года.

Предыстория:

У меня на домашнем ПК скопилось некоторое количество книг в электронном формате. Это в основной массе техническая литература. И мне хотелось всё это систематизировать. Придумывать не хочется, когда в книгах есть УДК, ББК классификаторы. Мне данная классификация в УДК очень даже подходит. А найти программу которая:

  1. получит структуру УДК в виде иерархии

  2. просканирует файлы pdf, и получит УДК коды

  3. создаст по УДК кодам папки

  4. переместит файлы в нужные папки

Этого всего я не нашел. Это лишь самое простое и базовое, что хотелось видеть. А еще хочется поиграться с названиями папок. Например после создания УДК структуры в каждой папке, создавать папку по расширению файла. Например PDF, DJVU. Или добавлять папку с годом книги и туда класть файлы. В общем вариантов много. И решил, что я буду писать небольшие консольные утилиты, которые сделают все это за меня.

Почему не все сразу? Все просто, вопрос во времени. Его как всегда нет, семья, работа, дети. А небольшие утилиты я могу попросить сгенерировать нейросеть, и быстенько проверить, что мне подходит.

Можете ругать меня, на чем белый свет стоит, за код. Я попытаюсь все замечания учесть и внести изменения. Идеи приветствуются.

Готовых таблиц я не нашел. Вероятно это связанно с авторскими правами. Поэтому будем получать таблицу сами.

Для частного использования полные таблицы не нужны. Мне нужны категории по IT, часть по разделам математики ну и пару разделов по философии и психологи.

Создаем maven проект

mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-simple -DarchetypeVersion=1.5

Вам будет предложено ввести groupId, artifactId, version, package

Define value for property 'groupId': ru.mcs.udk Define value for property 'artifactId': udk-site-parser Define value for property 'version' 1.0-SNAPSHOT: 1 Define value for property 'package' ru.mcs.udk: ru.mcs.udk Confirm properties configuration: groupId: ru.mcs.udk artifactId: udk-site-parser version: 1 package: jar  Y: Y

Будет создан проект, который вы уже можете менять.

Добавляем зависимости pom.xml

Для получения данных с сайта я буду использовать jsoup.

<dependency>     <groupId>org.jsoup</groupId>     <artifactId>jsoup</artifactId>     <version>1.15.3</version> </dependency>

Все лишнее можно удалить. У меня получилось так:

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">     <modelVersion>4.0.0</modelVersion>      <groupId>ru.mcs.udk</groupId>     <artifactId>udk-site-parser</artifactId>     <version>1.0</version>     <packaging>jar</packaging>      <properties>         <maven.compiler.source>21</maven.compiler.source>         <maven.compiler.target>21</maven.compiler.target>         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>         <jar.finalName>udk-site-parser</jar.finalName>     </properties>      <dependencies>         <dependency>             <groupId>org.jsoup</groupId>             <artifactId>jsoup</artifactId>             <version>1.15.3</version>         </dependency>     </dependencies>      <build>         <plugins>             <plugin>                 <artifactId>maven-assembly-plugin</artifactId>                 <version>3.7.1</version>                 <configuration>                     <descriptorRefs>                         <descriptorRef>jar-with-dependencies</descriptorRef>                     </descriptorRefs>                     <outputDirectory>${project.basedir}/jar</outputDirectory>                     <finalName>${jar.finalName}</finalName>                     <archive>                         <manifest>                             <addClasspath>true</addClasspath>                             <mainClass>ru.mcs.udk.UdkSiteParser</mainClass>                         </manifest>                     </archive>                 </configuration>                 <executions>                     <execution>                         <id>assemble-all</id>                         <phase>package</phase>                         <goals>                             <goal>single</goal>                         </goals>                     </execution>                 </executions>             </plugin>         </plugins>     </build>  </project>

Плагин maven-assembly-plugin добавлен чтобы сгенерироть jar файл с jsoup в одной jar-ке.

Пишем код парсера

package ru.mcs.udk;  import org.jsoup.Jsoup; import org.jsoup.nodes.Element; import org.jsoup.select.Elements;  import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.nio.charset.StandardCharsets;  public class UdkSiteParser {      public static final String HTTPS_WWW_TEACODE_COM_ONLINE_UDC = "https://www.teacode.com/online/udc";      public static void main(String[] args) throws IOException {         System.setOut(new PrintStream(new FileOutputStream("udk.txt"), true, StandardCharsets.UTF_8));          getHierarchy(HTTPS_WWW_TEACODE_COM_ONLINE_UDC, 0, 15);     }      public static void getHierarchy(String url, int level, int stopLevel) {         try {             var document = Jsoup.connect(url)                     .timeout(5000)                     .followRedirects(true)                     .userAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:25.0) Gecko/20100101 Firefox/25.0")                     .execute().parse();              Elements rows = document.select("table tr[bgcolor=#eaeaea]");              // тут создаем новую переменную которую будем передавать в метод             int nextLevel = level + 1;             for (Element row : rows) {                 Elements udkNumber = row.select("td:eq(0)");                 Elements udkTitle = row.select("td:eq(1)[align=left]");                 System.out.printf("%s%s\t%s%n", "\t".repeat(Math.max(0, level)), udkNumber.text(), udkTitle.text());                  String pageUrl = udkNumber.select("a").attr("href");                 if (!pageUrl.isEmpty() && level < stopLevel - 1) {                     String subUrl = getUrl(url, pageUrl);                      getHierarchy(subUrl, nextLevel, stopLevel);                 }             }         } catch (Exception ex) {             System.out.println(ex.getMessage());         }     }      private static String getUrl(String url, String subUrl) {         if (subUrl.startsWith(".")) {             return String.format("%s%s", HTTPS_WWW_TEACODE_COM_ONLINE_UDC, subUrl.replaceFirst(".", ""));         } else {             return String.format("%s%s", url.replaceAll("/[^/]+\\.html$", "/"), subUrl);         }     } }

В строчке 17 мы переопределяем стандартный вывод в консоль на нужный нам файл.

Строчки 24-28 это получение странички. Таймаут 5 секунд. Можно увеличить если будут ошибки с таймаутами.

Строчка 30 это получение интересующих нас элементов в таблице. Определяется опытным путем.

Строчки 34-45 это сама логика получения уже нужных данных.

Метод getUrl используется для получения пути на подстраницу. Определяется опытным путем. Есть разница в путях на первой странице, поэтому такие условия.

Добавил параметр stopLevel, для того чтобы не получать всю иерархию. А только до определенного уровня. Это больше для тестирования. Выставил в 15 так как там, по моему, больше 10 уровня и нет.

Результат для 2 уровня вложенности получим примерно такой:

00Наука в целом (информационные технологии - 004) 001Наука в целом. Науковедение. Организация умственного труда 002Печать в целом. Документация. Научно-техническая информация (НТИ) 003Системы письма и письменности. Знаки и символы. Семиотика в целом. Коды. Графическое представление мысли 004Информационные технологии. Компьютерные технологии. Теория вычислительных машин и систем 005Изучение проблемы организации: методология, анализ, синтез, классификация и таксономия (теория, основы), систематизация в целом 006Стандартизация и стандарты 007Деятельность и организация. Общая теория информации, связи и управления (кибернетика), включая деятельность человека 008Цивилизация. Культура. Прогресс 009Гуманитарные науки в целом 1Философия. Психология 101Сущность и задачи философии 11Метафизика 122Причинность (каузальность). Первопричинность. Принципы. Causa efficiens. Условие. Действие. Побуждение ...........  9География. Биография. История 902Архелогия 903Предыстория. Доисторические остатки, орудия труда, древности. Интерпретация и синтез материальных остатков древнего человека, его культур и цивилизаций 904Археологические памятники исторических времен. Древности античного, средневекового и нового времени 908Краеведение 91География. Географические исследования Земли и отдельных стран. Путешествия. Региональная география 929Биографические и подобные исследования 93История. Теоретические вопросы 94Всеобщая история

Программа будет выполняться примерно пол часа. Можно открыть файл udk.txt и посмотреть заполняемость файла.

Собираем проект

mvn clean package

Запускаем проект

java -jar .\jar\udk-site-parser-jar-with-dependencies.jar

На этом все. Можно приступать к следующим шагам. Можно теперь парсить pdf и получать УДК. Создавать папки. При создании папок будут конечно проблемы, нужно будет убирать специальные символы. Но это уже другая история и в другой программе.

Код доступен тут: udk-site-parser


ссылка на оригинал статьи https://habr.com/ru/articles/890644/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *