Теория лоадеров

    За последние 5 лет я написал множество лоадеров. Это так называемые программки, которые парсят инфу на сайтах-источниках и сохраняют ее себе в базу. Зачастую они представляют из себя последовательность регулярных выражений, с помощью которых находятся значения в нужных клеточках. Лоадеры могут авторизоваться, могут коннектиться через прокси, а иногда даже распознавать защитные картинки. Суть не в этом.

    Теоретическая проблема в том, что невозможно написать абсолютно автоматический лоадер. Мы можем затырить любую инфу, но база превращается в свалку, если лоадер теряет классификацию сайта-источника. А когда начинаем сохранять классификацию, возникает проблема.



    Рассмотрим пример. Пусть есть автосайт, на который грузятся объявления о продаже авто с сотни других ресурсов. Лоадер парсит объяву, выдает массив:

    {марка:"ford", модель:"focus", модификация:"1.6 Ti-VCT 5d", описание: итд...}.

    Автоматический лоадер часто работает так: смотрит в таблице марок по названию, если есть ford — берет id марки, если нет — добавляет «ford» в марки, и берет его id. То же делает с моделью и модификацией. Потом добавляет объявление с полученными id-шниками. Такая система плоха тем, что обязательно найдется объява, в которой на месте марки будет «ФОРД» или не «ВАЗ», а «VAZ», или «автоВаз», или не «Санкт-Петербург», а «С-Петербург»,«СПб»,«Cп-б». Умный гугл поймет, что это синонимы, а наш глупенький лоадер, сверяющий названия посимвольно, нет. В результате получается бардак в таблицах с классификациями.

    Пытаясь минимизировать ручной труд монгола/модератора, я придумал такой алгоритм.

    Прежде всего, лоадер состоит из двух частей.

    Первая — loader_pages.
    Скрипт просматривает страницы со списками объявлений типа вот таких http://cars.auto.ru/cars/used/ford/focus/ и тупо собирает ссылки на отдельные объявы. + находит ссылки на переходы по страницам и идет по ним рекурсией. Нашел ссылку на объяву — добавил ее в базу или, если она уже добавлена, обновил «дату последнего нахождения» на текущую. Это нужно для того, чтобы (лоадер работает ежечасно) удалять объекты, у которых дата нахождения ссылки достаточно старая (это значит, что ссылка уже не найдена, а значит объект с источника был удален).

    Вторая — loader_offer.
    Берет из базы еще не обработанные ссылки, грузит html, парсит. Получает массив типа

    {марка:"ford", модель:"focus", модификация:"1.6 Ti-VCT 5d", описание: итд...}

    Грузит табличку compares. В ней находятся сопоставления, которые будут вручную обрабатываться модератором. Табличка состоит из полей:

    {лоадер,тип,найденное значение,id в соответствующей таблице классификации}.

    В нашем случае,

    {лоадер:"auto.ru",тип:"марка",значение:"ford",сопоставление:"..."}.

    Если соответствующее сравнение уже проставлено, ура победа, берем id-шник. Если нет — добавляем в compares новое сравнение, а объект не добавляем.

    Модератор просматривает не проставленные сравнения и сопоставляет им значения из соответствующих «хороших» наших таблиц с марками автомобилей, моделями, городами итд.

    Паренты.
    Все хорошо работает пока таблицы маленькие. К примеру, марки авто — их всего 100. Сопоставить раз плюнуть. Моделей в моей базе 7000, а модификаций — 20.000. Представляете, из 20 тысяч выбрать сопоставление модификации «1.6 Ti-VCT 5d», которая у меня называется «1.6 Ti-VCT»? Модератор умирает. Или нужен хороший поиск.

    Но можно сделать проще. При загрузке объявы мы будем обрабатывать сравнения по-порядку, сначала марка, затем модель, после модификация. Берем сравнение для марки,

    {лоадер:"auto.ru",тип:"марка",значение:"ford",сопоставление:"..."},

    находим его или добавляем — не суть. Берем id-шник этого сравнения и записываем его в дополнительное поле parent для сравнения модели:

    {лоадер:"auto.ru",тип:"модель",значение:"focus",сопоставление:"...",parent:"id сравнения марки"}.

    То же самое делаем в модификации, в парент которой пишем id сравнения модели.

    Модератор работает по-порядку. Сначала берет сравнения марок и все их проставляет. Потом берет сравнение модели. При этом мы видим, что у сравнения есть parent-сравнение марки, которое уже проставлено, поэтому в качестве вариантов для сопоставления нужно выводить не все возможные модели, а только те, у которых марка соответствует значению этого parent-сравнения. Ну то есть «Ford» проставили, а затем «Focus» выбираем не из 7000 моделей, а только из сотни моделей фордов.

    Суть этого поста вовсе не в том, что я придумал что-то абсолютно новое. Просто нигде не встречал описания этих программ. А у меня мне нравится именно излишняя практичность, потому что в принципе ясно, что каждый объект — подмножество вершин некоторых деревьев, а парсер — это сопоставление элементов html-кода страницы этим вершинам. Можно бы было навести теорию, что-то вроде языка для описания парсеров итд… С другой стороны, средний код лоадера на php у меня занимает 2 страницы. И не ясно, стоит ли париться с теорией, потому как мне не придумать, как еще уменьшить и упростить этот код, даже применив какой-то абстрактный язык.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 28
    • +16
      Я всегда думал, что лоадер — это загрузчик, а то, что вы описали — граббер. о_О
      • +1
        Это для него граббер -)) А для сайтов это — лоадер -))
      • +7
        угу, или граббер или парсер, смотря кому-как нравится. :) О лоадерах тоже первый раз слышу, это типа красивое слово, чтобы не было стыдно, что чужой контент воруется… :)
        • +2
          Ах, да, забыл — информация должна быть свободно… воруемой :)
      • 0
        на хабре если не ошибаюсь проскакивал библиотека, которую автор рекомендовал для граббинга лоадинга :)
        но названия не помню
      • +1
        Граббер (по-вашему лоадер) — это лишь извлечение информации с сайта. И на сколько я понял, с этим у вас ни каких проблем нет. Вопросы у вас возникают с классификацией, упорядочиванием и хранением отпарсенной информации и тут единой методики не существует — все зависит от конкретной задачи.

        Ваш алгоритм, на мой взгяд, не плох, за исключением того, что у него иерархаичная классификация. То есть, если марка «ФОРТ», а не «Ford», то система сразу отбросит эту запись для обработки модератором. А могла бы искать дальше, найти «Focus» и поскольку у других марок такой модели нет, сделать вывод, что это все-таки «Ford». Тоже самое касается и модификаци. Я думаю, что найдя классификацию «1.6 Ti-VCT» тоже вполне можно сделать вывод и том что имеется в виду. Но для этого в классификационной базе должно быть двустороннее сопоставление. Если эту систему грамотно выстроить, то модератор будет круглосуточно пить чай, обрабатывая только совершенные ляпы типа «ВАЗ Focus 600» =)
        • 0
          Спасибо. Конечно, нужно вставить эту проверку. Смотреть, если нет марки, на паренты подходящих моделей, и если найдено только одно значение, подставлять его автоматически. Другое дело, что есть системы похуже марок-моделей. Например, база населенных пунктов. В Финляндии около 20.000, при этом есть две деревни «Хельсинки», а «Лахти» вообще штук 8. Иногда кроме как по тексту объявления и не поймешь, какое же Лахти имеется ввиду на источнике.
          • 0
            И каким именно критерием в тексте выступает четкая локализация конкретного «Лахти»? Я имею в виду, когда человек смотрит за счет какой информации он делает вывод?
            • 0
              Делает вывод за счет своей эрудиции. Обычно если это не основное Лахти, в текстах написано типа «Лахти 10 км от Уусикаупунки». А модератор выводит все Лахти на карту и выбирает нужное.
              • 0
                Нда. Тут модеру ни чем не поможешь =)
                • 0
                  Lahti — Залив (с Финского на Русский)
          • 0
            плюс можно добавить авто-проверку транслитерированных значений
            чтобы автоматом сопоставлялось ВАЗ-VAZ, ЛАДА-LADA и пр.
            в некоторых случаях позволяет несколько сэкономить человеко-время.
            • 0
              Интересно почитать как это делается у других=)
              А у нас есть специальные таблицы синонимов, причём (как писали выше) достаточно совпасть только модели, чтобы определить и производителя. Такой подход, конечно, полностью проблему не устраняет, но очень сильно снижает нагрузку на людей. Ну а что не распозналось, то да — отсматривается и, при необходимости, в базу добавляются новые синонимы.
              • НЛО прилетело и опубликовало эту надпись здесь
                • 0
                  Есть два вопроса:
                  1. Насколько сложно пользоваться гуглом для поиска синонимов (допустим, "wikipedia" обычно даёт первую ссылку на вики-страницу подходящего понятия)?

                  2. Насколько легально использовать заграбленную информацию для коммерческих целей ()?

                  Есть также соображение:
                  Эти подходы очень напоминают алгоритмы поисковиков. Для последнего подхода, парентов, очень просится map-reduce. Думается, что грамотный лоадер — маленький гугл.
                  • 0
                    Лучше бы написал про защиту от грабберов
                    • 0
                      А такие бывают? Мне кажется в лучшем случае система максимального усложнения им жизни =)
                      • 0
                        Защиту от грабберов написать не очень сложно. Первое, что приходит на ум — перед выводом менять случайным образом названия стилей css в коде (соответственно, cssник менять тоже). Только кеширование отключить. Менять местами блоки в контенте. Важно помнить, что сколько человекочасов потратишь на защиту, за столько она и ломается.
                        • 0
                          Ну так это и не защита, а именно усложнение жизни грабберу =) Защита — это когда время взлома намного привышает время потраченное на защиту. А тут ничего подобного не замечается.
                          • 0
                            Кстати тут подумал, что изменять имена классов — это защита пепец грабберу. Особенно в web2.0, где одни дивы на странице. Придется cssник парсить и в нем понимать, какой класс — название параметра, какой — заголовок. А еще мы вообще к каждому элементу на странице прибавим случайный класс, а в css-нике все перемешаем.

                            У меня в Питере был приятель, который занимался шифрованием программ. Вот только те методы не очень подходят к web, поскольку можно зашифровать так, что и поисковики ничего не разберут.
                            • 0
                              Я наверно слабо представляю как работает парсинг. Во всяком случае, всегда считал что парсинг идет по ДОМ-дереву, а не по css =) Оказывается, все намного сложнее =)
                              • 0
                                По dom-дереву то само собой. Но возьмите обычный сайт. У него есть меню, что-то сверху, сбоку, и все это в дивах или таблицах. Посередине контент тоже в дивах и таблицах. Вы ж не будете выбирать типа пятый тег и в нем третий тег в качестве, скажем, цены предложения. Иначе на сайт добавят баннер, и ваш парсер тут же накроется. А вот редизайн делают редко, и названия классов обычно не меняются.
                                • 0
                                  Да, действительно… Это меня не радует, потому что мне в скором времени возможно придется писать подобный парсер. Собственно, именно поэтому я начинаю потихоньку интересоваться этим вопросом. Ты парсишь с помощью какой-то библиотеки или используешь самописный конечный автомат?

                                  И еще есть вопрос по поводу правомерности публикации информации, полученной путем подобного сбора. Знакомые недавно открыли агенство недвижимости и по причине малой раскрученности не имеют своего каталога. Вот и возникла идея собирать инфу с больших городских порталов объявлений и публиковать под девизом «у нас нет своего каталога, наш каталог — весь рынок недвижимости» =) Насколько правомерна такая идея?
                                  • 0
                                    Пишу без библиотек на перле или пхп, стараюсь делать короткие независимые парсеры, больше сплитами чем реплейсами, потому как в случае ошибок на страницах источника последние часто привышают memory_limit, и из-за этого парсер останавливается и не грузит следующие «нормальные» страницы.

                                    Правомерность — скользкий вопрос. Мы обычно спрашиваем разрешение на трансляцию. Скажем, если у нас портал по недвижимости, мы списываемся с агентствами, и они обычно рады, что их предложения будут у нас, поскольку все заявки по объектам все равно переадресовываются им обратно.
                            • 0
                              Главное особо не увлекаться этими защитами, а то получится как с картинками. Знаете, на них раньше то на правую кнопку мыши alert выводили, чтобы не скопировали, то разбивали на много мелких картинок, то во флеш засовывали. А в итоге все равно, если очень хочется — жмакнул принтскрин и вырезал в photoshop. То же и с текстами. Будете наворачивать защиты, а придет школьник Вася и руками скопипастит все по 3 цента за страницу.
                        • 0
                          Просто нигде не встречал описания этих программ.

                          Откройте для себя удивительный мир синтаксического анализа

                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.