
Я реализовал первый прототип собственного механизма поиска, который сокращённо назвал PSE (Personal Search Engine). Создал я его с помощью трёх скриптов Bash, возложив всю основную работу на sqlite3, wget и PageFind.
Браузер Firefox вместе с Newsboat сохраняют полезную информацию в базах данных SQLite. В moz_places.sqlite содержатся все посещённые URL-адреса и адреса закладок (то есть moz_bookmarks.sqlite базы данных SQLite). У меня получилось около 2000 закладок. Это меньше, чем я предполагал, так как многие оказались нерабочими из-за битых ссылок.
Нерабочие URL-адреса страниц сильно замедляют процесс сбора, так как wget приходится ожидать истечения различных таймаутов (например, DNS, ответа сервера, время скачивания). URL-адреса из «истории» составили бы интересную коллекцию для сбора, но тут не обойтись без списка исключений (например, нет смысла сохранять запросы к поисковым системам, веб-почте, онлайн-магазинам). Изучение этого вопроса я отложу до следующего прототипа.
Кэш Newsboat cache.db обеспечил богатый источник контента и намного меньше мёртвых ссылок (что не удивительно, поскольку я мониторю этот список URL-адресов гораздо активнее, нежели закладки). Из обоих этих источников я собрал 16,000 страниц. Затем с помощью SQLite 3 я запросил из разных БД значения URL, упорядочив их в одном текстовом файле построчно.
После создания списка страниц, по которым я хотел выполнять поиск, нужно было скачать их в каталог с помощью wget. У этого инструмента есть множество настроек, из которых я решил включить регистрацию временны́х меток, а также создание каталогов на основе протокола, сопровождаемого доменом и путём каждого элемента. Это позволило в дальнейшем преобразовать локальные пути элементов в URL-адреса.
После сбора содержимого я использовал PageFind для его индексирования. Поскольку я стал использовать PageFind изначально, то сопроводил этот инструмент опцией --serve, которая предоставляет веб-службу localhost на порту 1414. Всё, что мне требовалось – это добавить файл index.html в каталог, где я собрал всё содержимое и сохранил индексы PageFind. После этого я снова использовал PageFind для предоставления собственного механизма поиска на базе localhost.
И хотя общее число страниц было невелико (16,000), мне удалось получить интересные результаты, просто опробуя случайные слова. Так что прототип получился перспективный.
▍ Текущие компоненты прототипа
Я использую простой скрипт Bash, который получает URL-адреса из закладок Firefox и кэша Newsboat, после чего генерирует файл pages.txt с уникальными URL.
Далее, используя этот файл, с помощью wget я собираю и организую всё содержимое в структуру дерева:
- htdocs
- http (все URL-адреса с типом соединения HTTP);
- https (все URL-адреса с типом соединения HTTPS);
- pagefind (здесь содержатся индексы PageFind и JavaScript-код интерфейса поиска);
- index.html (здесь находится страница для интерфейса поиска, использующего библиотеки из
pagefind).
Поскольку я скачал только HTML, 16K страниц заняли на диске не сильно много места.
▍ Реализация прототипа
Вот скрипты Bash для получения URL-адресов, сбора контента и запуска локального движка поиска на основе PageFind.
После сбора URL-адресов я использую две переменные среды для обнаружения различных баз данных SQLite 3 (то есть PSE_MOZ_PLACES и PSE_NEWSBOAT):
1.#!/bin/bash 2. 3.if [ "$PSE_MOZ_PLACES" = "" ]; then 4. printf "the PSE_MOZ_PLACES environment variable is not set." 5. exit 1 6.fi 7.if [ "$PSE_NEWSBOAT" = "" ]; then 8. printf "the PSE_NEWSBOAT environment variable is not set." 9. exit 1 10.fi 11. 12.sqlite3 "$PSE_MOZ_PLACES" \ 13. 'SELECT moz_places.url AS url FROM moz_bookmarks JOIN moz_places ON moz_bookmarks.fk = moz_places.id WHERE moz_bookmarks.type = 1 AND moz_bookmarks.fk IS NOT NULL' \ 14. >moz_places.txt 15.sqlite3 "$PSE_NEWSBOAT" 'SELECT url FROM rss_item' >newsboat.txt 16.cat moz_places.txt newsboat.txt | 17. grep -E '^(http|https):' | 18. grep -v '://127.0.' | 19. grep -v '://192.' | 20. grep -v 'view-source:' | 21. sort -u >pages.txt
Следующим шагом я с помощью wget получаю страницы:
1.#!/bin/bash 2.# 3.if [ ! -f "pages.txt" ]; then 4. echo "missing pages.txt, skipping harvest" 5. exit 1 6.fi 7.echo "Output is logged to pages.log" 8.wget --input-file pages.txt \ 9. --timestamping \ 10. --append-output pages.log \ 11. --directory-prefix htdocs \ 12. --max-redirect=5 \ 13. --force-directories \ 14. --protocol-directories \ 15. --convert-links \ 16. --no-cache --no-cookies
Наконец, у меня есть скрипт, который генерирует страницу index.html и XML-файл в формате OpenSearch Description, индексирует собранные сайты и запускает PageFind в режиме сервера:
1.#!/bin/bash 2.mkdir -p htdocs 3. 4.cat <<OPENSEARCH_XML >htdocs/pse.osdx 5.<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" 6. xmlns:moz="http://www.mozilla.org/2006/browser/search/"> 7. <ShortName>PSE</ShortName> 8. <Description>A Personal Search Engine implemented via wget and PageFind</Description> 9. <InputEncoding>UTF-8</InputEncoding> 10. <Url rel="self" type="text/html" method="get" template="http://localhost:1414/index.html?q={searchTerms}" /> 11. <moz:SearchForm>http://localhost:1414/index.html</moz:SearchForm> 12.</OpenSearchDescription> 13.OPENSEARCH_XML 14. 15.cat <<HTML >htdocs/index.html 16.<html> 17.<head> 18.<link 19. rel="search" 20. type="application/opensearchdescription+xml" 21. title="A Personal Search Engine" 22. href="http://localhost:1414/pse.osdx" /> 23.<link href="/pagefind/pagefind-ui.css" rel="stylesheet"> 24.</head> 25.<body> 26.<h1>A personal search engine</h1> 27.<div id="search"></div> 28.<script src="/pagefind/pagefind-ui.js" type="text/javascript"></script> 29.<script> 30. window.addEventListener('DOMContentLoaded', function(event) { 31. let page_url = new URL(window.location.href), 32. query_string = page_url.searchParams.get('q'), 33. pse = new PagefindUI({ element: "#search" }); 34. if (query_string !== null) { 35. pse.triggerSearch(query_string); 36. } 37. }); 38.</script> 39.</body> 40.</html> 41.HTML 42. 43.pagefind \ 44.--source htdocs \ 45.--serve
Затем я просто указываю в браузере адрес http://localhost:1414/index.html. При желании я могу даже передать строку запроса ?q=....
С функциональной точки зрения это очень примитивная система, и 16К страниц явно недостаточно для того, чтобы сделать её привлекательной для использования (думаю, для этого нужно где-то 100К).
▍ Чему я научился на этом прототипе
Текущий прототип имеет несколько ограничений:
- Мёртвые ссылки в файле pages.txt значительно замедляют процесс сбора содержимого. Мне нужно найти способ исключить попадание таких ссылок в этот файл или наладить их удаление из него.
- В выводе PageFind используются страницы, скачанные мной на локальную машину. Было бы лучше, если бы получаемые ссылки переводились и указывали на фактический источник страницы. Думаю, это можно реализовать с помощью JS-кода в файле index.html при настройке элемента PageFind, отвечающего за результат поиска. Этот вопрос нужно изучить подробнее.
16K страниц – это очень скромный объём. В ходе тестирования я получил интересные результаты, но недостаточно хорошие для того, чтобы начинать реально использовать эту систему поиска. Предполагаю, что для более-менее полноценного её применения нужно собрать хотя бы 100К страниц.
Очень круто иметь собственный локальный поисковый движок. Он позволит мне продолжать работать, даже если возникнут проблемы с домашним выходом в интернет. Мне это нравится. Поскольку сайт, сгенерированный для моей локальной системы, является «статическим», я могу с лёгкостью воссоздать его в сети и сделать доступным для других машин.
На данный момент значительное время занимает сбор содержимого страниц в индекс. Я пока не знаю, сколько конкретно места потребуется для планируемого объёма в 100К страниц.
Настройка индексирования и интерфейса поиска оказалась простейшим этапом процесса. С PageFind гораздо легче работать, нежели с корпоративными приложениями для поиска.
▍ Предстоящие доработки
Я вижу несколько способов расширения поискового массива. Первый подразумевает создание зеркал для нескольких сайтов, которые я использую в качестве ссылок. В wget есть функция зеркала. Опираясь на список из sites.txt, я мог бы периодически отображать эти сайты, делая их содержимое доступным для индексирования.
Экспериментируя с опцией зеркала, я заметил, что получаю PDF-файлы, привязанные к отображаемым страницам. Если я использую команду Linux find для обнаружения всех этих PDF, то смогу применить другой инструмент для извлечения их текста. Таким образом я расширю свой поиск за пределы простого текста и HTML. Нужно хорошенько продумать этот вариант, так как в конечном итоге я хочу иметь возможность восстанавливать путь к PDF при отображении этих результатов.
Ещё один подход будет заключаться в работе со всей историей браузера и его закладками. Это позволит значительно расширить массив страниц для поиска. Тогда я также смогу проверять «шапку» HTML на наличие ссылок на фиды, которые можно будет агрегировать в общий банк фидов. Это позволит захватывать содержимое из интересных для чтения источников, не пропуская посты, которые оказались бы упущены из-за ограничения времени чтения.
Для просмотра интересных страниц из моего RSS-агрегатора я использую приложение Pocket. У этого приложения есть API, и я могу получать из него дополнительные интересные страницы. В Pocket также есть различные организованные списки, в которых может присутствовать интересное содержимое для сбора и индексирования. Думаю, нужно будет реализовать механизм сопоставления выдаваемых системой предложений с определённым списком исключений. Например, нет смысла пытаться собрать содержимое платёжного шлюза или коммерческих сайтов в целом.
Помоги спутнику бороться с космическим мусором в нашей новой игре! ?
ссылка на оригинал статьи https://habr.com/ru/articles/784504/

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