Поиск по блогу

пятница, 16 января 2009 г.

Когда на форме нет места TWebBrowser-у

Еще один пост из серии для начинающих осваивать работу с интернетом в среде Delphi.

Как вы уже поняли, работать с DOM html-страницы гораздо удобнее, чем работать непосредственно с html с помощью регулярных выражений. Но компонент TWebBrowser на форме нам совсем не нужен. Можно просто скачать страницу, а потом создать экземпляр класса coHTMLDocument и работать с ним.

Код, иллюстрирующий сказанное:

uses
... MSHTML, UrlMon, activex;

function DownloadFile(SourceFile, DestFile: string): Boolean;
begin
try
Result := UrlDownloadToFile(nil, PChar(SourceFile), PChar(DestFile), 0,
nil) = 0;
except
Result := False;
end;
end;

procedure TMainF.cxButton1Click(Sender: TObject);
var
sFileName : string;
i: integer;
v : OleVariant;
Doc : IHTMLDocument2;
DocAll,
DocA : IHTMLElementCollection;
AParentElement,
DocElement : IHtmlElement;
SLBody : TStringList;
begin
// загружаем страницу
try
SLBody:=TStringList.Create;

sFileName:=ExtractFilePath(Application.ExeName) + 'cache.txt';
if DownloadFile(RegionURL,sFileName) then
SLBody.LoadFromFile(sFileName);
DeleteFile(sFileName);

Doc := coHTMLDocument.Create as IHTMLDocument2;
if Doc = nil then
begin
ShowMessage('Ошибка создания IHTMLDocument2');
exit;
end;

v := VarArrayCreate([0,0],VarVariant);
v[0] := SLBody.Text;
Doc.write(PSafeArray(TVarData(v).VArray));
DocAll := Doc.all;
DocA := DocAll.Tags('A') as IHTMLElementCollection;

for i := 0 to DocA.length-1 do
begin
DocElement := DocA.Item(i, 0) as IHtmlElement;
AParentElement := DocElement.parentElement;

if LowerCase(AParentElement.tagName) = 'li' then
begin
S := DocElement.innerHTML + ' ['+ DocElement.getAttribute('href',0) +']';
mRequest.Lines.Add(S);
end;
end;
finally
begin
SLBody.Free;
Doc.Close;
Doc := nil;
end;
end;
end;


Как видите, все просто.
В примере показана работа с атрибутом href ссылки. Отличие от работы с атрибутом href ссылок кода, предварительно загруженного в TWebBrowser, будет состоять в том, что относительные ссылки отражаются немного по-другому. Например, если в коде есть ссылка "href=/?region=1", то результатом кода
DocElement.getAttribute('href',0)

будет "about:blank/?region=1". Это связано с тем, что страницей по умолчанию объекта является about:blank. Но это не страшно. Можно их обработать и привести к нужному виду.

Удачных разработок!
___

А сама я помимо программирования решила попробовать поработать с биржей ссылок Nahaa.ru. Если еще не знаете, что это такое и с чем это едят, то можете почитать историю о моем освоении этого сервиса.

Чтобы быть в курсе обновлений блога, можно подписаться на RSS.

Статьи схожей тематики:



9 комментариев:

  1. Доброго времени суток, Маша.

    Да интересный блог. Все бы хорошо, только заинтересовало это
    "Но это не страшно. Можно их обработать и привести к нужному виду."

    Так как вы это обрабатываете??

    ОтветитьУдалить
  2. Да тут уже можно просто применить элементарные делфёвые функции работы со строками — просто заменить about:blank на нужную строку. Например:

    StringReplace(DocElement.getAttribute('href',0),'about:blank','http://yandex.ru',[]);

    Предпоследний аргумент (т.е. строка, на которую надо заменить) берется или вычисляется в зависимости от конкретной задачи. Например, если в коде ссылка всегда относительно корня — это самый элементарный случай. Если такая ссылка в коде скрипта, запускаемого из подкаталога — там уже нужно смотреть и "вычленять" нужную часть строки из адреса загруженной страницы.

    Может, немного несвязно объяснила, но, по-моему, выполнение этих преобразований не должно вызывать вопросов :)

    ОтветитьУдалить
  3. Доброго дня, Маша :)

    Спасибо за ответ. Про реплейс, это конечно красиво, но не то немножко (до этого я и сам допер).
    Дело в том, что у меня например, страничка сохраняется в какой-то каталог. А вместо about:blank. D:/// или другое имя диска.
    Т.е. в итоге немного геммороидально получается заменять реплейсом.

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

    И вообще, что за безобразие в коде одна ссылка, а возвращается какие-то локальные настройки... :)
    ============

    Дополнение.

    Сейчас делаю так (мне не очень нравится):
    1. какачаю с использованием Indy html-ку;
    2. открываю её в WebBrowser;
    3. работаю с DOM-документа;

    Мне понравился ваш метод. Быстрей и правильней.

    Но! При открытие в STtringList все русские символы заменяются кракозябрами.

    После некоторого времени, дошел, что страница с кодировкой UTF-8 а значит и строки нужно преобразовать из UTF-8 в Ansi.

    Функция: Utf8ToAnsi - может кому-то пригодится.

    ОтветитьУдалить
  4. Про глобальную настройку - не знаю, не попадалась такая :) А функцией Utf8ToAnsi регулярно пользуюсь, и в блоге она упоминалась. Но лишнее упоминание не повредит)) Спасибо за комментарий! :)

    ОтветитьУдалить
  5. Мне всё же как-то проще грузить страничку в WebBrowser. А если не хватает места на форме...просто прячу его с глаз долой. Конечно кривенько получатся, но мне не мешает :)

    ОтветитьУдалить
  6. Влад, это вопрос привычки :)

    ОтветитьУдалить
  7. Мария, здравствуйте.
    Подскажите, если можете, такой момент: нужно загружать страницу, причем так, чтобы работали все банеры, счетчики посещений и так далее. При этом нужно реализовать многопоточную работу. Пробовал загружать, как обычно, через TidHttp, но счетчики не учитывают такую загрузку. С WebBrowser вроде работает, но с потоками пока не получается. Поэтому вопрос, описанный в статье способ будет работать как полноценный WebBrowser, но при этом можно будет нормально запускать в отдельном потоке?
    Заранее благодарю за ответ.

    ОтветитьУдалить
  8. Анонимный9 мая 2011 г., 17:30

    А как в этом случае отключить ошибки выполнения скриптов?

    ОтветитьУдалить
  9. Анонимный, а что, они выскакивают? Я не сталкивалась, подсказать не могу.

    ОтветитьУдалить

Комментарии модерируются, вопросы не по теме удаляются, троллинг тоже.

К сожалению, у меня нет столько свободного времени, чтобы отвечать на все частные вопросы, так что, может, свой вопрос лучше задать на каком-нибудь форуме?

Поделиться