Пример использования событий для TTCPBlockSocket я уже рассматривал вкратце вот в этом посте. Но, как говориться, “Повторение – Мать учения”. Раз встречаются ещё вопросы, значит рассмотрим вопрос более подробно.
Итак, есть какая-либо абстрактная страница “Икс” на которой содержаться необходимые нам данные.
Наша цель: с минимумом затрат Интернет-траффика скачать необходимые нам данные с помощью THTTPSend и предоставить их пользователю…ну или отправить их на дальнейшую обработку в нашей программе.
Обращаю особое внимание на то, что “с минимумом затрат Интернет-траффика” НЕ времени, т.к. предложенный способ достаточно затратный с точки зрения потерь времени.
Итак, начнем.
Что нам может потребоваться для работы? В принципе, я бы определил свой набор “инструментов” следующим образом:
- любой браузер
- Synapse (само собой) – для скачивания данных
- Любая библиотека для работы с регулярными выражениями в Delphi, например нововведение Delphi XE – TRegExp – для парсинга данных.
Мы же сегодня ограничимся только первыми двумя пунктами, т.к. слишком громоздкий пример рассматривать смысла нет, а небольшого примерчика использования события соккета будет вполне достаточно, чтобы вы смогли написать сколь угодно сложную программку самостоятельно.
Теперь о том, что будем искать. Искать будем, наверное, одно из самых популярных значений – заголовок веб-странички, например про социальную сеть Фейсбук (кстати, в последнее время частенько захожу в Facebook, так что, если что – милости прошу).
Результатом выполнения нашей программы будет строка “Facebook | BigCorp — от стартапа к корпорации”.
Теперь открываем Delphi, создаем новое приложение и подключаем в uses модули HTTPSend и blcksock.
Главное окно программы будет до ужаса простым:
Приступим к написанию обработчика события. Обрабатывать будем событие OnReadFilter, процедурный тип которого выглядит вот так:
THookDataFilter = procedure(Sender: TObject; var Value: AnsiString)
Повторение пройденного материала: Value возвращает ту часть данных, которую сокет получил в результате последней операции чтения.
Поэтому определяем глобальную переменную, например:
var AllDocument: string;
И объявляем процедуру в разделе private/public главной формы приложения:
procedure MyFilter(Sender: TObject; var Value: AnsiString);
Сама процедура будет такой:
procedure TForm2.MyFilter(Sender: TObject; var Value: AnsiString); begin AllDocument:=AllDocument+UTF8ToString(Value); if (pos('',AllDocument)>0) then begin Label3.Caption:=GetBetween('<title>',’</title>’,AllDocument); label5.Caption:=IntToStr(Length(AllDocument))+' байт'; TBlockSocket(Sender).CloseSocket; end; end;
Здесь стоит обратить Ваше внимание на три вещи:
- UTF8ToString. Так как сайт в кодировке UTF-8, то перед тем как добавить скачанный текст к тому, что есть мы вначале меняем кодировку. Более подробно о работе с кодировками смотри в посте «3 варианта работы с кодировками веб-страниц в Delphi.«
- Функция GetBetween – возвращает строку, находящуюся между двумя подстроками, в нашем случае – это открывающий и закрывающий теги. Вообще таких функций в Сетке вагон и маленькая тележка. Но код метода рассмотрим чуть ниже.
- После того как нашли то, что искали – закрываем соединение, иначе смысл обработчика просто потеряется – качаться будет весь документ.
Теперь остается самая малость – правильно определить обработчик и проверить работу нашей программки. Пишем обработчик события OnClick кнопки:
procedure TForm2.Button1Click(Sender: TObject); var HTTP: THTTPSend; begin AllDocument:=''; HTTP:=THTTPSend.Create; try HTTP.Sock.OnReadFilter:=MyFilter;//определили обработчик события if HTTP.HTTPMethod('GET',Edit1.Text) then ShowMessage('Документ скачан на 100%'); finally HTTP.Free; end; end;
И, наконец, специально для тех кто не в курсе как вытащить строку, находящуюся между двумя подстроками — листинг функции GetBetween:
function GetBetween(const PairBegin, PairEnd, Value: string): string; var n: integer; x: integer; s: string; lenBegin: integer; lenEnd: integer; str: string; max: integer; begin lenBegin := Length(PairBegin); lenEnd := Length(PairEnd); n := Length(Value); if (Value = PairBegin + PairEnd) then begin Result := '';//nothing between exit; end; if (n < lenBegin + lenEnd) then begin Result := Value; exit; end; s := SeparateRight(Value, PairBegin); if (s = Value) then begin Result := Value; exit; end; n := Pos(PairEnd, s); if (n = 0) then begin Result := Value; exit; end; Result := ''; x := 1; max := Length(s) - lenEnd + 1; for n := 1 to max do begin str := copy(s, n, lenEnd); if (str = PairEnd) then begin Dec(x); if (x <= 0) then Break; end; str := copy(s, n, lenBegin); if (str = PairBegin) then Inc(x); Result := Result + s[n]; end; end;
Проверяем работу программы:
Как видите на поиск заголовка целевой странички мы потратили чуть больше 3-х килобайт трафика при весе страницы в 28 Кб.
Что можно сказать про предложенный выше способ частичного скачивания страницы?
- Обработчик события OnReadFilter хорош, когда в нем выполняется минимум операций – чем более громоздким он будет, тем больше времени “убьется” на фильтрацию и может случиться так, что быстрее будет скачать страницу целиком.
- Метод работает относительно быстро, когда необходимые данные находятся ближе к началу страницы и нет смысла его использовать, когда надо “стянуть” что-то с последних абзацев, футеров и т.д. – экономии пшик, а времени уйдет больше.
- Альтернативой этого события может служить событие OnMonitor, про которое можно прочитать тут.
Исходник рассмотренного в посте примера можно скачать по ссылке ниже:
Книжная полка
Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
|
||
Название: О чем не пишут в книгах по Delphi
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
|
Здравствуйте, статья понравилась, особенно, что расходуется меньше трафика, только мне больше нравится библиотека Indy, надо с ней попробовать. И что-то функция GetBetween слишком громоздкая, можно было сначала просто удалять все символы до искомой подстроки, а затем после искомой удалить все символы с помощью функции Delete
Andrey53, это как раз функция из модуля SynUtils :) Привел её просто для того, чтоб не возникало вопросов по её реализации. А подобных методов в сети валом -один из них как раз ваш
Привет, а если сделать скачивание страницы с использованием range request, указав сколько нужно получить байт от начала страницы, такой вариант лучше использования парсеров
Может и лучше, НО:
1. Где гарантия, что именно в те самые указанные байты попадет нужная информация
2. Всё равно так или иначе придётся парсить все данные на предмет поиска информации :)
Добрый день.
Помогите найти библиотеку synapse для delphiXE. Вот именно для этой версии ну никак не могу найти.
Спасибо.
тут — http://synapse.ararat.cz/doku.php/download
Использую Synapse с D2010 по Delphi XE3 и никогда никаких проблем не было. Сейчас использую XE2 и XE3 — тоже проблем никаких, в XE — тем более проблем не было :)