Подписка


Подписаться на Google Buzz

Друзья блога

Пульс блога

Опрос

Каких статей следует публиковать больше в блоге?

View Results

Loading ... Loading ...

Система Orphus

Блоги и сообщества

DelphiFeeds.ru - Все Delphi-блоги Рунета О раскрутке блога по программированию

Счётчики


Анализ веб сайтов

Рейтинг блогов

  • 19Oct

    В прошлой статье про выдачу Яндекса я привел лишь один вариант и один пример парсинга выдачи с целью определения позиции сайта в результатах поиска Яндекс. На самом деле нет ничего сверхъестественного в написании подобных компонентов под свои нужды.

    парсинг поисковиков

    А если учесть то обстоятельство, что мы не используем для парсинга всякого рода ухищрения наподобие прокси, потоков и т.д., а лишь делаем небольшую паузу между запросами документов, то задача становится и вовсе простой. Всё, что по сути от нас требуется – определить шаблон страницы с выдачей, написать регулярку и чуть-чуть исправить первоначальный алгоритм парсинга, чем мы сегодня и займемся.
    В качестве своих “подопытных” я выбрал следующие поисковые системы:

    • Яндекс
    • Google
    • Bing
    • Rambler
    • Mail.ru
    • Yahoo
    • Апорт

    В принципе, для наглядного примера этих ПС будет вполне предостаточно. Если возникнет желание дополнить список, то думаю, после прочтения этой статьи, проблем у Вас не возникнет.

    Первое с чего я обычно начинаю подобного рода работы – забиваю в поисковую форму запрос и пробую найти шаблон URL для перехода по страницам поисковой выдачи. При этом также следует учесть одно очень важное обстоятельство – чем больше ссылок на одной странице вернет нам поисковая система, тем меньше нам потребуется обращаться к ней, а следовательно и сам парсинг пройдет быстрее. Для этого желательно пользоваться расширенным поиском, которые имеет практически любая поисковая система. Итак, приступим. Про Яндекс уже говорили, поэтому сегодня первым на очереди стоит Google. Сразу же заходим на страницу расширенного поиска и забиваем любой запрос, например “Delphi в Internet”

    Google расширенный поиск

    Количество результатов выбираем по максимумы – 100. Жмем “Поиск в Google” и попадаем на страницу с результатами. Получаем URL следующего вида:

    http://www.google.ru/search?as_q=Delphi+%D0%B2+Internet&hl=ru&newwindow=1&num=100&btnG=Поиск+в+Google&as_epq=&as_oq=&as_eq=&lr=&cr=&as_ft=i&as_filetype=&as_qdr=all&as_occt=any&as_dt=i&as_sitesearch=&as_rights=&safe=images

    Длинно, непонятно и вообще не эстетично. Пробуем упростить URL без потери первоначального содержания страницы. У меня получился вот такой:

    http://www.google.ru/search?as_q=Delphi+в+Internet&num=100

    Но это только пол дела – первая страница, а надо определить общий для всех страниц поиска шаблон. Не долго думая, переходим на вторую страницу и опять производим те же манипуляции с URL. В результате Вы должны получить, что-то наподобие:

    http://www.google.ru/search?hl=ru&num=100&q=Delphi+в+Internet&start=100

    Что нам это дало? А то, что мы теперь можем легко сопоставить два URL и вывести общий шаблон для этих и последующих страниц выдачи. Проводим последнюю проверку:
    Если в URL второй страницы поиска поставить в параметр start вместо 100 ноль, то мы должны попасть на первую страницу поиска. Если это произойдет – шаблон найден. Проверяем:

    http://www.google.ru/search?hl=ru&num=100&q=Delphi+в+Internet&start=0

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

    http://www.google.ru/search?hl=ru&num=100&q=[ЗАПРОС]&start=[СТРАНИЦА*100]

    Двигаемся дальше – составляем регулярное выражение для парсинга. Здесь, признаться я несколько потерялся. Дело в том, что Google может выдавать для одного домена несколько результатов в которых один – основной, второй – дополнительный и оба видны на странице выдачи. Выглядит это примерно так:

    Google результаты выдачи

    Общее число URL сайтов на странице, включая дополнительные результаты, как и было задано 100. И как тут определить позицию в выдаче: с дополнительными результатами или без? Так как я далеко не web-мастер и не SEO-шник, то решил немного подстраховаться – написал сразу два регулярных выражения:
    Для всей выдачи регулярка получилась такая:

    Если же требуется отсеять повторяющиеся домена, то можно написать регулярное выражение так:

  • Думаю, что смысл поиска шаблона страницы Вам понятен. Регулярные выражения тоже из себя ничего сверхъестественного не представляют, просто в отдельную группу выносится адрес сайта и все. Поэтому, чтобы не расписывать ещё пять раз этот же алгоритм – просто приведу список шаблонов страниц и регулярных выражений для каждого поисковика из списка и приступим уже, как говориться, кодить.

    Bing

    Шаблон страницы поиска:

    http://www.bing.com/search?q=[ЗАПРОС]&filt=all&first=[КОЛИЧЕСТВО_URL_НА_СТРАНИЦЕ+1]&FORM=PERE1

    К сожалению не нашел в этом поисковике где регулируется количество выдаваемых запросов на страницу.
    Регулярное выражение:

    Rambler

    Шаблон страницы поиска:

    http://nova.rambler.ru/srch?query=[ЗАПРОС]&pagelen=50&page=[СТРАНИЦА]

    Выдается 50 результатов на страницу. В отличие от Яндекс и Google у Рамблера нумерация страниц идет не с нуля (как полагается у программистов :) ), а с единицы и это обстоятельство надо будет учесть при построении алгоритма.
    Регулярное выражение:

  • Mail.ru

    Шаблон страницы результатов:

    http://go.mail.ru/search?q=[ЗАПРОС]&num=40&sf=[НОМЕР_СТРАНИЦЫ*40]

    Нумерация страницы начинается с нуля.

    Yahoo

    Шаблон страницы результатов:

    http://ru.search.yahoo.com/search?n=100&ei=UTF-8va=[ЗАПРОС]&xargs=0&pstart=1&b=[НОМЕР_СТРАНИЦЫ*100+1]

    Регулярное выражение

    <a class="yschttl spt" href="http:.*?http.*?//(.*?)"

    Апорт

    Шаблон страницы результатов:

    http://sm.aport.ru/scripts/template.dll?r=[ЗАПРОС]&p=[НОМЕР_СТРАНИЦЫ]

    Нумерация, как и полагается у порядочных программистов, начинается с нуля.
    Регулярное выражение:

    .*n.*s.*?

    Признаться, исходник страницы результатов Апорта просто пестрит непонятными переводами на новую строку, кучей пробелов и прочими вещами, ухудшающими самочувствие при составлении регулярного выражения. Постарался сделать его как можно точнее – вроде бы по десятку различных запросов ошибок не было.
    Теперь, имея в руках все необходимые данные для парсинга, можно приступать к программированию на Delphi.
    Я решил, что лучше всего не создавать 7 отдельных компонентов для каждого поисковика, а просто доработать немного уже готовый компонент для парсинга выдачи Яндекс. И так как основные сведения о нем уже достаточно подробно описаны, то здесь я расскажу только то, что касается непосредственной его доработки. Итак, во-первых, теперь каждый поисковик может быть задан в свойствах компонента. Для того, чтобы облегчить немного процесс настройки компонента, каждый поисковик в компоненте описан константой следующего вида (для Google):

    GoogleStr: array [1..2] of string = ('http://www.google.com/search?q=%s&&num=100&&hl=ru&&start=%d',
    '
    

    ')

    Чтобы выбрать необходимую для парсинга выдачи поисковую систему, в компоненте определено свойство типа:

    type
      TIncFormula = (tiYandex, tiGoogle, tiBing, tiYahoo, tiMail, tiRambler, tiAport);

    которая определяет:
    1. Шаблон страницы с выдачей и регулярное выражение
    2. Номер в URL, определяющий номер страницы с выдачей в поисковой системе.
    Номер в URL, определяющий номер страницы, определяется следующим образом:

    function TYaParser.NextInc(var CurrPage: integer): integer;
    begin
      case FIncFormula of
        tiYandex,tiAport: result:=CurrPage;
        tiRambler: result:=CurrPage+1;
        tiGoogle:  result:=CurrPage*100;
        tiBing:    result:=CurrPage*10+1;
        tiYahoo:   result:=CurrPage*100+1;
        tiMail:    result:=CurrPage*40;
      end;
    end;

    где CurrPage - переменная в цикле, определяющее номер сачиваемой страницы поисковика. Чтобы стало предельно ясно как это работает, приведу ещё раз функцию для парсинга выдачи и определения положения сайта, но уже с внесенными изменениями:

    function TYaParser.FindPos(Key: string): integer; // поиск позиции домена
    var
      Page, i, LinkNum: integer;
      TextList: TStringList;
      isFind: boolean;
      RE: IRegExp2;
      mc: MatchCollection;
      mm: Match;
      sm: SubMatches;
      FindedLink: string;
    begin
      Page := 0;//принимаем, что первая скачиваемая страница имеет порядковый номер 0
      LinkNum := 0;
      while (isFind = false) and (LinkNum < FCountPos) do
        begin
          if FActive then     begin       {скачиваем страницу, сразу определяя все необходимые данные для шаблона}
          if  DownloadPage(StringBuilder(FNextPage, Key, NextInc(Page)), TextList) then
              begin
                 TextList.Text := Utf8ToAnsi(TextList.Text); //перекодируем в ANSI
    // начинаем парсить страницу
                  try
                    try
                       RE := coRegExp.Create as IRegExp2;
                       RE.Pattern := FRegular;
                       RE.Global := true;
                       RE.IgnoreCase := true;
                       RE.Multiline := true;
                       mc := RE.Execute(TextList.Text) as MatchCollection;
                       for i := 0 to mc.Count - 1 do // проходим по порядку все совпадения
                         begin
                           mm := mc[i] as Match;
                           sm := mm.SubMatches as SubMatches;
                           FindedLink := sm.Item[0];// проверка, является ли ссылка искомой (входит ли она подстрокой в найденную)
                           inc(LinkNum);
                          if Pos(FDomain, FindedLink) > 0 then
                            begin
                              isFind := true;
                              Result := LinkNum;
                              break;
                            end;
                end;
              except
                if Assigned(FOnError) then
                  OnError('Ошибка парсинга полученных данных');
              end;
              if mc.Count = 0 then
                LinkNum := FCountPos; // если совпадения не были найдены
            finally
              RE := nil;
              FreeAndNil(TextList);
            end;
            inc(Page);
            Sleep(FTimeShift); // ждем заданное время перед повторным скачиванием
          end
          else
          begin
            Result := -1; // если была ошибка при скачивании страницы, то результат не достигнут
            Exit;
          end;
        end
      end;
    end;

    При этом функция StringBuilder производит простую замену ключевых подстрок %s и %d на поисковый запрос и номер соответственно:

    function TYaParser.StringBuilder(const Template, Key: string; Page: integer)
      : string;
      function StrReplace(const Str, Str1, Str2: string): string;
      var
        P, L: integer;
      begin
        Result := Str;
        L := length(Str1);
        repeat
          P := Pos(Str1, Result); // ищем подстроку
          if P > 0 then
          begin
            Delete(Result, P, L); // удаляем ее
            Insert(Str2, Result, P); // вставляем новую
          end;
        until P = 0;
      end;
    begin
      Result := StrReplace(Template, '%d', IntToStr(Page));
      Result := StrReplace(Result, '%s', Key);
    end;

    Вот так, не прибегая к коренной переделке всего алгоритма парсинга выдачи Яндекс мы смогли разработать компонент для парсинга сразу семи поисковых систем. Кстати сказать, Вы и сейчас можете использовать компонент парсинга Яндекс (старый вариант) для парсинга, например Апорта - просто задайте в компоненте вручную шаблон и регулярное выражение. В шаблоне обязательно должня быть подстроки %s и %d.
    Ну, а пока Вы тренируетесь в работе с поисковыми системами я всё-таки попробую сделать компонент, который будет парсить всё, что потребуется в потоках. Тем более, что Серёга уже как можно более подробно постарался донести до нас информацию по разработке многопоточных приложений.

    Мой блог находят по следующим фразам

    Мой блог находят по следующим фразам

    Для того, чтобы быть в курсе последних обновлений блога WebDelphi.ru Вы можете:
    Подписаться на RSS
    Подписаться на рассылку по e-mail
    Подписаться на RSS-трубу Delphi и получать новости сразу пяти блогов по программированию на Delphi
    Закладки:
    • Print
    • Digg
    • Sphinn
    • del.icio.us
    • Facebook
    • Mixx
    • Google Bookmarks
    • RSS
    • FriendFeed
    • LinkedIn
    • Live
    • Twitter
    • Twitthis

    Похожие записи:

    1. Простейший компонент Delphi 2010 для парсинга выдачи Яндекс.
    2. Сбор статистики поисковых систем. Компонент Delphi 2010.

    Автор Vlad в 8:50 am

    Метки: , , , , , , , ,

1 Comment

WP_Cloudy
  • progg.ru пишет:

    Парсинг выдачи поисковых систем. Примеры регулярных выражений и их применения на практике. | Delphi в Internet…

    Thank you for submitting this cool story – Trackback from progg.ru…

Ваш ответ

Внимание: Все комментарии модерируются, и это может вызвать задержку их публикации. Отправлять комментарий заново не требуется.

Пожалуйста, заключайте программный код в теги [code][/code].


Protected by Copyscape Duplicate Content Detector