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

    За последние 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 страницы. И не ясно, стоит ли париться с теорией, потому как мне не придумать, как еще уменьшить и упростить этот код, даже применив какой-то абстрактный язык.
    Поделиться публикацией
    Ой, у вас баннер убежал!

    Ну. И что?
    Реклама
    Комментарии 28
      +16
      Я всегда думал, что лоадер — это загрузчик, а то, что вы описали — граббер. о_О
        +1
        Это для него граббер -)) А для сайтов это — лоадер -))
          +5
          crawler :)
          +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
                            Просто нигде не встречал описания этих программ.

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

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

                            Самое читаемое