C# — C# Javascript Браузер


Содержание
Пример: Навигация по сайту Перед тем как создавать свой парсер сайтов, кликер-бота и т.п. необходимо разобраться с макетом документа, как искать и находить нужные блоки в документе Найдите на странице интересующий вас элемент Найдите id этого элемента на странице Для поиска id можно использовать FireFox, либо Chrome я использую последний Нажмите в Chrome F12 — Вы войдете в режим «Инструменты разработчика». Нажите на лупу и выберите интересующий вас элемент на странице Тег привязки (якорь), выделенные на картинке выше, не имеет никакого уникального идентификатора, поэтому, если мы используем функцию GetElementByTag(“a”), то мы получим список всех ссылок на странице, для нас это не вариант Итак, попробуем поискать ближайший элемент у которого есть > Теперь мы можем получить адрес нашей ссылки: C#: Событие загрузки страницы WebBrowser или как дождаться WebBrowser.ReadyState.Complete Сегодня небольшая заметка будет просвещенна компоненту winforms с помощью которого можно имитировать Интернет браузер. Для тех кто не догадался о каком контроле идет речь — это элемент управления WebBrowser. Контрол WebBrowser можно использовать для решения большого круга задач. Одной из основных таких задач является парсинг информации с веб ресурсов и автоматизация различных рутинных действий. Главной особенностью элемента управления WebBrowser является тот факт, что работать с содержимым страницы можно только после полной загрузки DOM страницы. Многие начинающие разработчики сталкиваются с проблемой, когда после навигации браузера на указанный адрес, программа «падает» с ошибкой доступа к содержимому страницы. Например код ниже, будет генерировать такую ошибку: Причина ошибки — w.Document равен null. Почему? Потому что вторая строчка инициирует переход браузера на новую страницу (асинхронно), однако строчка три выполняется сразу после второй (без ожидания загрузки страницы). Интернет страница грузится гораздо дольше чем выполняются строчки кода в программе. А значит программа выполнит строчку три до момента загрузки указанной страницы, что приводит к ошибке в работе. Для такого что бы избежать данной проблемы у контрола WebBrowser существует событие, которое вызывается после загрузки любой страницы. Называется данное событие DocumentCompleted. Пример: Теперь мы можем получить доступ к нашей странице без ошибки, так как данный код выполниться только после полной ее загрузки. Данный подход отлично работает, однако если Вам нужно работать не с одной страницей, а с несколькими и выполнять разную логику, то данный поход будет не очень удобен. Причиной этого является то, что событие DocumentCompleted вызывается после загрузки любой страницы, но при этом Вы точно не знаете какой. Значит нужно добавлять дополнительный проверки на текущий Url страницы, что приводит к разрастанию кода и снижению его читаемости. Однако есть еще один способ как можно открыть страницу в браузере, при этом дождавшись ее загрузки. Для этого напишем простую вспомогательную функцию: Теперь можем работать с нашим WebBrowser следующим образом: Вот и все. Надеюсь заметка была полезной �� Об использовании WebKit .NET Введение Связка HTML+CSS+JavaScript на сегодняшний день зарекомендовала себя как универсальный способ построения пользовательских интерфейсов. Причем не только в веб приложениях, но также в десктоп и мобильных приложениях. Примерами тому являются metro-приложения в Windows 8, фреймворк PhoneGap для создания мобильных приложений. Реализация интерфейса с помощью HTML, CSS и JavaScript прежде всего подразумевает, что интерфейс будет отображаться в некотором браузере. Если мы рассматриваем десктоп или мобильное приложение, то, очевидно, браузер должен быть встраиваемым. В данной статье мы рассмотрим использование WebKit .NET в десктоп приложении на C# под Windows. Требования к встраиваемому браузеру Выявим основные требования к встраиваемому браузеру. Прежде всего, из C# мы должны иметь возможность устанавливать HTML документу произвольное содержимое — т. е. наш интерфейс. Далее естественным образом возникает потребность в коммуникации между C# и JavaScript. Необходимо иметь возможность вызывать C# из JavaScript и JavaScript из C#, причем двумя способами — синхронно и асинхронно. Наше десктоп приложение с интерфейсом, реализованным во встраиваемом браузере, во многом похоже на традиционное веб приложение, имеющее клиент-серверную архитектуру. Поэтому наличие асинхронных вызовов C# из JavaScript очень важно. Эти вызовы представляют собой аналог AJAX запросов в традиционном веб приложении. Веб инспектор и отладчик — лучший друг каждого веб разработчика. А как с этим обстоит дело здесь? Скажем сразу — здесь с этим не все так просто. Нам не удалось найти способ отлаживать JavaSсript, выполняющийся во встраиваемом браузере, но мы нашли возможность исследовать dom и получили JavaScript консоль. Таким образом, основные требования к WebKit .NET заключались в наличии следующих вещей: возможность устанавливать HTML документу произвольное содержимое вызовы JavaScript из C# синхронно или асинхронно вызовы C# из JavaScript синхронно или асинхронно веб инспектор Далее мы рассмотрим, что из вышеперечисленного присутствовало в WebKit .NET и как недостающие функции были реализованы. Установка содержимого HTML документа Свойство WebKitBrowser.DocumentText позволяет установить HTML документу произвольное содержимое. Наш интерфейс полностью независим от внешних ресурсов, весь JavaScript и CSS мы включаем непосредственно в HTML. Для увеличения производительности все скрипты включаются в минифицированном виде. Вызовы JavaScript из C# Для вызовов JavaScript из C# в WebKit .NET имеется метод Document.InvokeScriptMethod со следующей сигнатурой: К сожалению, данный метод имеет проблему с передачей параметров в JavaScript функцию — она просто не работает. Чтобы решить эту проблему нам пришлось разработать свой собственный протокол вызовов JavaScript из C#. Идея заключается в следующем: для передачи параметров используется div с заданным идентификатором C# сериализует имя и массив параметров для JavaScript функции в JSON строку и помещает ее в заданный div JavaScript извлекает JSON, десериализует его и вызывает указанную функцию Код вызова JavaScript функции в C# выглядит следующим образом: А в JavaScript вызов обрабатывается так: Чтобы сделать вызов асинхронным мы просто вызываем указанную функцию с задержкой на 1мс. Так как мы не нуждаемся в асинхронных вызовах, возвращающих значение, то такое решение нас вполне удовлетворяет. Вызовы C# из JavaScript Штатного механизма вызовов С# из JavaScript в WebKit .NET в принципе нет. После пристального вглядывания в документацию было найдено событие WebKitBrowser.DocumentTitleChanged. Это, пожалуй, единственное событие, которое JavaScript легко может генерировать в любой момент путем установки document.title. Есть две вещи, которые делают это событие привлекательным: document.title можно установить достаточно большим, более 16Кб установка document.title в JavaScript завершается только после выполнения всех обработчиков события DocumentTitleChanged в C# Это легло в основу нашего протокола вызовов C# из JavaScript. В следующем листинге приведен JavaScript код, предназначенный для вызовов C#. Как видно из листинга, каждый вызов снабжается уникальным идентификатором. Далее он используется в качестве идентификатора элемента div, в который C# помещает результат. Если вызов синхронный, то непосредственно перед своим завершением C# обработчик может поместить свой результат в тело HTML документа. В этом случае метод callCSharp может извлечь результат из dom сразу после установки document.title. Для асинхронных вызовов C# должен инициировать запуск callback функций по завершении обработчиков. В этом случае из C# мы вызываем специальный JavaScript метод, приведенный в следующем листинге: На стороне C# у нас есть класс CallManager, управляющий подпиской на вызовы из JavaScript. CallManager имеет единственный обработчик события WebKitBrowser.DocumentTitleChanged, который десериализует значение свойства WebKitBrowser.DocumentTitle и, в зависимости от указанного в JavaScript имени (config.name), вызывает соответствующий зарегистрированный обработчик с переданными параметрами. Также CallManager учитывает тип вызова: синхронный или асинхронный. В зависимости от типа обработчик вызывается либо синхронно, либо асинхронно. Веб инспектор Мы производим разработку интерфейса в два этапа. На первом этапе мы разрабатываем его как традиционное веб приложение, используя браузер и веб-сервер. Только по достижении желаемого результата мы переходим ко второму этапу — упаковке скриптов и интеграции с C#. На первом этапе мы активно использовали инструменты разработчика в браузере и имели полный контроль над dom и JavaScript. Но после перехода ко второму этапу весь интерфейс попросту превращался в черный ящик. Возникающие проблемы с версткой и JavaScript становилось достаточно трудно обнаруживать. Мы вынуждены были искать хоть какой-то аналог веб инспектора. К сожалению, WebKit .NET не позволяет использовать родной веб инспектор WebKit и никакой remote debugging тут не поддерживается. Поэтому мы решили воспользоваться Firebug Lite (1.4.0) — встраиваемым отладчиком, основанным на Firebug. В HTML страницу Firebug Lite мы подключаем следующим образом: При работе со встраиваемым браузером удобнее, когда Firebug Lite открывается именно в новом окне, что задается опцией startInNewWindow. Но для того, чтобы это произошло необходимы некоторые манипуляции в C#: Конечно, Firebug Lite не поддерживает отладку скриптов, но дает возможность исследовать dom и дает нам JavaScript консоль, а это уже облегчает разработку. Заключение После всех описанных выше доработок WebKit .NET превратился во вполне пригодный встраиваемый браузер, который стабильно работает и справляется с достаточно большим dom. Конечно, реализация интерфейса таким образом сопряжена с определенными сложностями, которые по большей части вызваны отсутствием полноценного веб инспектора, но есть и плюсы. Например, можно повторно использовать JavaScript код из других частей приложения или вообще реализовать одинаковый интерфейс в мобильном, десктоп и веб приложении. Поэтому усилия можно считать оправданными. Использование Gecko в C# [GeckoFx] Не всех устраивает стандартный движок IE в Винде. Но, к счастью, есть много альтернативных движков для C#, Gecko входит в их число и в этом посте я опишу, как использовать GeckoFx в своих проектах. Исходники можно найти в конце статьи. На момент написания статьи последняя версия GeckoFx для C# это 22 . Давненько не было обновлений и, возможно, проект умер, но даже 22 версия лучше IE . Так что начнем �� Напишем приложение, которое будет заходить на главную станицу гугла, вводить какой-то запрос и переходить по случайному сайту в выдаче. Создаем новый проект (Приложение Windows Forms ), называем его « GeckoExample «, переименовываем главную форму в « FrmMain «, размеры главной формы = 514; 399. Для работы нам понадобиться: Теперь в созданном проекте добавляем ссылки на Geckofx-Core.dll и Geckofx-Winforms.dll. Бросаем на форму Panel ( Name = pnl1, Location = 0;0, Size = 495; 25 ), на эту панель добавляем Button ( Name = «btnStart», Location = 0;0, Size = 75; 23, Text = Начнем ), рядом с кнопкой бросаем TextBox ( Name = «tbUrl», Location = 84; 2, Size = 244; 20 ). В свойствах проекта переключаем конечную платформу на x86. Теперь приступим к написанию кода. В using класса главной формы подключаем: Добавляем приватное поле _webBrowser типа GeckoWebBrowser: В конструкторе класса главной формы пишем следующее: Т.е. мы инициализируем движок, указывая путь к движку (у меня он находится в папке с программой). Далее создаем экземпляр класса GeckoWebBrowser (т.е. наш браузер), создаем обработчик события DocumentCompleted (который будет изменять текущий адрес страницы в tbUrl), меняем наш юа и добавляем контрол браузера на форму. Кстати, вот реализация метода _webBrowser_DocumentCompleted : Настало время написать класс, который будет иметь следующие методы: загрузка главной страницы гугла; написание произвольного поискового запроса в текстовое поле; клик по случайному сайту на странице выдачи. Добавляем новый класс GoogleExample и следующие поля: Поле _webBrowser — это ссылка на наш браузер, _loadingTimer через 2000 (т.е. две секунды) миллисекунд будет изменять состояние загрузки страницы и _loading — статус загрузки (этому полю наш таймер будет присваивать значение false ). Незабываем в using подключить следующее: Теперь напишем конструктор класса GoogleExample : Конструктор принимает ссылку на браузер, инициализирует таймер. Также создается обработчик события CreateWindow2 . Это событие вызывается перед созданием окна. Нужно нам это событие для того, чтобы «глушить» открытие новых окон при нажатии на ссылку результата на странице выдачи гугла . В этом событии мы отменяем открытие нового окна и заставляем главное окно перейти на ссылку, которую хотело открыть новое окно. Реализация события Tick для _loadingTimer : Все просто: останавливаем таймер и изменяем значение переменной _loading , это значение указывает на статус загрузки страницы. Реализация метода WaitForLoading : Обычный цикл, каждые 200 миллисекунд проверяется статус загрузки страницы. Реализация метода Navigate : Открываем браузером страницу, запускаем таймер и асинхронно ждем загрузки страницы. Основные методы готовы. Начнем открывать гугл �� Метод OpenGoogle загружает главную страницу гугла. Но есть один момент: гугл может быть на английском, потому цикл foreach нужен для того, чтобы пройтись по всем ссылкам на главной странице и найти ту ссылку (если она есть), при нажатии на которую можно переключить язык на русский. Следующий в очереди метод ввода поискового запроса — WriteQuery . Этот метод получает все input‘ы, далее выбирает первый input, который имеет имя «q». Далее запускается цикл, с помощью которого поисковый запрос вводиться побуквенно (типа, реальный пользователь набирает текст :D). После цикла выбираем все button‘ы и кликаем по первому, у которого имя равно « btnG » (это синяя кнопка для поиска) и ждем загрузки страницы. Ну и последний метод в нашем классе — ClickRandomLink . Собственно, получаем все ссылки, инициализируем список «нужных ссылок» и запускаем цикл по списку всех ссылок, в котором ищем ссылки, атрибут « onmousedown » которых начинается с « return rwt( » и сама ссылка не содержит « webcache.googleusercontent.com » (иначе получим ссылку на сохраненную копию). дофига ща раз было слово «ссылка». Конструкцию try..catch нужно использовать обязательно, т.к. если попытаться получить доступ к несуществующему атрибуту элемента, то движок выбросит исключение. Например, в том же HtmlAgilityPack все по-другому (и, как мне кажется, удобнее): в методе получения атрибута элемента мы заранее указываем, что нам возвращать, если у элемента нет такого атрибута. Ну да ладно �� Возвращаемся к классу формы. Создаем обработчик события Click кнопки btnStart , добавляем к этому методу модификатор async и пишем следующее: Ну вот и всё. Можно компилить, тыкать на кнопку и наблюдать результат �� Кстати, исходники можно скачать на GitHub. 66 комментариев на «Использование Gecko в C# [GeckoFx]» Исходники на гитхабе, не рабочие, замените, пожалуйста Чего в них не рабочего? Уже разобрался, не было в сборке xullrunnera. Остался вопрос про контрол. Добавляется он на форму кодом this.Controls.Add( this._webBrowser ); как я понял. Но это очень не гибко. Как можно сделать, чтобы строго определенное место было для него выделено? Есть ли возможность масштабирования содержимого под эти размеры? Так же интересно, как быть с тегом select. Как выбрать нужный элемент? Можно попробовать так: https://gist.github.com/dredei/69af2f47b6c36a48fc70 Код, который выше, должен работать и для тех select‘ов, у которых нет атрибута value в option. Это пример, так что ожидать от него какой-то гибкости (чтобы сразу скопировал и работало, как нужно), не стоит �� На счет размеров, то я, думаю, не сложно поставить точку после this._webBrowser и глянуть, какие у этого объекта есть поля и методы. Среди них есть такие поля, как Height (высота) и Width (ширина), с помощью которых можно настроить размеры контролла. Также следует установить свойство Anchor в AnchorStyles.Left | AnchorStyles.Top , т.к. в примере с помощью якорей (AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom) контролл «цепляется» ко всем краям формы. Точно. Спасибо! Документации, как я понял, нет на него, даже на английском? Документации нет. Когда-то находил примеры (для 16 версии, вроде) на англ. Так что метод научного тыка рулит �� Я вижу что Вы очень неплохо разобрались с Geckofx. Подскажите если знаете. По свойству geckoWebBrowser1.Document мы получаем доступ к документу, который был уже распарсен движком. Но бывают случаи когда оригинал исходника веб страницы с сервера, не соответствует OuterHtml. Хотя движок и верно отображает страницу, свойство geckoWebBrowser1.Document уже потеряло некоторые данные и к ним не получить доступ. если сделать geckoWebBrowser1.Navigate («view-source:» + url); то код без потерь, но во первых он отображается на странице, что не всегда нужно, во вторых запрашивается с сервера ещё раз, а в третьих он только выглядит верно, а получить доступ к html документу как? OuterHtml это будет уже не оригинал, туда добавится разметка оформления для вывода кода. Надеюсь вы поняли, что я хочу узнать. Заранее спасибо. Я не в курсе, как получить оригинал кода, который отдает сервак, с помощью GeckoFx. Т.к. какой смысл таскать за собой такое двигло, если нужно получить просто код (без рендеринга и т.д.), который отдает сервак? Для таких целей есть WebClient �� Спасибо за ответ. Таскать двигло имеет смысл в определенных ситуациях. Цель его использования в конкретной проблеме была не в получении исходного кода, движок используется по назначению. Просто параллельно и такой вопрос возник, чтоб программно обработать данные со страницы. К сожалению в связи со скудным документированием сам ответа не нашел. Согласитесь, раз движок все же используется, то глупо городить костыли и обращаться через WebClient, когда эту конкретную страницу уже получил и отобразил движок. Ладно, будем искать, возможно не все потерянно. Городить костыли в программировании нужно чуть ли не постоянно �� Т.к. не все либы имеют нужный функционал/работают так, как нужно. Ну, либо портировать (допиливать) этот движок самому с преферансом и поэтессами. Но на это уйдет намного больше времени, чем соорудить костыль. Также можно попробовать задать вопрос тем, кто портировал двигло здесь. П.С. На счет view-source. Можно схитрить и получить доступ к коду так: _webBrowser.Navigate( «view-source: someurl» ); string html = _webBrowser.Document.GetElementsByTagName( «html» )[ 0 ].TextContent; В теории, должно сработать �� Здравствуйте, не подскажете как в gecko 29 версии изменить дерикторию куки? Xpcom.ProfileDirectory — меняет только папку кеша а куки остаются стандартно C:\Users\Админ\AppData\Local\Geckofx\DefaultProfile Здравствуйте! У меня отлично все меняет. Пишет все данные (кеш, куки и т.д.) профиля туда, куда я и указал. У версии geckoFX 29,0,6 и выше — куки остаются в стандартной папке! И еще прошу помощи с авторизацией Proxy по паролю.. Буду ждать ваших коментариев по этому поводу. Спасибо.. Специально только что проверил на 29.0.11 — все данные профиля сохраняются там, где я и указал. На счет прокси — смотрите пример здесь. А можно примерчик на почту или ссылку на пример? только без браузера! что не делаю всеравно куки сохраняет в стандартную папку! сижу уже пару дней, ничего толком не выходит( Спасибо за быстрые, супер быстрие отзывы… Спасибо.. В общем, ничего особенного. Делаю так, как вы и писали �� Пример отправил на почту (указываю профиль в конструкторе главной формы). Низкий поклон вам, все, разобрался) так работает Xpcom.ProfileDirectory = Application.StartupPath + «\bin\cookie»; Xpcom.Initialize(Application.StartupPath + «\xulruner\»); так неработало у меня Xpcom.Initialize(Application.StartupPath + «\xulruner\»); Xpcom.ProfileDirectory = Application.StartupPath + «\bin\cookie»; в чем разница такого события? раньше все работало до обновления версии. Сасибо, ваш пример решил мою проблему… Фиг знает, почему раньше работало. Может, те, кто портировали новую версию что-то изменили или это изменения в самом движке. В принципе, логично, что сначала указывает профиль, а потом инициализируем движок (так как раз Лиса и работает: сначала выбираем профиль, а потом уже запускается браузер). Хорошо что хорошо все решилось. Для этого буду знать куда вертеть)) Спасибо за ответы. буду внимательно читать ваш блог. с автоматической авторизацией прокси по паролю разобрался. если нужно будет кому-то пример то через админа будет можно взять пример. Спасибо еще раз.. Не за что, удачного кодинга �� Здравствуйте, столкнулся с проблемой. Открытия окон в новой вкладки, неработает с некоторыми сайтами, в основном с многими. Вот навожу пример с одним из сайтов — http://123.sovetam.ru Во время подписки выскакивает новая вкладка, но сайт сообщает об ошибке. Если не блокировать окно то подписка проходит нормально! Пробовал подставлять реферер но толку мало, хоча на некоторых из кликовых спонсоров, клики по ссылкам, открытие в новом окне, реферер помог! Без реферера клики тоже непроходили. Прошу помощи, так как это является большой проблемой с использованием геско вкладки. Спасибо.. Буду ждать ответа. Просто происходит не просто открытие окна, а еще и отправка post-запроса, потому и сообщает об ошибке. Здесь уже нужно сидеть и копать (и гуглить :)), у меня сейчас времени на это нет, занят другим проектом. У меня такой вопрос странный. Не могу разобраться как работает ваша синхронизация? Как узнать что страница полностью прогрузилась и с ней можно дальше работать? с обычным компонентом webBrowser я проверял на ReadyState, если он completed то идем дальше. Но тут как то не могу разобраться, подскажите, а?) Здесь таймер, который меняет состояние булевой переменной (_loading) по истечению 2 секунд после начала загрузки страницы. Переменные подписаны комментариями, не сложно в студии выбрать нужную переменную и юзануть «Find Usages», чтобы увидеть места, где она используется/изменяется ее состояние. Ни в одном из компонентов нельзя четко определить полную загрузку страницы, т.к. сейчас сайты напичканы кучей js скриптов, которые после загрузки документа могут много чего изменить на странице и это фиг отловишь. С одними сайтами DocumentCompleted работает идеально, с другими — вечная загрузка, а третьи вообще на одном аяксе. Так что лучше делать всякие «комбо» из таймеров, метода DocumentCompleted и свойства IsBusy. я просто не нашел зависимости таймера и загрузки. он просто меняет переменную и говорит, что страница загрузилась через 2 секунды? а если она не успела загрузиться за это время? или я что то упустил? В данном примере таймер решает: загрузилась страницы или нет �� Это же пример, лень было что-то «мега-крутое» для простого примера делать. А если она не успела загрузится, то работа продолжиться с не загруженной страницей. ага, я понял. Спасибо. а может подскажите еще какие сторонние компоненты, в которых это решается более просто, при мопощи методов и свойств? проблема стандартного веб-браузера в том, что он почему то не перегружает содержимое документа, вообще никак. (как загрузил после первой навигации, так и все) я так понял в Gecko с этим все ок, вот только нужно костылить с синхронизацией? Я ниже описал, что ни в одном компоненте (с которым я сталкивался �� ) нельзя одним методом/событием определить полную загрузку страницы (еще в Делфи 7 и выше с этой фигней сталкивался и перепробовал еще тогда кучу компонент). Даже обычный браузер (Хром, Лиса) не может этого сделать �� А костыль с загрузкой достаточно простой: используем таймер и проверку свойства IsBusy. Таймер «заводим» на, например, 10 секунд, при срабатывании таймера меняется значение переменной _loading в false. А в методе открытия ссылки, где происходит ожидание загрузки страницы, делаем простой цикл: while (_wb.IsBusy && _loading) <
// ждем > _loadingTimer.Stop(); // работаем со страницей Использовать таймер в любом случае нужно, т.к. может какой-то скрипт какого-то нафиг ненужного счетчика, который загружается синхронно, «повешать» страницу (т.е. будет грузиться вечно или очень долго) и в итоге программа будет ждать, как Хатико �� П.С. Считаю GeckoFX самым нормальным двиглом для C#. Сталкивался с портом Хромиума (уже не помню, как называется), но там всё печально. Нужно лепить «обертку» для работы с элементами страницы на JavaScript, а в GeckoFX уже из коробки реализованы классы веб-элементов, сделана удобная работа с ними и т.п.
  • Downloading .
  • Launching GitHub Desktop .
  • Launching GitHub Desktop .
  • Launching Xcode .
  • Launching Visual Studio .
  • Поиск по сайту
  • Каким образом отследить HTTP ошибки
  • Почему событие DocumentCompleted вызывается несколько раз и как этого избежать?
  • Как дождаться загрузки страницы полностью?
  • Как сделать скриншот веб-страницы программно?
  • Как запретить использование веб-браузера?
  • Как выполнить свой код на JavaScript?
  • Как распечатать страницу с помощью WebBrowser?
  • Как запретить отображение окна с JavaScript ошибками?
  • Использование элемента управления WebBrowser в консольных приложениях
  • Как изменить UserAgent у WebBrowser?
  • Как запретить у WebBrowser переход на предыдущую страницу?
  • Проблемы с кодировкой
  • Парсинг HTML
  • Еще несколько советов
  • Пользовательский веб-браузер С# не может поддерживать javascript
  • Парсинг сайтов на c#. Часть 1. Использование WebBrowser
  • Компонент WebBrowser
  • Пример: WebBrowser Download Event (событие загрузки)
  • Пример: Навигация по сайту
  • C#: Событие загрузки страницы WebBrowser или как дождаться WebBrowser.ReadyState.Complete
  • Об использовании WebKit .NET
  • Введение
  • Требования к встраиваемому браузеру
  • Установка содержимого HTML документа
  • Вызовы JavaScript из C#
  • Вызовы C# из JavaScript
  • Веб инспектор
  • Заключение
  • Использование Gecko в C# [GeckoFx]
  • 66 комментариев на «Использование Gecko в C# [GeckoFx]»
  • Цукерберг рекомендует:  Роботы - Могут ли роботы уничтожить человечество

    Взаимодействие C# и JavaScript

    Silverlight 5 — Взаимодействие C# и JavaScript

    В примерах из предыдущей статьи приложение Silverlight обращалось к браузеру для манипулирования элементами HTML. Один из недостатков этого способа состоит в том, что код приложения жестко привязан к странице HTML. При его создании необходимо заложить в код информацию об элементах текущей страницы и уникальных значениях id. Как результат, после изменения HTML-страницы код Silverlight становится неработоспособным.

    Для решения этой проблемы необходимо запрограммировать взаимодействие кодов, а не элементов. Например, приложение Silverlight может обновлять HTML-содержимое, вызывая методы JavaScript, определенные на странице. Код JavaScript создает дополнительную прослойку между Silverlight и HTML, обеспечивая гибкость приложения.

    При использовании этого способа устраняется необходимость перекомпиляции приложения Silverlight, потому что элементы HTML можно изменять, обновляя методы JavaScript для учета изменений. Взаимодействие может выполняться и в обратном направлении. Например, можно создать код JavaScript, который вызывает методы Silverlight, написанные на C#. В следующих разделах подробно рассматриваются оба подхода.

    Вызов сценария JavaScript из кода Silverlight

    С помощью классов Silverlight, приведенных в пространстве имен System.Windows.Browser, можно вызывать функции JavaScript, объявленные в блоке сценариев. Этот способ взаимодействия позволяет коду Silverlight взаимодействовать с HTML-страницей. Он особенно полезен, если уже существует страница с полным набором функций JavaScript. Вместо дублирования кодов, манипулирующих элементами страницы, можно вызывать существующие функции.

    Рассмотрим функцию changeParagraph, определенную в разделе HTML-страницы:

    Для ее вызова в Silverlight нужно применить метод HtmlPage.Window.GetProperty () и передать ему имя функции. Метод возвратит объект типа ScriptObject, через который можно в любой момент запустить функцию, вызвав метод InvokeSelf():

    Вызов методов Silverlight из браузера

    Код JavaScript может вызывать методы Silverlight, написанные на C#. Эта задача немного сложнее. Для ее решения необходимо выполнить ряд действий:

    Создайте в коде Silverlight открытый метод, предоставляющий информацию или средства, которые нужно использовать на HTML-странице. Метод можно поместить в классе страницы или в отдельном классе. Используйте простые типы данных, такие как строки, булевы значения и числа, в противном случае вам придется сериализовать объекты данных для совместимости с типами JavaScript.

    Добавьте атрибут ScriptableMember в объявление метода, который планируете вызывать из JavaScript.

    Добавьте атрибут ScriptableType в объявление класса, содержащего метод.

    Чтобы предоставить сценарию доступ к методу Silverlight, вызовите метод HtmlPage.RegisterScriptableObject().

    После выполнения этих операций код JavaScript сможет вызывать методы Silverlight посредством элемента , представляющего область содержимого Silverlight. Программа Visual Studio по умолчанию создает тестовую страницу и присваивает имя silverlightControlHost элементу

    В приведенном ниже примере используется пользовательский класс страницы. Он содержит метод, доступный в сценариях и регистрируемый при первом создании страницы:

    При регистрации типа, доступного в сценариях, нужно задать имя объекта JavaScript и передать ссылку на объект. В данном примере экземпляр класса MainPage зарегистрирован с именем Page. Регистрация вынуждает Silverlight создать свойство Page в элементе управления. Чтобы вызвать метод, код JavaScript должен получить элемент управления Silverlight, извлечь его содержимое и вызвать его метод Page.ChangeText():

    Запустить функцию JavaScript можно в любой момент времени. Приведенный ниже код запускает ее при щелчке на абзаце:

    Компиляция C# и XAML в JavaScript

    В этой статье мы расмотрим расширение для Visual Studio под наванием ‘C#/XAML for HTML5’. Данное расширение позволяет транслировать имеющийся код на C# и XAML в код HTML5+JavaScript. Благодаря подобной трансляции мы сможем создавать на C# приложение, которое после трансляции в JavaScript будет запускаться и на тех платформах, где .NET по умолчанию не поддерживается и где есть поддержка HTML5 и Javascript — Android, iOS, Mac, Chromebooks, Linux, Windows и т.д. То есть по сути у нас получается гибридное приложение.

    Также стоит отметить, что данная надстройка пока находится в бета-версии и имеет много ограничений, и сходу на настоящий момент вряд ли можно перевести большое полноценное приложение на JavaScript. Но в то же время функционал расширения динамично развивается, а возможности увеличиваются. Ее возможности и ограничения также можно найти на вышеуказанном официальном сайте. Кроме того, расширение существует в бесплатной и платной версиях, что также накладывает некоторые ограничения на бесплатную версию.

    Вначале установим это расширение. Его можно загрузить по адресу http://cshtml5.com/. Установщик расширения представляет собой msi-файл размером не более 4 Мб. Но сразу надо отметить, что мы можем устанавливать расширения и надстройки в версии Visual Studio выше Express — то есть для версий Community, Professional, Ultimate, поскольку Express не поддерживает расширения и надстройки.

    После загузки и установки расширения в Visual Studio мы сможем найти новые типы проектов:

    Empty Application : пустое приложение с минимальной разметкой xaml и кодом c#

    Empty Class Library : проект для создания библиотеки классов

    Sample — Calculator App : образец готового приложения — калькулятор

    Sample — Controls Showcase : еще один готовый пример использования некоторых элементов управления и функциональностей

    Создадим проект по первому типу Empty Application.

    Создаваемый проект имеет структуру, похожую на проекты WPF, Silverlight, Windows Phone, с главной страницей MainPage.xaml и файлом кода на c#.

    В коде xaml мы можем использовать те же элементы управления и конструкции, что и в WPF. В частности, привязка прекрасно работает, а также большинство элементов управления.

    Также есть визуальное представление, где мы можем сделать предпросмотр страницы в портретном и альбомном режиме при разных расширениях экрана.


    При запуске проекта отображается некое подобие эмулятора, где мы можем протестировать приложение:

    Если мы перейдем к каталогу bin\Debug\output в папке этого проекта, то сможем увидеть сгенерированные файлы js и html. Файл index.html как раз и будет представлять файл нашего приложения, который можно запустить в браузере:

    Цукерберг рекомендует:  Web программирование - ищу друзей по web программированию

    И в браузере он будет работать точно также, как работало бы приложение на c#.

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

    Браузер от Mozilla в проекте на C#

    Обычно свой браузер пишут, чтобы произвести автоматизацию или программное управление над некоторыми процессами. И как ни странно практически никто не хочет использовать встроенный компонент браузера той среды разработки, в которой создается проект. И здесь нет ничего удивительного. Поэтому разработчики вынуждены искать сторонние продукты для решения своих задач.

    При поисках движка, выбор пал на движок от Mozilla Gecko. И так получилось, что документация и примеры по его использованию (практически только на англоязычных ресурсах) были под C# или под VB.Net. Я свой выбор остановил на C#.

    Проект будет разрабатываться в среде разработки – Visual Studio 2010. Для работы нам понадобится скачать и установить SDK (xulrunner) от Mozilla. Xulrunner можно скачать здесь. Рекомендую скачать версию 1.9.0.0. Далее нам необходимо скачать и установить библиотеку Skybound.GeckoFX.bin, которая является оберткой для xulrunner под язык программирования C#. И в этом случае я также рекомендую скачать версию библиотеки – 1.9.0.0.

    Дело в том, что в некоторых SDK, есть баги. Я сам недавно столкнулся, когда потребовалось написать новый проект. Часть исходного кода взял со старого проекта, а вот какой версии xulrunner в нем использовался, я забыл. Получив баг при работе проекта и прочитав пару статей (сначала подозрение падало на Visual Studio 2010) я узнал, что в некоторых версиях есть существенные недоработки. Поэтому демонстрация подключения браузера, будет происходить на проверенной версии платформы xulrunner и проверенной версии библиотеки-обертки.

    Если вы скачали все необходимое, то можно переходить к созданию демонстрационного проекта. Но для начала необходимо разобраться с подключением xulrunner. Из полученного архива с xulrunner нас интересует каталог bin. Создадим на диске “С” к примеру, каталог “XPCOM” и в него скопируем все содержимое каталога bin из архива с нашим SDK. Затем, необходимо распаковать архив с библиотекой Skybound.GeckoFX.bin. Далее открываем Visual Studio и создаем стандартный проект под windows. На следующем шаге, необходимо открыть панель элементов. После чего кликаем по ее области, правой клавишей мыши. Перед вами должна появиться форма с выбором элементов панели управления.

    Переходим на вкладку “Компоненты .NET Framework” и нажимаем кнопку “Обзор”. Перед нами откроется стандартное диалоговое окно для выбора файла. В нем, то и выбираем файл Skybound.Gecko.dll, который тоже находится в каталоге bin, каталога Skybound.GeckoFX.bin.v1.9.x.x и нажимаем кнопку “OK”. В панели элементов во вкладке “Общие” должен появиться компонент – GeckoWebBrowser. После чего, компонент GeckoWebBrowser, нужно перенести на форму.

    Теперь необходимо произвести инициализацию компонента. Для начала необходимо добавить пространство имен Skybound.Gecko. Для этого в начале кода, вставим строку:

    Затем в модуле формы, в конструкторе формы, добавим следующий код:

    И еще одну строку кода необходимо добавить в обработчик события активации формы:

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

    В самом движке, есть все те возможности, которые присутствовали в Mozilla, а это около трех лет тому назад. Чего нельзя сказать о библиотеке-обертке. В этой версии, на основе которой построен демонстрационный проект, перечень возможностей очень и очень мал. Может быть и обратное: в xulrunner могут отсутствовать некоторые интерфейсы, реализация которых есть в установленной библиотеке-обертке. Посмотреть перечень доступных интерфейсов в xulrunner можно, если в каталоге с SDK открыть каталог bin\components. Там должны присутствовать файлы с расширением *.xpt. Это и есть библиотеки, которые получились в результате компиляции файлов с описанием интерфейсов. На данный момент движок Mozilla фундаментально изменен и существуют библиотеки-обертки, гораздо более новых версий (возможно там функциональных особенностей будет намного больше). Что я понимаю под ограничением функциональных возможностей?

    Вот, к примеру, какие возможности отсутствуют в Skybound.Gecko v1.9.0.0:

    • удаление cookie;
    • возможность генерации событий от мыши;
    • и еще много всего;

    Согласитесь, такие функциональные особенности списать со счетов мы не можем. Конечно, ничего страшного в этом нет. Это все при желании реализовывается самостоятельно, путем добавления необходимых интерфейсов и реализацией некоторых методов. Документации в наше время достаточно, но не факт что у кого то, будет проблема идентичная вашей. Но в любом случае при желании разобраться можно.

    О том как можно модифицировать браузер, смотрите здесь.

    Комментариев: 2

    Эдуард
    Фев 06, 2020 @ 11:45:02

    Существует, глобальный вопрос. как организовать скачивание файла с событием прогресса и окончания загрузки?

    admin
    Фев 09, 2020 @ 14:11:18

    Скачайте здесь сборник решений. В свое время был неплохой форум по обсуждению geckofx.

    Добавить комментарий Отмена

    Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.

    C# — C# Javascript Браузер

    We recommend upgrading to the latest Google Chrome or Firefox.

    Join GitHub today


    GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.

    New pull request

    Clone with HTTPS

    Use Git or checkout with SVN using the web URL.

    Downloading .

    Want to be notified of new releases in sharpbrowser/SharpBrowser ?

    Launching GitHub Desktop .

    If nothing happens, download GitHub Desktop and try again.

    Launching GitHub Desktop .

    If nothing happens, download GitHub Desktop and try again.

    Launching Xcode .

    If nothing happens, download Xcode and try again.

    Launching Visual Studio .

    Permalink

    Type Name Latest commit message Commit time
    Failed to load latest commit information.
    images major release v2, update to cefsharp 51 Oct 12, 2020
    src update to cefsharp 71 and .net 4.6 Feb 22, 2020
    .gitignore update to cefsharp 71 and .net 4.6 Feb 22, 2020
    LICENSE Initial commit Aug 7, 2020
    README.md update versions in readme Feb 22, 2020

    SharpBrowser is the fastest open source C# web browser there is! Slightly faster than Google Chrome when rendering web pages due to lightweight CEF renderer. We compared every available .NET browsing browsing engine and finally settled on the high-performance CefSharp. Released under the permissive MIT license.

    Поиск по сайту

    В предыдущей части мы рассмотрели основные принципы разработки HTML Editor на базе WebBrowser. В этом посте я постараюсь дать ответы на часто задаваемые вопросы по WebBrowser. Элемент управления WebBrowser позволяет разместить в приложениях Windows Forms веб-страницы и другие документы с поддержкой браузера. В первую очередь хочу остановиться на том, где можно использовать компонент WebBrowser:

    • при написании «своих» веб-браузеров со специфической логикой
    • для обеспечения интеграции справочной HTML-системы
    • для разработки уже рассмотренного нами HTML Editor
    • web data extracting, data parsing c помощью Microsoft.mshtml.dll (хотя этот вариант парсинга не самый лучший)

    Каким образом отследить HTTP ошибки

    Для этого в проект необходимо добавить библиотеку «Microsoft Internet Contols» (Add Reference -> COM), после чего написать следующий код:

    Почему событие DocumentCompleted вызывается несколько раз и как этого избежать?

    Это происходит по той причине, что событие DocumentComplete вызывается каждый раз для отдельного фрейма (frame). Таким образом, для корректной работы необходимо добавить дополнительные проверки:

    Еще один способ рассмотрен дальше.

    Как дождаться загрузки страницы полностью?


    Более эффективным вариантом дождаться полного окончания загрузки страницы является вариант с использованием свойства ReadyState:

    Как сделать скриншот веб-страницы программно?

    Для этого есть метод DrawToBitmap:

    Вы не сможете сделать скриншот тех участков веб-страницы, где используется Flash или Silverlight.

    Как запретить использование веб-браузера?

    У WebBrowser нет свойства Enabled, поэтому вы не можете запретить его использование напрямую. Но с учетом того, что WebBrowser — наследник Control, то вы можете это сделать таким образом:

    Как выполнить свой код на JavaScript?

    Для этого необходимо использовать следующий код:

    Как распечатать страницу с помощью WebBrowser?

    Как запретить отображение окна с JavaScript ошибками?

    Несмотря на то, что это достаточно простой вопрос, его также часто задают. Для этого необходимо воспользоваться свойством ScriptErrorsSuppressed:

    Использование элемента управления WebBrowser в консольных приложениях

    WebBrowser работает в STA (Single Thread Application) режиме, что значит, что вы, наверняка, получите сообщение об ошибке:

    ‘XXX’ cannot be instantiated because the current thread is not in a single-threaded apartment

    Для избежания этой проблемы необходимо помечать все методы атрибутом [STAThread].

    Если необходимо получить скриншот в новом потоке, то можно использовать такой код:

    где GenerateWebSiteImage — метод для получения скриншота, приведенный выше.

    Как изменить UserAgent у WebBrowser?

    Несмотря на то, что это довольно простая задача при условии использования WebClient, для WebBrowser решение не такое уж очевидное:

    Как запретить у WebBrowser переход на предыдущую страницу?

    Пользуемся следующим кодом:

    Проблемы с кодировкой

    Если вы загружаете HTML страницу из файла, то кириллические символы будут отображаться в неправильной кодировке.

    Для избежания этой проблемы необходимо либо читать из файла в нужной кодировке:

    либо задать кодировку для WebBrowser с помощью свойства Documemt.Encoding:

    Парсинг HTML

    Для парсинга HTML использование WebBrowser не обязательное, так как все равно задача в итоге сводится к использованию библиотеки Microsoft.mshtml или сторонних библиотек:

    Но нужно понимать, что парсинг HTML с помощью WebBrowser также возможен:

    Еще несколько советов

    Элемент управления WebBrowserинтенсивно потребляет системные ресурсы. Завершив работу с элементом управления не забудьте вызвать метод Dispose(), чтобы своевременно освободить все задействованные ресурсы. Необходимо вызвать метод Dispose() в том же потоке, присоединившем события, который всегда должен быть потоком сообщений или потоком пользовательского интерфейса.

    Класс WebBrowser может использоваться только в потоках в режиме однопотокового апартамента (STA).Чтобы использовать этот класс, убедитесь, что используемый метод Main помечен атрибутом STAThreadAttribute.


    Пользовательский веб-браузер С# не может поддерживать javascript

    Я создаю веб-браузер, который имеет автоматическую загрузку определенных веб-страниц, но проблема в том, что браузер, который я создал с помощью С# в visual studio, не загружает javascipt, браузер, который я создал только загружать html файл, но не поддержка java-скрипта. может ли кто-нибудь помочь мне в том, как добавить некоторые функции в мой пользовательский веб-браузер, который будет поддерживать javascript.

    WebKit DotNet — лучший порт мощного браузера WebKit в DotNetFramework.

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

    У этого JavaScript включен по умолчанию.

    Управление веб-браузером действительно дрянное. Я предполагаю, что вы пытаетесь запустить какой-то веб-сайт. Для этого вместо этого используйте HttpWebRequest .

    Если вы пытаетесь создать свой собственный веб-браузер: не используйте или не используйте Webkit или Gecko.

    Парсинг сайтов на c#. Часть 1. Использование WebBrowser

    Парсинг сайтов — это получение интересующей информации с веб-страниц. Автор попытался сделать пошаговое руководство, начиная с основ парсинга с помощью компонента WebBrowser и заканчивая темами такими как выполнение логина и поддержания сессий через HTTPWebRequest.

    Компонент WebBrowser

    Этот контрол обеспечивает встроенный полноценный браузер в вашем приложении. Он позволяет пользователю перемещаться по веб-страницам внутри формы.

    Пример: WebBrowser Download Event (событие загрузки)

    1. Добавьте контрол WebBrowser на форму. И выставите свойству Dock значение «Fill»
    2. Добавьте следующие события и код:
    3. Функция Navigate переходит по указанному адресу
    4. Событие DocumentCompleted возникает когда вэб страница загружена
    5. Запускайте программу
  • Есть много способов решения вышеуказанной проблемы, например, подсчет фреймов на странице совместно с подсчетом количества срабатываний события DocumentCompleted. Это довольно таки сложно для начинающих, поэтому рассмотрим пример на основе ведения журналов.
  • Добавьте List и модифицируйте наше событие загрузки страницы как показано ниже:
  • Пример: Навигация по сайту

    1. Перед тем как создавать свой парсер сайтов, кликер-бота и т.п. необходимо разобраться с макетом документа, как искать и находить нужные блоки в документе
      1. Найдите на странице интересующий вас элемент
      2. Найдите id этого элемента на странице
    2. Для поиска id можно использовать FireFox, либо Chrome я использую последний
    3. Нажмите в Chrome F12 — Вы войдете в режим «Инструменты разработчика». Нажите на лупу и выберите интересующий вас элемент на странице

    4. Тег привязки (якорь), выделенные на картинке выше, не имеет никакого уникального идентификатора, поэтому, если мы используем функцию GetElementByTag(“a”), то мы получим список всех ссылок на странице, для нас это не вариант
    5. Итак, попробуем поискать ближайший элемент у которого есть >
    6. Теперь мы можем получить адрес нашей ссылки:

    C#: Событие загрузки страницы WebBrowser или как дождаться WebBrowser.ReadyState.Complete

    Сегодня небольшая заметка будет просвещенна компоненту winforms с помощью которого можно имитировать Интернет браузер. Для тех кто не догадался о каком контроле идет речь — это элемент управления WebBrowser.
    Контрол WebBrowser можно использовать для решения большого круга задач. Одной из основных таких задач является парсинг информации с веб ресурсов и автоматизация различных рутинных действий.
    Главной особенностью элемента управления WebBrowser является тот факт, что работать с содержимым страницы можно только после полной загрузки DOM страницы. Многие начинающие разработчики сталкиваются с проблемой, когда после навигации браузера на указанный адрес, программа «падает» с ошибкой доступа к содержимому страницы. Например код ниже, будет генерировать такую ошибку:

    Причина ошибки — w.Document равен null. Почему? Потому что вторая строчка инициирует переход браузера на новую страницу (асинхронно), однако строчка три выполняется сразу после второй (без ожидания загрузки страницы). Интернет страница грузится гораздо дольше чем выполняются строчки кода в программе. А значит программа выполнит строчку три до момента загрузки указанной страницы, что приводит к ошибке в работе. Для такого что бы избежать данной проблемы у контрола WebBrowser существует событие, которое вызывается после загрузки любой страницы. Называется данное событие DocumentCompleted. Пример:

    Теперь мы можем получить доступ к нашей странице без ошибки, так как данный код выполниться только после полной ее загрузки. Данный подход отлично работает, однако если Вам нужно работать не с одной страницей, а с несколькими и выполнять разную логику, то данный поход будет не очень удобен. Причиной этого является то, что событие DocumentCompleted вызывается после загрузки любой страницы, но при этом Вы точно не знаете какой. Значит нужно добавлять дополнительный проверки на текущий Url страницы, что приводит к разрастанию кода и снижению его читаемости.
    Однако есть еще один способ как можно открыть страницу в браузере, при этом дождавшись ее загрузки. Для этого напишем простую вспомогательную функцию:

    Теперь можем работать с нашим WebBrowser следующим образом:

    Вот и все. Надеюсь заметка была полезной ��

    Об использовании WebKit .NET

    Введение

    Связка HTML+CSS+JavaScript на сегодняшний день зарекомендовала себя как универсальный способ построения пользовательских интерфейсов. Причем не только в веб приложениях, но также в десктоп и мобильных приложениях. Примерами тому являются metro-приложения в Windows 8, фреймворк PhoneGap для создания мобильных приложений.

    Реализация интерфейса с помощью HTML, CSS и JavaScript прежде всего подразумевает, что интерфейс будет отображаться в некотором браузере. Если мы рассматриваем десктоп или мобильное приложение, то, очевидно, браузер должен быть встраиваемым.

    В данной статье мы рассмотрим использование WebKit .NET в десктоп приложении на C# под Windows.

    Требования к встраиваемому браузеру

    Выявим основные требования к встраиваемому браузеру.

    Прежде всего, из C# мы должны иметь возможность устанавливать HTML документу произвольное содержимое — т. е. наш интерфейс. Далее естественным образом возникает потребность в коммуникации между C# и JavaScript. Необходимо иметь возможность вызывать C# из JavaScript и JavaScript из C#, причем двумя способами — синхронно и асинхронно. Наше десктоп приложение с интерфейсом, реализованным во встраиваемом браузере, во многом похоже на традиционное веб приложение, имеющее клиент-серверную архитектуру. Поэтому наличие асинхронных вызовов C# из JavaScript очень важно. Эти вызовы представляют собой аналог AJAX запросов в традиционном веб приложении.

    Веб инспектор и отладчик — лучший друг каждого веб разработчика. А как с этим обстоит дело здесь? Скажем сразу — здесь с этим не все так просто. Нам не удалось найти способ отлаживать JavaSсript, выполняющийся во встраиваемом браузере, но мы нашли возможность исследовать dom и получили JavaScript консоль.

    Таким образом, основные требования к WebKit .NET заключались в наличии следующих вещей:

    • возможность устанавливать HTML документу произвольное содержимое
    • вызовы JavaScript из C# синхронно или асинхронно
    • вызовы C# из JavaScript синхронно или асинхронно
    • веб инспектор

    Далее мы рассмотрим, что из вышеперечисленного присутствовало в WebKit .NET и как недостающие функции были реализованы.

    Установка содержимого HTML документа

    Свойство WebKitBrowser.DocumentText позволяет установить HTML документу произвольное содержимое. Наш интерфейс полностью независим от внешних ресурсов, весь JavaScript и CSS мы включаем непосредственно в HTML. Для увеличения производительности все скрипты включаются в минифицированном виде.

    Вызовы JavaScript из C#

    Для вызовов JavaScript из C# в WebKit .NET имеется метод Document.InvokeScriptMethod со следующей сигнатурой:

    К сожалению, данный метод имеет проблему с передачей параметров в JavaScript функцию — она просто не работает.

    Чтобы решить эту проблему нам пришлось разработать свой собственный протокол вызовов JavaScript из C#. Идея заключается в следующем:


    • для передачи параметров используется div с заданным идентификатором
    • C# сериализует имя и массив параметров для JavaScript функции в JSON строку и помещает ее в заданный div
    • JavaScript извлекает JSON, десериализует его и вызывает указанную функцию

    Код вызова JavaScript функции в C# выглядит следующим образом:

    А в JavaScript вызов обрабатывается так:

    Чтобы сделать вызов асинхронным мы просто вызываем указанную функцию с
    задержкой на 1мс. Так как мы не нуждаемся в асинхронных вызовах, возвращающих значение,
    то такое решение нас вполне удовлетворяет.

    Вызовы C# из JavaScript

    Штатного механизма вызовов С# из JavaScript в WebKit .NET в принципе нет. После пристального вглядывания в документацию было найдено событие WebKitBrowser.DocumentTitleChanged. Это, пожалуй, единственное событие, которое JavaScript легко может генерировать в любой момент путем установки document.title.

    Есть две вещи, которые делают это событие привлекательным:

    • document.title можно установить достаточно большим, более 16Кб
    • установка document.title в JavaScript завершается только после выполнения всех обработчиков события DocumentTitleChanged в C#

    Это легло в основу нашего протокола вызовов C# из JavaScript.
    В следующем листинге приведен JavaScript код, предназначенный для вызовов C#.

    Как видно из листинга, каждый вызов снабжается уникальным идентификатором.
    Далее он используется в качестве идентификатора элемента div, в который C# помещает результат.

    Если вызов синхронный, то непосредственно перед своим завершением C# обработчик может
    поместить свой результат в тело HTML документа. В этом случае метод callCSharp может
    извлечь результат из dom сразу после установки document.title.

    Для асинхронных вызовов C# должен инициировать запуск callback функций по завершении
    обработчиков. В этом случае из C# мы вызываем специальный JavaScript метод, приведенный в следующем листинге:

    На стороне C# у нас есть класс CallManager, управляющий подпиской на вызовы из JavaScript. CallManager имеет единственный обработчик события WebKitBrowser.DocumentTitleChanged, который десериализует значение свойства WebKitBrowser.DocumentTitle и, в зависимости от указанного в JavaScript имени (config.name), вызывает соответствующий зарегистрированный обработчик с переданными параметрами. Также CallManager учитывает тип вызова: синхронный или асинхронный. В зависимости от типа обработчик вызывается либо синхронно, либо асинхронно.

    Веб инспектор

    Мы производим разработку интерфейса в два этапа. На первом этапе мы разрабатываем его как традиционное веб приложение, используя браузер и веб-сервер. Только по достижении желаемого результата мы переходим ко второму этапу — упаковке скриптов и интеграции с C#.

    На первом этапе мы активно использовали инструменты разработчика в браузере и имели полный контроль над dom и JavaScript. Но после перехода ко второму этапу весь интерфейс попросту превращался в черный ящик. Возникающие проблемы с версткой и JavaScript становилось достаточно трудно обнаруживать. Мы вынуждены были искать хоть какой-то аналог веб инспектора.

    К сожалению, WebKit .NET не позволяет использовать родной веб инспектор WebKit и никакой remote debugging тут не поддерживается. Поэтому мы решили воспользоваться Firebug Lite (1.4.0) — встраиваемым отладчиком, основанным на Firebug.

    В HTML страницу Firebug Lite мы подключаем следующим образом:

    При работе со встраиваемым браузером удобнее, когда Firebug Lite открывается именно в новом окне, что задается опцией startInNewWindow. Но для того, чтобы это произошло необходимы некоторые манипуляции в C#:

    Конечно, Firebug Lite не поддерживает отладку скриптов, но дает возможность исследовать dom и дает нам JavaScript консоль, а это уже облегчает разработку.

    Заключение

    После всех описанных выше доработок WebKit .NET превратился во вполне пригодный встраиваемый браузер, который стабильно работает и справляется с достаточно большим dom.

    Конечно, реализация интерфейса таким образом сопряжена с определенными сложностями, которые по большей части вызваны отсутствием полноценного веб инспектора, но есть и плюсы. Например, можно повторно использовать JavaScript код из других частей приложения или вообще реализовать одинаковый интерфейс в мобильном, десктоп и веб приложении. Поэтому усилия можно считать оправданными.

    Использование Gecko в C# [GeckoFx]

    Не всех устраивает стандартный движок IE в Винде. Но, к счастью, есть много альтернативных движков для C#, Gecko входит в их число и в этом посте я опишу, как использовать GeckoFx в своих проектах.

    Исходники можно найти в конце статьи.

    На момент написания статьи последняя версия GeckoFx для C# это 22 . Давненько не было обновлений и, возможно, проект умер, но даже 22 версия лучше IE . Так что начнем ��

    Напишем приложение, которое будет заходить на главную станицу гугла, вводить какой-то запрос и переходить по случайному сайту в выдаче.
    Создаем новый проект (Приложение Windows Forms ), называем его « GeckoExample «, переименовываем главную форму в « FrmMain «, размеры главной формы = 514; 399.

    Для работы нам понадобиться:


    Теперь в созданном проекте добавляем ссылки на Geckofx-Core.dll и Geckofx-Winforms.dll.
    Бросаем на форму Panel ( Name = pnl1, Location = 0;0, Size = 495; 25 ), на эту панель добавляем Button ( Name = «btnStart», Location = 0;0, Size = 75; 23, Text = Начнем ), рядом с кнопкой бросаем TextBox ( Name = «tbUrl», Location = 84; 2, Size = 244; 20 ).

    В свойствах проекта переключаем конечную платформу на x86.
    Теперь приступим к написанию кода.
    В using класса главной формы подключаем:

    Добавляем приватное поле _webBrowser типа GeckoWebBrowser:

    В конструкторе класса главной формы пишем следующее:

    Т.е. мы инициализируем движок, указывая путь к движку (у меня он находится в папке с программой). Далее создаем экземпляр класса GeckoWebBrowser (т.е. наш браузер), создаем обработчик события DocumentCompleted (который будет изменять текущий адрес страницы в tbUrl), меняем наш юа и добавляем контрол браузера на форму.
    Кстати, вот реализация метода _webBrowser_DocumentCompleted :

    Настало время написать класс, который будет иметь следующие методы:

    • загрузка главной страницы гугла;
    • написание произвольного поискового запроса в текстовое поле;
    • клик по случайному сайту на странице выдачи.

    Добавляем новый класс GoogleExample и следующие поля:

    Поле _webBrowser — это ссылка на наш браузер, _loadingTimer через 2000 (т.е. две секунды) миллисекунд будет изменять состояние загрузки страницы и _loading — статус загрузки (этому полю наш таймер будет присваивать значение false ).

    Незабываем в using подключить следующее:

    Теперь напишем конструктор класса GoogleExample :

    Конструктор принимает ссылку на браузер, инициализирует таймер. Также создается обработчик события CreateWindow2 . Это событие вызывается перед созданием окна. Нужно нам это событие для того, чтобы «глушить» открытие новых окон при нажатии на ссылку результата на странице выдачи гугла .

    В этом событии мы отменяем открытие нового окна и заставляем главное окно перейти на ссылку, которую хотело открыть новое окно.

    Реализация события Tick для _loadingTimer :

    Все просто: останавливаем таймер и изменяем значение переменной _loading , это значение указывает на статус загрузки страницы.

    Реализация метода WaitForLoading :

    Обычный цикл, каждые 200 миллисекунд проверяется статус загрузки страницы.

    Реализация метода Navigate :

    Открываем браузером страницу, запускаем таймер и асинхронно ждем загрузки страницы.

    Основные методы готовы. Начнем открывать гугл ��

    Метод OpenGoogle загружает главную страницу гугла. Но есть один момент: гугл может быть на английском, потому цикл foreach нужен для того, чтобы пройтись по всем ссылкам на главной странице и найти ту ссылку (если она есть), при нажатии на которую можно переключить язык на русский.

    Следующий в очереди метод ввода поискового запроса — WriteQuery .

    Этот метод получает все input‘ы, далее выбирает первый input, который имеет имя «q». Далее запускается цикл, с помощью которого поисковый запрос вводиться побуквенно (типа, реальный пользователь набирает текст :D). После цикла выбираем все button‘ы и кликаем по первому, у которого имя равно « btnG » (это синяя кнопка для поиска) и ждем загрузки страницы.

    Ну и последний метод в нашем классе — ClickRandomLink .

    Собственно, получаем все ссылки, инициализируем список «нужных ссылок» и запускаем цикл по списку всех ссылок, в котором ищем ссылки, атрибут « onmousedown » которых начинается с « return rwt( » и сама ссылка не содержит « webcache.googleusercontent.com » (иначе получим ссылку на сохраненную копию). дофига ща раз было слово «ссылка». Конструкцию try..catch нужно использовать обязательно, т.к. если попытаться получить доступ к несуществующему атрибуту элемента, то движок выбросит исключение. Например, в том же HtmlAgilityPack все по-другому (и, как мне кажется, удобнее): в методе получения атрибута элемента мы заранее указываем, что нам возвращать, если у элемента нет такого атрибута. Ну да ладно ��

    Возвращаемся к классу формы. Создаем обработчик события Click кнопки btnStart , добавляем к этому методу модификатор async и пишем следующее:

    Ну вот и всё. Можно компилить, тыкать на кнопку и наблюдать результат ��

    Кстати, исходники можно скачать на GitHub.

    66 комментариев на «Использование Gecko в C# [GeckoFx]»

    Исходники на гитхабе, не рабочие, замените, пожалуйста


    Чего в них не рабочего?

    Уже разобрался, не было в сборке xullrunnera.
    Остался вопрос про контрол. Добавляется он на форму кодом this.Controls.Add( this._webBrowser ); как я понял. Но это очень не гибко. Как можно сделать, чтобы строго определенное место было для него выделено? Есть ли возможность масштабирования содержимого под эти размеры?

    Так же интересно, как быть с тегом select. Как выбрать нужный элемент?

    Можно попробовать так:
    https://gist.github.com/dredei/69af2f47b6c36a48fc70
    Код, который выше, должен работать и для тех select‘ов, у которых нет атрибута value в option.

    Это пример, так что ожидать от него какой-то гибкости (чтобы сразу скопировал и работало, как нужно), не стоит ��
    На счет размеров, то я, думаю, не сложно поставить точку после this._webBrowser и глянуть, какие у этого объекта есть поля и методы.
    Среди них есть такие поля, как Height (высота) и Width (ширина), с помощью которых можно настроить размеры контролла. Также следует установить свойство Anchor в AnchorStyles.Left | AnchorStyles.Top , т.к. в примере с помощью якорей (AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom) контролл «цепляется» ко всем краям формы.

    Точно. Спасибо!
    Документации, как я понял, нет на него, даже на английском?

    Документации нет. Когда-то находил примеры (для 16 версии, вроде) на англ.
    Так что метод научного тыка рулит ��

    Я вижу что Вы очень неплохо разобрались с Geckofx. Подскажите если знаете. По свойству geckoWebBrowser1.Document мы получаем доступ к документу, который был уже распарсен движком. Но бывают случаи когда оригинал исходника веб страницы с сервера, не соответствует OuterHtml. Хотя движок и верно отображает страницу, свойство geckoWebBrowser1.Document уже потеряло некоторые данные и к ним не получить доступ. если сделать geckoWebBrowser1.Navigate («view-source:» + url); то код без потерь, но во первых он отображается на странице, что не всегда нужно, во вторых запрашивается с сервера ещё раз, а в третьих он только выглядит верно, а получить доступ к html документу как? OuterHtml это будет уже не оригинал, туда добавится разметка оформления для вывода кода. Надеюсь вы поняли, что я хочу узнать. Заранее спасибо.

    Я не в курсе, как получить оригинал кода, который отдает сервак, с помощью GeckoFx. Т.к. какой смысл таскать за собой такое двигло, если нужно получить просто код (без рендеринга и т.д.), который отдает сервак? Для таких целей есть WebClient ��

    Спасибо за ответ. Таскать двигло имеет смысл в определенных ситуациях. Цель его использования в конкретной проблеме была не в получении исходного кода, движок используется по назначению. Просто параллельно и такой вопрос возник, чтоб программно обработать данные со страницы. К сожалению в связи со скудным документированием сам ответа не нашел. Согласитесь, раз движок все же используется, то глупо городить костыли и обращаться через WebClient, когда эту конкретную страницу уже получил и отобразил движок. Ладно, будем искать, возможно не все потерянно.

    Городить костыли в программировании нужно чуть ли не постоянно �� Т.к. не все либы имеют нужный функционал/работают так, как нужно.
    Ну, либо портировать (допиливать) этот движок самому с преферансом и поэтессами. Но на это уйдет намного больше времени, чем соорудить костыль.

    Также можно попробовать задать вопрос тем, кто портировал двигло здесь.
    П.С. На счет view-source. Можно схитрить и получить доступ к коду так:
    _webBrowser.Navigate( «view-source: someurl» );
    string html = _webBrowser.Document.GetElementsByTagName( «html» )[ 0 ].TextContent;
    В теории, должно сработать ��

    Здравствуйте, не подскажете как в gecko 29 версии изменить дерикторию куки?
    Xpcom.ProfileDirectory — меняет только папку кеша а куки остаются стандартно C:\Users\Админ\AppData\Local\Geckofx\DefaultProfile

    Здравствуйте! У меня отлично все меняет. Пишет все данные (кеш, куки и т.д.) профиля туда, куда я и указал.

    У версии geckoFX 29,0,6 и выше — куки остаются в стандартной папке!
    И еще прошу помощи с авторизацией Proxy по паролю..
    Буду ждать ваших коментариев по этому поводу. Спасибо..

    Специально только что проверил на 29.0.11 — все данные профиля сохраняются там, где я и указал.
    На счет прокси — смотрите пример здесь.

    А можно примерчик на почту или ссылку на пример? только без браузера! что не делаю всеравно куки сохраняет в стандартную папку!
    сижу уже пару дней, ничего толком не выходит(
    Спасибо за быстрые, супер быстрие отзывы…
    Спасибо..

    В общем, ничего особенного. Делаю так, как вы и писали ��
    Пример отправил на почту (указываю профиль в конструкторе главной формы).

    Низкий поклон вам, все, разобрался)

    так работает
    Xpcom.ProfileDirectory = Application.StartupPath + «\\bin\\cookie»;
    Xpcom.Initialize(Application.StartupPath + «\\xulruner\\»);

    так неработало у меня
    Xpcom.Initialize(Application.StartupPath + «\\xulruner\\»);
    Xpcom.ProfileDirectory = Application.StartupPath + «\\bin\\cookie»;

    в чем разница такого события? раньше все работало до обновления версии.

    Сасибо, ваш пример решил мою проблему…

    Фиг знает, почему раньше работало. Может, те, кто портировали новую версию что-то изменили или это изменения в самом движке.
    В принципе, логично, что сначала указывает профиль, а потом инициализируем движок (так как раз Лиса и работает: сначала выбираем профиль, а потом уже запускается браузер).

    Хорошо что хорошо все решилось. Для этого буду знать куда вертеть))

    Спасибо за ответы. буду внимательно читать ваш блог.

    с автоматической авторизацией прокси по паролю разобрался. если нужно будет кому-то пример то через админа будет можно взять пример.
    Спасибо еще раз..

    Не за что, удачного кодинга ��

    Здравствуйте, столкнулся с проблемой. Открытия окон в новой вкладки, неработает с некоторыми сайтами, в основном с многими. Вот навожу пример с одним из сайтов — http://123.sovetam.ru Во время подписки выскакивает новая вкладка, но сайт сообщает об ошибке. Если не блокировать окно то подписка проходит нормально! Пробовал подставлять реферер но толку мало, хоча на некоторых из кликовых спонсоров, клики по ссылкам, открытие в новом окне, реферер помог! Без реферера клики тоже непроходили.
    Прошу помощи, так как это является большой проблемой с использованием геско вкладки. Спасибо.. Буду ждать ответа.

    Просто происходит не просто открытие окна, а еще и отправка post-запроса, потому и сообщает об ошибке.
    Здесь уже нужно сидеть и копать (и гуглить :)), у меня сейчас времени на это нет, занят другим проектом.

    У меня такой вопрос странный. Не могу разобраться как работает ваша синхронизация? Как узнать что страница полностью прогрузилась и с ней можно дальше работать?
    с обычным компонентом webBrowser я проверял на ReadyState, если он completed то идем дальше.
    Но тут как то не могу разобраться, подскажите, а?)

    Здесь таймер, который меняет состояние булевой переменной (_loading) по истечению 2 секунд после начала загрузки страницы. Переменные подписаны комментариями, не сложно в студии выбрать нужную переменную и юзануть «Find Usages», чтобы увидеть места, где она используется/изменяется ее состояние.
    Ни в одном из компонентов нельзя четко определить полную загрузку страницы, т.к. сейчас сайты напичканы кучей js скриптов, которые после загрузки документа могут много чего изменить на странице и это фиг отловишь. С одними сайтами DocumentCompleted работает идеально, с другими — вечная загрузка, а третьи вообще на одном аяксе. Так что лучше делать всякие «комбо» из таймеров, метода DocumentCompleted и свойства IsBusy.

    я просто не нашел зависимости таймера и загрузки. он просто меняет переменную и говорит, что страница загрузилась через 2 секунды? а если она не успела загрузиться за это время?
    или я что то упустил?

    В данном примере таймер решает: загрузилась страницы или нет �� Это же пример, лень было что-то «мега-крутое» для простого примера делать.
    А если она не успела загрузится, то работа продолжиться с не загруженной страницей.

    ага, я понял. Спасибо.
    а может подскажите еще какие сторонние компоненты, в которых это решается более просто, при мопощи методов и свойств?

    проблема стандартного веб-браузера в том, что он почему то не перегружает содержимое документа, вообще никак. (как загрузил после первой навигации, так и все)
    я так понял в Gecko с этим все ок, вот только нужно костылить с синхронизацией?

    Я ниже описал, что ни в одном компоненте (с которым я сталкивался �� ) нельзя одним методом/событием определить полную загрузку страницы (еще в Делфи 7 и выше с этой фигней сталкивался и перепробовал еще тогда кучу компонент). Даже обычный браузер (Хром, Лиса) не может этого сделать ��
    А костыль с загрузкой достаточно простой: используем таймер и проверку свойства IsBusy. Таймер «заводим» на, например, 10 секунд, при срабатывании таймера меняется значение переменной _loading в false.
    А в методе открытия ссылки, где происходит ожидание загрузки страницы, делаем простой цикл:
    while (_wb.IsBusy && _loading)
    <
    // ждем
    >
    _loadingTimer.Stop();
    // работаем со страницей

    Использовать таймер в любом случае нужно, т.к. может какой-то скрипт какого-то нафиг ненужного счетчика, который загружается синхронно, «повешать» страницу (т.е. будет грузиться вечно или очень долго) и в итоге программа будет ждать, как Хатико ��

    П.С. Считаю GeckoFX самым нормальным двиглом для C#. Сталкивался с портом Хромиума (уже не помню, как называется), но там всё печально. Нужно лепить «обертку» для работы с элементами страницы на JavaScript, а в GeckoFX уже из коробки реализованы классы веб-элементов, сделана удобная работа с ними и т.п.

    Понравилась статья? Поделиться с друзьями:
    Все языки программирования для начинающих