Есть еще одна особенность, которую следует учитывать при сравнении URL. В
строковом параметре URL метода Navigate необходимо обязательно указывать протокол
в виде http://, ftp:// или file://, если вдруг понадобится открыть документ на
локальном компьютере. В последнем случае префикс file://, при возникновении события
DocumentComplete, будет опущен. Процедура, предусматривающая этот нюанс, приведена
ниже.
Public Sub InternetExplorerNavigate(ByVal strURL As String)
'-- Процедура
вызывает метод Navigate
'-- для открытия
необходимой Web-страницы
'--
и сохраняет URL в глобальной переменной
If
gblnInternetExplorerIsOpen Then
'-- Сохранение
URL в глобальной переменной
If Left(strURL,
7) <> "file://" Then
gstrURL = strURL
Else
gstrURL
= Mid(strURL, 8)
End If
With gobjWithEvents.IE
'-- URL страницы
отравляется на сервер
.Navigate strURL
End
With
End If
End Sub
Обработка HTML-документа
Все рассмотренные выше процедуры имеют общий характер и могут использоваться
в разных приложениях в неизменном виде. Обработка загруженной Web-страницы зависит
от конкретных потребностей. Ниже будут показаны только начальные возможности.
Прежде всего следует уяснить, что введенный объект Internet Explorer построен
на основе объектной модели Microsoft Internet Controls, которая не содержит каких-либо
средств доступа непосредственно к содержимому документа. Свойство InternetExplorer.Document
предоставляет только ссылку на некий обобщенный объект, не имеющий собственных
свойств и методов. Очевидно, это сделано потому, что компонент Microsoft Internet
Controls предназначен для реализации различных протоколов Internet, а не для работы
с документами. Поэтому первое, что необходимо сделать, это обеспечить процедуру
обработки необходимой объектной моделью документа.
Раз уж речь зашла о Web-страницах, то в качестве объектной модели следует использовать
Microsoft HTML Object Library, то есть именно ту среду, с которой оперируют скрипты
на языках JavaScript и VBScript, создаваемые Web-программистами.
В нашем случае процедура обработки документа вызывается обработчиком события
DocumentComplete из модуля класса Internet Explorer With Events. Это означает,
что некий документ полностью загружен и самое время создавать нужный объект. Создание
объекта выполняется традиционно. Используются описание объектной переменной класса
HTMLDocument и инструкция Set, присваивающая объектной переменной ссылку на объект,
адресуемый свойством Document объекта Internet Explorer. Все остальные объявления
зависят от конкретного применения процедуры. В приведенном ниже примере дополнительно
описана объектная переменная класса HTMLLinkElement, обеспечивающая доступ к семейству
гиперссылок. В начале процедуры выполняется сравнение URL (необходимость которого
была обоснована выше):
Public Sub DocumentComlete(varURL As Variant)
'-- Процедура вызывается событием DocumentComlete,
'-- сравнивает URL загруженной страницы,
'-- создает объект HTML Document
'-- и выполняет необходимые действия с
'-- содержимым Web-страницы
Dim objDoc As HTMLDocument
Dim objLink As HTMLLinkElement
Dim strLink As String
'-- Проверка URL загруженной страницы
If varURL <> gstrURL Then Exit Sub
'-- Создание объекта HTML Document
Set objDoc = gobjWithEvents.IE.document
'-- Обработка документа
With objDoc
'-- Отладочная печать всех полных ссылок
For Each objLink In .links
strLink = objLink.toString
If Left(strLink, 4) = "http" Then
Debug.Print strLink & " " & objLink.innerText
End If
Next
'-- Отладочная печать текста и HTML-кода документа
Debug.Print .body.innerText
Debug.Print .body.innerHTML
End With
Set objDoc = Nothing
End Sub
В рассмотренной процедуре обработки документа выполняется хорошо знакомая всем
офисным программистам конструкция For Each… Next. С помощью этой конструкции осуществляется
просмотр всего множества ссылок в документе с целью выделения и печати ссылок
с полным URL. Нечто подобное можно использовать и при анализе страниц порталов
и поисковых систем.
После цикла обработки ссылок помещены два оператора, печатающие различные представления
документа в целом. Аналогичные свойства можно использовать для разбора как текста,
так и HTML-кода, с помощью собственного алгоритма.
Реализация процесса
Представленные выше четыре процедуры составляют основу механизма взаимодействия
проекта Office с Internet Explorer. Эти процедуры открывают приложение Internet
Explorer, запускают процесс навигации, обрабатывают полученный результат и закрывают
приложение. При этом процессы навигации и обработки могут повторяться многократно —
сообразно интересам пользователя. Список URL открываемых страниц можно задавать
заранее или формировать динамически, основываясь на анализе данных, полученных
при обработке предшествующих страниц. Можно даже определенным образом повторить
работу таких приложений, как Teleport Pro, скачивающих из сети целые сайты.
Как бы то ни было, совершенно очевидно, что для создания работающего проекта
необходима еще одна программа, осуществляющая планирование и диспетчеризацию обращения
к перечисленным процедурам. Необходимость в такой внешней программе мониторе вызвана
еще и тем, что в процессе задействованы ненадежные компоненты и оплачиваемые средства
коммуникации. Вряд ли следует, запустив навигацию, беспечно ожидать непременного
наступления события DocumentComplete. Весь опыт работы с Internet в интерактивном
режиме свидетельствует об обратном. Поэтому при разработке монитора необходимо
позаботится о постоянном контроле над состоянием в режиме online и предусмотреть
переключение процедур, если загрузка очередной страницы затягивается сверх установленного
лимита времени.
Если попытаться сформулировать требования к монитору, то получится, что эта
программа должна обеспечивать следующие функции:
- открывать и закрывать Internet Explorer, в том числе и по желанию пользователя;
- хранить и обновлять список URL, запланированных для обработки;
- хронометрировать продолжительность загрузки отдельной страницы и всего сеанса
работы с Internet;
- запускать очередной процесс навигации как после завершения обработки очередной
страницы, так и по истечении заданного лимита времени;
- переключать режим визуального отображения окна Internet Explorer;
- отображать состояние процесса загрузки очередной страницы.
К этим требованием можно добавить и ведение протокола процесса, если, конечно,
процедуры обработки не предусматривают вывод результатов непосредственно в открытые
документы Office.
Совершенно очевидно, что для удовлетворения всех требований вполне подходит
форма VBA c обычными элементами управления, оснащенная таймером. Пример такой
формы приведен на рисунке.
Список URL хранится в элементе управления ListBox, что позволяет управлять
им проще, чем в случае использования динамических массивов. Элементы управления
CheckBox напрямую связаны с соответствующими свойствами объекта InternetExplorer.
Запуск и остановка процесса выполняются с помощью командных кнопок. Время и состояние
отображаются в обычных окнах TextBox. При этом номер шага и общее количество шагов
берутся непосредственно из свойств ListIndex и ListCount списка URL. Наглядности
ради продолжительность загрузки страницы изображается в виде имитации элемента
ProgressBar.
Что же касается состояния процесса загрузки, то здесь необходимо дать некоторые
пояснения. Объект InternetExplorer имеет очень полезное для контроля состояния
свойство — readyState. Это свойство принимает пять значений: от 0 до 4. Значение
4 соответствует состоянию Complete, переход в которое в нашем примере осуществляется
посредством прерывания и вызова процедуры обработки. Отображая значения указанного
свойства в окне состояния, можно прекрасно ориентироваться в происходящем «за
кадром».
Из приведенного описания программы-монитора и соответствующей формы становится
ясно, что ключевую функцию в процессе несет процедура, вызываемая таймером. Именно
в этой процедуре происходят анализ состояния, визуальное отображение и переключение
процесса. Полный текст этой процедуры приведен ниже:
Private Sub IeTimer_Timer()
'-- Обработка окончания паузы ожидания:
'-- отображение состояния IE,
'-- инициация загрузки следующей страницы,
'-- завершение работы, когда список страниц исчерпан.
TextTime.Value = Format(Now — datStart, "hh:mm:ss")
'-- проверка состояния IE
If gblnInternetExplorerIsOpen Then
Select Case gobjWithEvents.IE.readyState
Case READYSTATE_COMPLETE
TextReadyState.Value = "Complete"
blnDone = True
Case READYSTATE_INTERACTIVE
TextReadyState.Value = "Interactive"
blnDone = False
Case READYSTATE_LOADED
TextReadyState.Value = "Loaded"
blnDone = False
Case READYSTATE_LOADING
TextReadyState.Value = "Loading"
blnDone = False
Case READYSTATE_UNINITIALIZED
TextReadyState.Value = "Uninitialized"
blnDone = False
Case Else
TextReadyState.Value = "Undefined"
blnDone = False
End Select
End If
'-- проверка продолжительности загрузки
If LabelBar.Width \ intBarInc < TIME_LIMIT Then
LabelBar.Width = LabelBar.Width + intBarInc
Else
blnDone = True
End If
'-- загрузка следующей страницы или конец работы
If blnDone Then
If ListURL.ListIndex < ListURL.ListCount — 1 Then
ListURL.ListIndex = ListURL.ListIndex + 1
TextStep.Value = (ListURL.ListIndex + 1) & _
" / " & ListURL.ListCount
LabelBar.Width = 0
InternetExplorerNavigate ListURL.Value
Else
InternetExplorerClose
IeTimer.Enabled = ValFalse
End If
End If
End Sub
Как видно из приведенного текста, переход к очередному этапу осуществляется
с помощью булевой переменной blnDone, которая принимает значение ИСТИНА в случае
исчерпания времени ожидания или появления значения свойства readyState = READYSTATE_COMPLETE.
Поскольку прерывание от таймера наступает позже, чем событие DocumentComplete
(предполагаем, что наша машина — однопроцессорная), то переход в это состояние
означает, что обработка страницы уже завершена.
Справедливости ради следует отметить, что в ряде случаев обработку страницы
можно начинать и при readyState = READYSTATE_INTERACTIVE. Это то самое состояние,
когда Internet Explorer позволяет просматривать страницу в интерактивном режиме,
хотя еще не все компоненты загружены. Начиная с этого момента HTML-код вполне
пригоден для обработки. Если для решения задач пользователя кода HTML достаточно,
то процесс можно несколько ускорить, поместив вызов обработчика страниц в приведенную
выше процедуру в конструкцию Select Case для состояний READYSTATE_INTERACTIVE
и READYSTATE_COMPLETE. В этом случае событие DocumentComplete нужно заблокировать.
Для того чтобы совсем минимизировать время загрузки, необходимо использовать пару
событий: NavigateComplete2 и DownloadComplete. Событие NavgateComplete2 возникает,
когда документ объявляется найденным и его URL попадает в стек навигации и становится
доступным для проверки. Событие DounloadComplete, не имеющее параметров вызова,
возникает неоднократно — перед событием NavigateComplete2 и после него. Именно
наступление события DounloadComplete вслед за событием NavigateComplete2 соответствует
переходу в состояние READYSTATE_INTERACTIVE и может использоваться для вызова
процедуры обработки кода Web-страницы.
Надеюсь, что приведенные примеры послужат хорошим подспорьем для разработчиков
офисных приложений и стимулируют создание интересных проектов, использующих неисчерпаемый
источник информации — Internet.
КомпьютерПресс 12'2000