уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

tkch1Хотел было назвать пост как-то типо “Текучка”, но потом подумал, что сие название не отразит суть написанного, поэтому переименовал в то, что есть, но по большому счёту – это обычная текучка.

Родилась у меня тут одна мысль по поводу повышения удобства работы с “Пинговалкой”, а именно сделать возможность автоопределения параметров нового проекта, таких как название сайта, ключевые слова, адрес RSS-канала и т.д., т.е. того, что сейчас вручную заносится пользователем. Смысл просто – задаем только адрес главной страницы, жмем кнопку, программка скачивает главную страничку и парсит её в поисках необходимых значений, что не смогли найти автоматом – вбиваем ручками. В принципе задача достаточно тривиальная. Например, про то, как вытаскивать значения различных тегов из HTML-документа я писал чуть ли не два года назад, но возникла небольшая проблемка с относительными ссылками в элементах link документа. Поясню в чем суть.

Если Ваш сайт использует нормальную CMS (а сейчас редко когда встретишь, что-либо иное), то в html-коде страницы часто могут прописываться связи с внешними документами, например, связи с css-файлами, скриптами, а также пути к rss-каналу, atom’у, rdf и пр. Такие связи описываются в html-тегах LINK. Отличием элемента LINK от A (ссылки) заключается в том, что тег link размещается всегда внутри контейнера head и не создает ссылку. Как может выглядеть адрес RSS-канала, заключенного в теге link? В моем блоге эта связь описывается как:

link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="feed/"

На blogspot’е Гугла эта же связь описывается полностью, то есть, например:

link rel="alternate" type="application/rss+xml" title="Flash-отдых — RSS" href="http://true-swf.blogspot.com/feeds/posts/default?alt=rss

Соответственно, задача заключается в том, чтобы вне зависимости от того как определена ссылка: полностью или относительно выдать пользователю полный URL.

Вообще вопрос о работе с относительными ссылками в Delphi поднимался давным-давно в блоге “Парсинг от А до Я” и Маша (автор блога) привела довольно простое рабочее решение проблемы. Но это решение касается только тегов A и на LINK никак не влияет. Поэтому пришлось делать что-то свое.

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

Второй вариант решения задачки – специально для тех, кто во всю использует WinInet. В этой библиотеке есть полезная функция – InternetCombineUrl, которая умеет “склеивать” относительный путь с базовым URL и возвращать полный путь к ресурсу:

function InternetCombineUrl(lpszBaseUrl, lpszRelativeUrl: PWideChar; lpszBuffer: PWideChar; var lpdwBufferLength: DWORD; dwFlags: DWORD): BOOL; stdcall;

где

lpszBaseUrl — базовый адрес, например, http://webdelphi.ru

lpszRelativeUrl – относительный путь, например feed/

lpszBuffer – буфер, в который будет записан итоговый URL

lpdwBufferLength – размер буфера

dwFlags – флаги, определяющие как будет выглядеть итоговый URL (будут ли маскироваться символы и т.д.)

Используя эту функцию можно “склеивать” все относительные ссылки с базовым адресом и получать то, что нам требуется. Теперь, что касается вытягивания с HTML-страницы адреса RSS-канала. Я решил для этого воспользоваться возможностями MSHTML и поразбирать немного элементы DOM. Можно и теме же регулярными выражениями напарсить всё, что необходимо, но, по-момему в данном случае использование MSHTML более предпочтительно. Приведу ту часть кода (подробно расписанную), которая отвечает за получение адреса RSS-канала:

var
  Content: string;//содержимое страницы
  Doc: IHTMLDocument2;
  V: OLEVariant;
  Link: IHTMLElement;
  RelAttr, href, linktype: string;
  links: IHTMLElementCollection;
begin
{получаем контент странички, используя Synapse, Indy, WinInet и т.д.}
    Doc := CoHTMLDocument.Create as IHTMLDocument2;//создаем новый документ
    V := VarArrayCreate([0, 0], varVariant);
    V[0] := Content;
    Doc.write(PSafeArray(TVarData(V).VArray));//записываем полученный контент в документ
    links := Doc.all.tags('link') as IHTMLElementCollection;//получаем коллекцию элементов link
    for I := 0 to links.Length - 1 do
    begin
      Link := links.item(I, 0) as IHTMLElement;//получаем элемент
      RelAttr := Link.getAttribute('rel', 0);//читаем значение атрибута rel
      if Length(Trim(RelAttr)) > 0 then //если атрибут есть, то ссылка может содержать путь к RSS
      begin
        if pos('alternate', lowercase(RelAttr)) > 0 then //rel совпадает с тем, что нам нужно
        begin
          linktype := Link.getAttribute('type', 0);//читаем MIME-тип содержимого ресурса
          if pos(cRSSlinkType, lowercase(linktype)) > 0 then //тип совпал cRSSlinkType='application/rss+xml' 
          begin
            href := Link.getAttribute('href', 0);//получаем значение атрибута href
            RSS := UrlCombine(BASEURL, href);//проверяем URL на "относительность", склеиваем, если надо
            break;
          end;
        end;
      end;
    end;
{чистим память, возвращаем результаты и т.д.}
  end;
end;

 

Здесь в UrlCombine() можно использовать любой из предложенных вариантов работы с относительными ссылками, например, использовать InternetCombineUrl:

var
  I: Cardinal;
begin
{...}
  SetLength(Result, 1024);
  InternetCombineUrl(PChar(ABase), PChar(ARel), @Result[1], I, 0);
  SetLength(Result, I);
{...}
end;

После этого результат стал возвращаться так как надо. Что касается чтения других параметров сайта, то тут все просто и легко. О том как вытаскивать анкоры ссылок типа скайлинк отзывы, значения заголовков, мета-тегов и прочих элементов HTML я тоже довольно давно рассказывал в постах "Что можно «вытащить» из DOM’а?" и "MSHTML в Delphi. Анализ ссылок на странице." так что с этим проблем никаких не возникло. Теперь стараюсь как можно сильнее ускорить работу программы как в плане работы с пинг-сервисами, так и в плане более быстрой работы пользователя с новыми проектами. Вроде бы получается не плохо, по крайней мере работа с базой данных ускорилась на несколько порядков. Так что, пока ковыряюсь в коде – можете предлагать какие новые возможности можно добавить в пинговалку, а также отписываться о найденных ошибках, а я их постараюсь исправить до выхода новой версии.

Книжная полка

Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
купить книгу delphi на ЛитРес
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
купить книгу delphi на ЛитРес
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
0 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии