Объектная модель HTML в C# Язык С# представляет разработчику богатый набор классов для работы с Html, который поможет нам совершать с веб-страницей практически все, что угодно, без малейшего напряжения. Жаль, что Microsoft практически это не документирует. Уж не знаю, в чем причина, но замечено, что Microsoft делает возможным реализацию очень многих вещей на C#, но документирует из них лишь 15-20%, до остального же приходится доходить самому (либо с помощью своего обширного мозга, либо сперев нужные участки из чужих листингов). Главным классом здесь, конечно же, будет WebBrowser, который заключает в себе почти весь набор методов, свойств и событий, присущих Internet Explorer. По сути, WebBrowser является клоном IE, поскольку, к примеру, при обработке каких-либо веб-скриптов или ошибок будут задействованы его библиотеки. Для организации работы с активным содержимым веб-страницы в проект нужно включить библиотеку MSHTML, предоставляющую интерфейс для доступа к элементам DHTML. Решения поставленной нами задачи можно достичь двумя путями – либо работать напрямую с Internet Explorer, либо писать свой веб-браузер, заточенный под конкретные нужды. Я предлагаю выбрать второй вариант, благо он прост до безобразия. Работать напрямую с IE и другими веб-браузерами в C# можно, но это сложнее, поскольку придется использовать библиотеку взаимодействия с COM-компонентами со всеми отсюда вытекающими недостатками. Основное, что надо предусмотреть – перебор всех элементов html-контента по заданным критериям. В этом нам поможет класс HtmlElementCollection, который определяет набор Html-элементов, что нам, собственно, и нужно. Критерии поиска могут быть такими: 1) выборка по html-тегу методом webBrowser.Document.GetElementsByTagName(тэг) 2) выборка элемента по его id – методом webBrowser.Document.GetElementById(id) или еще одним интересным методом – webBrowser.Document.GetElementFromPoint(point), который позволяет выбирать элемент html-страницы по ее координатам на странице. Кстати, можно прогуляться в сторону леса и получить сразу все имеющиеся элементы на странице вот таким способом: void GetAllElements() { foreach (HtmlElement pageElement in webBrowser1.Document.All) { ... } } Существует, по меньшей мере, четыре метода организации клика, которые можно реализовать средствами C#. Чем они отличаются друг от друга? По большому счету – ничем, просто, когда один метод не проходит (например, объект не поддерживает метода «click»), можно реализовать так называемый «псевдоклик» или просто перенаправить веб-браузер по ссылке, которую всегда можно выдрать из страницы, где бы она ни находилась. Рассмотрим методы подробнее. 1) «Псевдоклик» путем эмуляции нажатия на элемент страницы, который в данный момент имеет фокус. Суть проста – находим необходимую нам ссылку или кнопку, ставим ее в фокус и эмулируем клавишу путем вызова функции SendKeys.Send("{ENTER}"). Организуем «псевдоклик» HtmlElementCollection es = webBrowser1.Document.GetElementsByTagName("a"); if (es != null && es.Count != 0) { HtmlElement ele = es[0]; ele.ScrollIntoView(true); ele.Focus(); SendKeys.Send("{ENTER}"); } Тем самым, посылкой «ввода» мы симулируем клик по первой попавшейся ссылке в html-документе. При этом функция ScrollIntoView опциональна, она просто прокручивает окно вниз, если, скажем, ссылка находится где-то за пределами видимости. 2) Вызов метода click() на нужном нам элементе. Для организации натурального клика по html-элементу можно использовать уже реализованный метод click(). Здесь используется возможность обращения к html-элементу страницы по его id. Скажем, у нас на страничке есть кнопка, которой присвоен некий id, равный «button1». Чтобы обратиться к кнопке, достаточно в методе GetElementById("") в качестве параметра указать id нужного нам элемента страницы. Естественно, для этой реализации нужно знать id элемента, на который предстоит кликнуть. Смотрим на код – все очень просто: Клик «в натуре» void click_it() { HtmlElement el = webBrowser1.Document.All["id"]; mshtml.HTMLLinkElement input_element = (mshtml.HTMLLinkElement)el.DomElement; input_element.click(); } Как всегда, простота метода с лихвой компенсируется его недостатками – дело в том, что он неудобен в использовании, поскольку для его реализации нужно знать либо id, либо индекс html-элемента, по которому нужно кликнуть. Иначе придется перебирать все доступные элементы на предмет соответствия нужным требованиям. 3) Уверен, что ты знаешь о существовании в .NET так называемой рефлексии типов, позволяющей получать информацию о программе (а точнее о типах, реализованных в сборке) на этапе ее выполнения. Так можно получить информацию обо всех членах исследуемой программы – методах, свойствах, событиях, конструкторах, самой сборке (для каждого из типов, которые в ней реализованы). И самое главное, получив информацию о необходимом объекте – в нашем случае это будет метод click() – его можно легко вызвать из чужой программы! Элементы, которые необходимы для использования возможности рефлексии типов – это класс Type из пространства имен System.Reflection (читай MSDN для получения дополнительной информации, если рефлексия типов для тебя – новое понятие). Сам же код сводится к получению информации о методе «click», реализованном в DomElement, который возвращает указатель на свой интерфейс. Смотрим код: Клик void click_reflect() { HtmlElement el = webBrowser1.Document.All["mybutton"]; object obj = el.DomElement; System.Reflection.MethodInfo mi = obj.GetType().GetMethod("click"); mi.Invoke(obj, new object[0]); } Или то же самое, но еще проще... HtmlElement el = webBrowser1.Document.All["mybutton"]; webBrowser1.Document.All["Submit"].InvokeMember("click"); 4) Теперь рассмотрим, как можно организовать переход по необходимой нам ссылке без самого клика. Как известно, у класса WebBrowser есть метод Navigate, вызов которого отправляет нас в путешествие по переданной ссылке. Описанным выше способом в html-контенте находим нужную нам ссылку и отправляем веб-браузер вслед за ней... Возможная реализация подобного метода – NavigateTo: HtmlElementCollection links = webBrowser1.Document.GetElementsByTagName("a"); foreach (HtmlElement el in links) { Form form_new = new Form(); form_new.Owner = this; form_new.Show(); form_new.NavigateTo(el.GetAttribute("href")); } void NavigateTo(string url) { if(url != null && url != "" && Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute)) webBrowser1.Navigate(url); } Для контроля за поведением веб-страницы рекомендую использовать обработчики событий Navigating и Navigated, определенных для класса WebBrowser. Событие Navigating происходит, когда браузер загружает страницу (имеется в виду процесс загрузки), а Navigated – когда начал загрузку. Использование данных событий весьма удобно, за исключением одного – в твоем приложении крайне желательно предусмотреть использование потоков для реализации данного замысла, иначе ничего путного из этой идеи не получится. Использование событий private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e) { this.Text = "Viewing: " + webBrowser1.Document.Title; browser_url.Text = webBrowser1.Document.Url.ToString(); } Работаем с фреймами Иногда спонсоры, не желающие платить деньги авторам кликеров, стараются размещать линки во фреймах. Ничего страшного, на каждую хитрую задницу, сам знаешь, всегда можно найти соответствующий механизм. Язык C# дает разработчику готовые инструменты для работы с фреймами – таковым, например, является свойство WindowFrameElement: Метод для работы с фреймами void NavigateToFrame() { HtmlElement frameElement = null; HtmlWindow docWindow = webBrowser1.Document.Window; foreach (HtmlWindow frameWindow in docWindow.Frames) { frameElement = frameWindow.WindowFrameElement; String originalUrl = frameElement.GetAttribute("SRC"); if (!originalUrl.Equals(frameWindow.Url.ToString())) { frameWindow.Navigate(new Uri(originalUrl)); } } } Ну и напоследок. Чтобы наиболее полно автоматизировать процесс «кликания и серфинга», можно (да и нужно) реализовать метод автоматического соединения с почтовым сервером, что-то типа «нажал кнопку и забыл». Многие почтовики для авторизации используют метод GET, при котором все твои данные (логин и пароль) передаются открытым текстом в строке браузера. Происходит это так: http://mail.rambler.ru/script/auth.cgi?domain=rambler.ru&login=твой_логин&passw=твой_пасс. Отброшу рассуждения насчет безопасности такой авторизации, скажу лишь, что запуск твоей проги можно легко замутить одним кликом. Поскольку спонсоры шлют письма на почту, таким вот нехитрым способом можно сделать автоматическую авторизацию, после чего начать поиск необходимых ссылок в полученном html-контенте. Заключение Основываясь на объектной модели HTML в .NET, можно соорудить много вкусных и полезных вещей – не только написать что-то типа кликера или серфера, но также создать вполне полноценный HTML-парсер или HTML-эдитор, наколбасить отслеживание загрузки и анализ подозрительных скриптов, да мало ли, чему еще можно найти применение! Например, организовать полноценную работу с с ActiveX-контролами, для чего в .NET Framework существует стандартный и документированный подход. Средствами .NET SDK или Visual Studio генерируем сборку, в которой будет создана обертка для ActiveX-контрола, представляющая его в виде .NET контрола. Так можно сгенерировать обертку и для контрола Microsoft Internet Explorer WebBrowser и использовать функциональность браузера веб-страниц в своих программах. Если хочешь, чтобы что-то было сделано, как следует, сделай это сам. Кстати, посмотри такой вариант «обертки» на http://rsdn.ru/article/files/dotnet/WebBrowser.xml, который создал Олег Михайлик (ему принадлежат слова «Копирайт – не копирайт, а уважение имейте» :)).
|