Важная заметка: вопросы ниже не предназначены для нарушения каких-либо авторских прав на данные. Все просканированные и сохраненные данные связаны напрямую с источником.
Привет, ребята!
Для клиента я собираю информацию для создания комбинации поисковой системы и веб-паука. У меня есть опыт индексирования внутренних ссылок веб-страниц с определенной глубиной. У меня также есть опыт сбора данных с веб-страниц. Тем не менее, в этом случае объем больше, чем у меня есть опыт, поэтому я надеялся получить некоторые знания и понимание наилучшей практики для этого.
Прежде всего, мне нужно пояснить, что клиент собирается предоставить список сайтов, которые будут проиндексированы. Так что, по сути, вертикальный поисковик. Результаты должны иметь только ссылку, заголовок и описание (например, как Google отображает результаты). Основная цель этой поисковой системы — облегчить посетителям поиск по большому количеству сайтов и результатов, чтобы найти то, что им нужно.
So:
Веб-сайт A содержит множество ссылок -> сохранить все ссылки вместе с метаданными.
Во-вторых, есть более конкретная поисковая система. Эта статья, которая также индексирует все ссылки на статьи (назовем их), распространяется на множество небольших сайтов с меньшим количеством статей по сравнению с сайтами, попадающими в вертикальную поисковую систему. Причина проста: статьи, найденные на этих страницах, должны быть собраны в максимально возможном количестве деталей. Вот в чем заключается первая проблема: для написания скребка для каждого веб-сайта потребуется огромное количество времени, например, необходимо собрать данные: название города, дата статьи, название статьи. So:
Веб-сайт B содержит более подробные статьи, чем веб-сайт A, мы собираемся проиндексировать эти статьи и очистить полезные данные.
У меня в голове есть метод, который может сработать, но он включает в себя написание скребка для каждого отдельного сайта, на самом деле это единственное решение, которое я могу придумать прямо сейчас. Поскольку DOM каждой страницы полностью отличается, я не вижу возможности построить надежный алгоритм, который ищет DOM и «знает», какая часть страницы является местоположением (однако … это возможность, если вы можете сопоставить текст против полного списка городов).
Несколько вещей, которые приходили мне в голову:
Вертикальная поисковая система
Соскоб страницы
the city name lies in "#content .about .city"
,Избыточность данных
Важной частью паука / сканера является предотвращение индексации дубликатов данных. То, что я надеялся сделать, это отслеживать время, когда сканер начинает индексировать веб-сайт, и когда он заканчивается, я также буду отслеживать «время последнего обновления» статьи (на основе URL-адреса статьи) и удалите все статьи, которые старше, чем время начала сканирования. Потому что, насколько я вижу, этих статей больше не существует.
С помощью скребка страниц легче справляться с данными, поскольку мой клиент составил список «хороших источников» (читай: страницы с уникальными статьями). Избыточность данных для системы вертикального поиска сложнее, поскольку индексируемые сайты уже сами выбирают художественные файлы из «хороших источников». Так что есть вероятность, что несколько сайтов имеют выбор из одних и тех же источников.
Как сделать результаты поиска
Это вопрос помимо того, как сканировать и сканировать страницы, потому что, как только все данные сохранены в базе данных, они должны быть доступны для поиска с высокой скоростью. Объемы данных, которые будут сохранены, до сих пор неизвестны, по сравнению с некоторыми конкурентами, у моего клиента было указано около 10000 записей меньшего размера (вертикальный поиск) и, возможно, 4000 записей большего размера с более подробной информацией.
Я понимаю, что это все еще небольшое количество по сравнению с некоторыми базами данных, над которыми вы, возможно, работали. Но в итоге может быть до 10-20 полей поиска, которые пользователь может использовать для поиска того, что он ищет. С большим объемом трафика и большим количеством этих поисков я могу себе представить, что использование обычных запросов MySQL для поиска не является умной идеей.
До сих пор я нашел SphinxSearch и ElasticSearch. Я не работал ни с одним из них и не изучал возможности обоих, единственное, что я знаю, это то, что оба должны хорошо работать с большими объемами и большими поисковыми запросами в данных.
Подводя итог
Подводя итог, вот короткий список вопросов, которые у меня есть:
Я надеюсь, что я все прояснил, и я извиняюсь за огромное количество текста. Я предполагаю, что это показывает, что я уже провожу некоторое время, пытаясь разобраться во всем сам.
У меня есть опыт создания крупномасштабных веб-скребков, и я могу засвидетельствовать, что при выполнении этой задачи всегда будут большие проблемы, которые необходимо преодолеть. У веб-скребков возникают проблемы, начиная от проблем с ЦП и заканчивая хранилищем и сетевыми проблемами, и любой пользовательский скребок должен быть достаточно модульным, чтобы изменения в одной части не повредили приложение в целом. В своих проектах я выбрал следующий подход:
Выясните, где ваше приложение может быть логически разделено
Для меня это означало создание 3 отдельных разделов:
Web Scraper Manager
Веб скребок
HTML-процессор
Работу можно было бы разделить так:
1) Web Scraper Manager
Web Scraper Manager извлекает URL-адреса для очистки и порождает Web Scrapers. Диспетчер веб-скребка должен пометить все URL-адреса, которые были отправлены веб-скребкам, как «активно очищенные», и знать, что их не нужно удалять, пока они находятся в этом состоянии. Получив сообщение от скребков, менеджер либо удалит строку, либо оставит ее в состоянии «активно очищен», если ошибок не было, в противном случае он вернет ее обратно в состояние «неактивно».
2) Веб-скребок
Веб-скребок получает URL-адрес для очистки и начинает оборачивать его и загружать HTML-код. Весь этот HTML может быть сохранен в реляционной базе данных со следующей структурой
ID | URL | HTML (BLOB) | ОБРАБОТКА
Обработка — это целочисленный флаг, который указывает, обрабатываются ли данные в данный момент. Это позволяет другим анализаторам не извлекать данные, если они уже просматриваются.
3) Процессор HTML
Процессор HTML будет постоянно читать из таблицы HTML, помечая строки как активные каждый раз, когда он извлекает новую запись. Процессор HTML может свободно работать с HTML столько времени, сколько необходимо для анализа любых данных. Это могут быть ссылки на другие страницы сайта, которые могут быть помещены обратно в таблицу URL для повторного запуска процесса, любые соответствующие данные (метатеги и т. Д.), Изображения и т. Д.
Как только все релевантные данные будут проанализированы, HTML-процессор отправит все эти данные в кластер ElasticSearch. ElasticSearch обеспечивает молниеносный полнотекстовый поиск, который можно сделать еще быстрее, разбив данные на различные ключи:
{
"url" : "http://example.com",
"meta" : {
"title" : "The meta title from the page",
"description" : "The meta description from the page",
"keywords" : "the,keywords,for,this,page"},
"body" : "The body content in it's entirety",
"images" : [
"image1.png",
"image2.png"]
}
Теперь ваш сайт / сервис может иметь доступ к самым последним данным в режиме реального времени. Анализатор должен быть достаточно многословным, чтобы обрабатывать любые ошибки, чтобы он мог установить флаг обработки на false, если он не может извлекать данные или, по крайней мере, регистрировать их где-то, чтобы их можно было просмотреть.
Каковы преимущества?
Преимущество этого подхода заключается в том, что в любой момент, если вы хотите изменить способ извлечения данных, обработки данных или хранения данных, вы можете изменить только этот фрагмент без необходимости повторной архитектуры всего приложения. В дальнейшем, если одна часть скребка / приложения ломается, остальные могут продолжать работать без потери данных и без остановки других процессов.
Каковы недостатки?
Это большая сложная система. Каждый раз, когда у вас есть большая сложная система, вы просите о больших сложных ошибках. К сожалению, очистка веб-страниц и обработка данных являются сложным делом, и, по моему опыту, я никак не могу найти комплексное решение этой особенно сложной проблемы.
Действия по сканированию и индексированию могут занять некоторое время, но вы не будете сканировать один и тот же сайт каждые 2 минуты, поэтому вы можете рассмотреть алгоритм, в котором вы прикладываете больше усилий для сканирования и индексирования ваших данных, и другой алгоритм, который поможет вам получить более быстрый поиск.
Вы можете постоянно сканировать свои данные и обновлять остальные таблицы в фоновом режиме (каждые Х минут / часов), чтобы результаты поиска всегда были свежими, но вам не придется ждать окончания сканирования ,
ползком
Просто получите все данные, которые вы можете (возможно, весь HTML-код), и сохраните их в простой таблице. Эти данные понадобятся вам для анализа индексации. Эта таблица может быть большой, но вам не нужна хорошая производительность при работе с ней, потому что она будет частью фонового использования и не будет доступна для поисковых запросов пользователей.
ALL_DATA
____________________________________________
| Url | Title | Description | HTML_Content |
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Таблицы и индексирование
Создать большую таблицу, которая содержит URL-адреса и ключевые слова
KEYWORDS
_________________
| URL | Keyword |
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Эта таблица будет содержать большинство слов в каждом контенте URL (я бы удалил такие слова, как «the», «on», «with», «a» и т. Д.)
Создать таблицу с ключевыми словами. Для каждого вхождения добавьте 1 в столбец вхождений.
KEYWORDS
_______________________________
| URL | Keyword | Occurrences |
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Создайте другую таблицу с «горячими» ключевыми словами, которые будут намного меньше
HOT_KEYWORDS
_________________
| URL | Keyword |
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Содержимое этой таблицы будет загружено позже в соответствии с поисковыми запросами.
Наиболее распространенные поисковые слова будут храниться в HOT_KEYWORDS
Таблица.
Другая таблица будет содержать кэшированные результаты поиска
CACHED_RESULTS
_________________
| Keyword | Url |
‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Алгоритм поиска
Сначала вы будете искать в кэшированной таблице результатов. Если у вас достаточно результатов, выберите их. Если нет, ищите больше KEYWORDS
Таблица. Ваши данные невелики, поэтому поиск по индексу ключевых слов не займет много времени. Если вы найдете более релевантные результаты, добавьте их в кэш для дальнейшего использования.
Примечание: вы должны выбрать алгоритм, чтобы сохранить CACHED_RESULTS
таблица небольшая (возможно, чтобы сохранить последнее использование записи и удалить самую старую запись, если кэш заполнен).
Таким образом, таблица кеша поможет вам снизить нагрузку на таблицы ключевых слов и даст вам сверхбыстрые результаты для обычных поисков.
Реализация собственного веб-сканера не так уж и проста, и для поиска обычная СУБД намного сложнее извлекать данные во время выполнения.
У меня был опыт сканирования веб-сайтов, и это действительно сложная тема.
Всякий раз, когда у меня возникают проблемы с этой областью, я смотрю, что делают лучшие люди в этой области (да, Google).
У них есть много хороших презентаций о том, что они делают, и они даже выпускают некоторые из своих инструментов.
phpQuery Например, это отличный инструмент для поиска конкретных данных на веб-сайте, я бы посоветовал взглянуть на него, если вы еще этого не знаете.
Маленькая хитрость, которую я сделал в аналогичном проекте, заключалась в том, чтобы иметь две таблицы для данных.
Данные должны были быть как можно более актуальными, поэтому сканер работал большую часть времени, и были проблемы с заблокированными таблицами. Таким образом, всякий раз, когда сканер записывал в одну таблицу, другая была бесплатной для поисковой системы и наоборот.
Я создал веб-сканер для обнаружения новостных сайтов, и он работает очень хорошо.
Он в основном загружает всю страницу, а затем сохраняет ее, подготавливая ее к другому анализу, который ищет ключевые слова. Затем он в основном пытается определить, является ли сайт релевантным, используя ключевые слова. Смертельно просто.
Вы можете найти исходный код для этого здесь. Пожалуйста, помогите внести свой вклад 🙂
Это целенаправленный сканер, который на самом деле ничего не делает, кроме как ищет сайты и ранжирует их в соответствии с наличием ключевых слов. Его нельзя использовать для больших объемов данных, но он довольно хорош при поиске подходящих сайтов.
https://github.com/herreovertidogrom/crawler.git
Это немного плохо документировано — но я до этого дохожу.
Если вы хотите выполнить поиск по просканированным данным, у вас много данных и вы стремитесь создать службу проверки будущего — вам НЕ следует создавать таблицу с N столбцами, по одному для каждого поискового запроса. Это общий дизайн, если вы думаете, что URL является первичным ключом. Скорее, вы должны избегать дизайна широкого стола, как вредитель. Это связано с тем, что чтения с IO-дисков становятся невероятно медленными при работе с широкими таблицами Вместо этого следует хранить все данные в одной таблице, указать ключ и значение, а затем разбить таблицу на имя переменной.
Избегать дубликатов всегда сложно. По моему опыту, из хранилищ данных — спроектируйте первичный ключ и позвольте БД делать свою работу. Я пытаюсь использовать источник + ключ + значение в качестве первичного ключа, что позволяет избежать двойного счета и имеет несколько ограничений.
Могу я предложить вам создать такую таблицу:
URL, переменная, значение и сделать этот первичный ключ.
Затем запишите все данные в эту таблицу, разбейте их на отдельные переменные и выполните поиск только по этой таблице.
Это позволяет избежать дублирования, это быстро и легко сжимается.
Вы пробовали http://simplehtmldom.sourceforge.net/manual.htm? Я нашел это полезным для удаления страниц и может быть полезным для поиска по содержимому.
использовать asynchronous approach
сканировать и хранить данные, так что вы можете запустить несколько параллельных обхода и хранения
ElasticSearch
будет полезен для поиска хранимых данных.
Вы можете искать HTML, используя этот код:
<?
//Get the HTML
$page = file_get_html('http://www.google.com')
//Parse the HTML
$html = new DOMDocument();
$html->loadHTML($page);
//Get the elemnts you are intersted in...
$divArr = $html->getElementsByTagName('div');
foreach($divArr as $div) {
echo $div->nodeValue;
}
?>