WebBrowser launch internet explorer - c#

I'm trying to parse content from URL's that contains a lot of Javascript generated content, for that I'm using WebBrowser control. Initially I had many issues when loading all the urls of my list of target urls in the same instance of the object, so I decided to dispose the object every few requests and then create a new instance and so on. The issue I'm facing now is that sometimes, when I Dispose the object, it opens a new IE browser window, independent from my application, loading the url's of the object that I've already disposed. Here is my code:
I saw a similar answer in this post, but it's not working for me.
Why is sometimes WebBrowser.Dispose() launching Internet Explorer?
private void TriggerNavigation ()
{
if (urlList.Count > 0)
{
progressBar1.Value++;
if (LoopUrls++ >= 1)
{
URL = string.Empty;
LoopUrls = 0;
timerAjaxLoad.Stop();
webBrowser1.Stop();
webBrowser1.AllowNavigation = false;
webBrowser1.Dispose();
webBrowser1 = null;
GC.Collect();
webBrowser1 = new WebBrowser();
}
URL = urlList.First();
label1.Text = "Processing.." + URL;
webBrowser1.ScriptErrorsSuppressed = true;
webBrowser1.Navigate(URL);
webBrowser1.Navigating += webBrowser1_Navigating;
timerAjaxLoad.Start();
urlList.RemoveAt(0);
}
else
{
timerAjaxLoad.Stop();
}
}
UPDATE:
I figured out what was causing the issue. It was not happening for all the pages, but only for some with embedded JS that was triggering an external page. By catching the Navigating event and cancel the script calls to that page, it solved the issue.
void webBrowser1_Navigating (object sender, WebBrowserNavigatingEventArgs e)
{
foreach (HtmlElement x in ((WebBrowser)sender).Document.GetElementsByTagName("script"))
{
if (x.OuterHtml.Contains("survey"))
e.Cancel = true;
}
foreach (HtmlElement x in ((WebBrowser)sender).Document.GetElementsByTagName("iframe"))
{
e.Cancel = true;
}
}

I figured out what was causing the issue. It was not happening for all the pages, but only for some with embedded JS that was triggering an external page. By catching the Navigating event and cancel the script calls to that page, it solved the issue.
void webBrowser1_Navigating (object sender, WebBrowserNavigatingEventArgs e)
{
foreach (HtmlElement x in ((WebBrowser)sender).Document.GetElementsByTagName("script"))
{
if (x.OuterHtml.Contains("survey"))
e.Cancel = true;
}
foreach (HtmlElement x in ((WebBrowser)sender).Document.GetElementsByTagName("iframe"))
{
e.Cancel = true;
}
}

Related

Why the Login web page isn't showing in webBrowser?

I am using C# to login to a local web page.
I am using webBrowser in order to display the page after the log.
First, I navigate to page then I fill the username & password then I invoke a click.The element to be clicked is recognized; so I assume that the click happened. But the result page isn't showing, nothing appears when I execute.
I tried this:
public WebBrowser webBrowser;
public MainWindow()
{
InitializeComponent();
webBrowser = new WebBrowser();
webBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(LoginEvent);
webBrowser.AllowNavigation = true;
webBrowser.Navigate("http://192.168.1.100/login.html");
}
private void LoginEvent(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser webBrowser = sender as WebBrowser;
//To execute the event just one time
webBrowser.DocumentCompleted -= LoginEvent;
//load page's document
HtmlDocument doc = webBrowser.Document;
doc.GetElementById("u").SetAttribute("value", "admin");
doc.GetElementById("pw").SetAttribute("value", "123456");
foreach (HtmlElement elem in doc.GetElementsByTagName("a"))
{
elem.InvokeMember("click");
}
}
Can anyone help me please to figure why the page isn't showing?
1) Your WebBrowser object is a local variable in your MainWindow() constructor.
This object is being deposed once the MainWindow constructor ends.
You need to declare the WebBrowser object as a class member.
2) There might be a multiple DocumentComplete events being fired. You need to filter out all iFrame events and wait before the page being fully loaded:
private void LoginEvent(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// filter out non main documents
if (e.Url.AbsolutePath != (sender as WebBrowser).Url.AbsolutePath)
return;
//To execute the event just one time
webBrowser.DocumentCompleted -= LoginEvent;
//load page's document
HtmlDocument doc = webBrowser.Document;
doc.GetElementById("u").SetAttribute("value", "admin");
doc.GetElementById("pw").SetAttribute("value", "123456");
foreach (HtmlElement elem in doc.GetElementsByTagName("a"))
{
elem.InvokeMember("click");
}
}

How to disable every navigation in WebBrowser?

I have a WebBrowser control which I dinamically refresh/change url based on user input. I don't want to let the user to navigate, so I set AllowNavigation to false. This seems to be OK, however the below link is still "active":
Close Page
The issue here is: If the user clicks it, and confirms closure in the pop-up window I can't manage WebBrowser anymore. Looks like it is closed though the last page is still visible. Also I can't remove this link as the site is not managed by me.
Disable the control? Nope, I have to allow the user to highlight and copy text from the webpage.
Do I have any other option to disable literally ALL links?
#TaW: here is my code based on yours. So I have to set the url from my code and call a custom one:
button_click()
{
webBrowser1_load_URL("http://website/somecheck.php?compname=" + textBoxHost.Text);
}
Here it is the function:
private void webBrowser1_load_URL(string url)
{
string s = GetDocumentText(url.ToString());
s = s.Replace(#"javascript:window.close()", "");
webBrowser1.AllowNavigation = true;
webBrowser1.DocumentText = s;
}
The rest is exaclty what's in your answer:
private void webBrowser1_DocumentCompleted(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
webBrowser1.AllowNavigation = false;
}
public string GetDocumentText(string s)
{
WebBrowser dummy = new WebBrowser(); //(*)
dummy.Url = new Uri(s);
return dummy.DocumentText;
}
Still it's not working. Please help me to spot the issue with my code.
If you have control over the loading of the pages you could grab the pages' text and change the code to disable rogue scripts. The one you showed can simply be deleted. Of course you might have to forsee more than the one..
Obviously this could be eased if you could do without javascript alltogether, but if that is not an option go for those that do real or pseudo-navigation..
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
webBrowser1.AllowNavigation = false;
}
private void loadURL_Click(object sender, EventArgs e)
{
webBrowser1.AllowNavigation = true;
string s = File.ReadAllText(textBox_URL.Text);
s = s.Replace("javascript:window.close()", "");
webBrowser1.DocumentText = s;
}
If the pages are not in the file system, the same trick should work, for instance by loading the URL into a dummy WebBrowser like this:
private void cb_loadURL_Click(object sender, EventArgs e)
{
string s = GetDocumentText(tb_URL.Text);
s = s.Replace("javascript:window.close()", "");
webBrowser1.AllowNavigation = true;
webBrowser1.DocumentText = s;
}
public string GetDocumentText(string s)
{
WebBrowser dummy = new WebBrowser(); //(*)
dummy.Url = new Uri(s);
return dummy.DocumentText;
}
Note: According to this post you can't set the DocumentText quite as freely as one would think; probably a bug.. Instead of creating the dummy each time you can also move the (*) line to class level. Then, no matter how many changes you had to make, you would always have an unchanged version, th user could e.g. save somewhere..

DocumentCompleted firing only once

I have a WebBrowser inside a form and I want to do some automation with it. I click a button inside a windows form that commands the Navigate method of the WebBrowser to a certain page. Then I automatically click a link after DocumentCompleted has fired but after that I want to also click a Button that exists in the new page that appeared by clicking the link. It seems DocumentCompleted fires only when I click the button in the windows form not when I automatically click the a link inside the webpage.
void BtnTestClick(object sender, EventArgs e)
{
webBrowser1.Navigate(#"https://play.google.com/apps/");
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted);
}
public void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var webBrowser = sender as WebBrowser;
//webBrowser.DocumentCompleted -= WebBrowser_DocumentCompleted;
// test to see if we're on fist CONFIRM page then go forward by clicking
var links = webBrowser1.Document.GetElementsByTagName("a");
foreach (HtmlElement link in links)
{
if (link.InnerText == "Proceed anyway")
{
link.InvokeMember("click");
}
} // this works
webBrowser1.Document.GetElementById("gwt-uid-126").InvokeMember("click");
}
After the link.InvokeMember("click"); a new page loads in the webbrowser that has a button which I also want to click ( gwt-uid-126 )
But it doesn't get clicked.
I've also tried:
var elements = webBrowser1.Document.GetElementsByTagName("button");
foreach (HtmlElement file in elements)
{
if (file.GetAttribute("class") == "GKYRWGTDNX GKYRWGTDLY")
{
file.Focus();
file.InvokeMember("click");
}
}
With no luck!
From what I see, second click doesn't work because the document is not completely loaded and second click is invoked.
You will have to add another if-else block that handled second document load.
Edit1: I was on phone when I answered this, so couldn't provide any snippet. Following is the change that you can do WebBrowser_DocumentCompleted method.
var links = webBrowser1.Document.GetElementsByTagName("a");
foreach (HtmlElement link in links)
{
if (link.InnerText == "Proceed anyway")
{
link.InvokeMember("click");
}
}
// following is for the page that is loaded on click of link.
var gwt_uid_126 = webBrowser1.Document.GetElementById("gwt-uid-126");
if(gwt_uid_126 != null)
{
gwt_uid_126.InvokeMember("click");
}
You might want to check if the WebBrowser_DocumentCompleted method is actually being called on second page load. This might be the reason why second click is not registering.
move this part of code in the Constructor or Form_Load:
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(WebBrowser_DocumentCompleted);
try this instead of using WebBrowserDocumnetCompletedEventHandler:
void btnTestClick(object sender, EventArgs e)
{
webBrowser1.Navigate(#"https://www.google.com/");
while (webBrowser1.ReadyState != WebBrowserReadyState.Complete)
continue;
var webBrowser = sender as WebBrowser;
//webBrowser.DocumentCompleted -= WebBrowser_DocumentCompleted;
// test to see if we're on fist CONFIRM page then go forward by clicking
var links = webBrowser1.Document.GetElementsByTagName("a");
foreach (HtmlElement link in links)
{
if (link.InnerText == "Proceed anyway")
{
link.InvokeMember("click");
}
} // this works
webBrowser1.Document.GetElementById("gwt-uid-126").InvokeMember("click");
}

Wait for loading page after button click

I want to be able to click on button and than wait for the page to load.
I search, but there is no solution that work correctly.
This is part of code:
el = webBrowser1.Document.GetElementById("LoginButton");
el.InvokeMember("click");
webBrowser1.Navigate(url);
I need it to be that after click, the application will load the page, and only then go to another page.
Also, webBrowser1.Navigate(url) must be in the same method as click. Because it all in a loop.
Please help.
EDITED.
*More code* (first code was and example of what i need)
List<string> list1 = new List<string>();
bool flag = true;
while (flag)
{
flag = false;
foreach (HtmlElement he2 in webBrowser1.Document.GetElementsByTagName("a"))
{
if (he2.GetAttribute("href").Contains("profile.php?ID="))
{
list1.Add(he2.InnerText);
}
}
foreach (HtmlElement he in webBrowser1.Document.GetElementsByTagName("a"))
{
if (he.InnerHtml == "Next")
{
flag = true;
he.InvokeMember("click");
}
}
}
When I click, next page must load, and i have to parse tag on next page, but it begin parse page before next page is load, so it parse the same page.
Finally, I just got href from my button and used this code(insted of he.InvokeMember("click"))
:
webBrowser1.Navigate(url_next);
while (webBrowser1.ReadyState != WebBrowserReadyState.Complete)
Application.DoEvents();
It works fine.
You can use the DocumentCompleted event to find out when the login has completed.
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
el = webBrowser1.Document.GetElementById("LoginButton");
el.InvokeMember("click");
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
Uri myUrl = new Uri("http://stackoverflow.com");
if (e.Url == myUrl)
{
WebBrowser1.Navigate(url);
}
}

Adding back and forward button for WebBrowser control

I have a WebBrowser element in a page, to which I would like to add a back and forward buttons, and have those buttons disabled when there's nothing to go back to and nothing to go forward to.
In Cocoa, the UIWebView has methods to easily check that: canGoBack and canGoForward, and you have goBack and goForward methods available (along with reload etc..)
Android has the exact same method names for achieving the same.
I see those methods are available in .Net 4 and 3.5 SP1.
I've found some references about using javascript commands in Silverlight but I find this very cumbersome, plus there's no way to detect if there's anything in the history (unless of course I manage this myself)
Surely, there's something a tad more advanced in Windows Phone ..
Here is how I ended up doing it.
This assumes you have set a backButton and forwardButton; the status of these buttons will be updated accordingly depending on where you are in the navigation stack.
webView is the WebBrowser object
List<Uri> HistoryStack;
int HistoryStack_Index;
bool fromHistory;
// Constructor
public HelpView()
{
InitializeComponent();
HistoryStack = new List<Uri>();
HistoryStack_Index = 0;
fromHistory = false;
webView.Navigated += new EventHandler<System.Windows.Navigation.NavigationEventArgs>(WebView_Navigated);
UpdateNavButtons();
}
private void backButton_Click(object sender, RoutedEventArgs e)
{
if (HistoryStack_Index > 1)
{
HistoryStack_Index--;
fromHistory = true;
webView.Navigate(HistoryStack[HistoryStack_Index-1]);
updateNavButtons();
}
}
private void forwardButton_Click(object sender, RoutedEventArgs e)
{
if (HistoryStack_Index < HistoryStack.Count)
{
HistoryStack_Index++;
fromHistory = true;
webView.Navigate(HistoryStack[HistoryStack_Index-1]);
UpdateNavButtons();
}
}
private void UpdateNavButtons()
{
this.backButton.IsEnabled = HistoryStack_Index > 1;
this.forwardButton.IsEnabled = HistoryStack_Index < HistoryStack.Count;
}
private void WebView_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
if (!fromHistory)
{
if (HistoryStack_Index < HistoryStack.Count)
{
HistoryStack.RemoveRange(HistoryStack_Index, HistoryStack.Count - HistoryStack_Index);
}
HistoryStack.Add(e.Uri);
HistoryStack_Index++;
UpdateNavButtons();
}
fromHistory = false;
}
I have a back button added to the applicationbar of a page in one of my apps which contains a webbrowser. I wanted the back button in the app bar to take the web page navigation backward, and wanted the hardware back button to go to the previous xaml page. This way, the user doesn't have to use the hardware back button to navigate backward through all the visited web pages in the webbrowser in order to go back to the prior xaml page. Here is how I did it, and you could easily set up a forward stack and when the user clicks the back (appbar) button, the page pops from that stack and is pushed to the forward stack.
private void NavigateWeb()
{
if (!loaded)
{
NavigationStack.Clear();
try
{
Web.Source = new Uri("http://m.weightwatchers.com/");
loaded = true;
}
catch (Exception ex)
{
MessageBox.Show("Unable to navigate to page.\n" + ex.Message,
"Error", MessageBoxButton.OK);
}
}
}
void Web_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
{
NavigationStack.Push(e.Uri);
}
void btnBack_Click(object sender, EventArgs e)
{
if (NavigationStack.Count > 2)
{
// get rid of the topmost item...
NavigationStack.Pop();
// now navigate to the next topmost item
// note that this is another Pop - as when the navigate occurs a Push() will happen
Web.Navigate(NavigationStack.Pop());
}
}
The reason I check for NavigationStack.Count > 2 is that the particular webpage that I'm showing in the webbrowser always starts with a "click here to continue" link on the first page, and there is no reason to go back to there. That's the downfall of showing other people's sites in your webbrowser - you don't have control over what is shown.
In regards to the javascript solution it is doing something like this:
private void backButton_Click(object sender, RoutedEventArgs e)
{
try
{
webView.InvokeScript("eval", "history.go(-1);");
}
catch
{
// Eat error
}
}
private void forwardButton_Click(object sender, RoutedEventArgs e)
{
try
{
webView.InvokeScript("eval", "history.go(1);");
}
catch
{
// Eat error
}
}
with having the IsScriptingEnabled set to true for the WebBrowser element.
However, this always generates an exception with error 80020006. I read various posts about how the DOCTYPE could have been the culprit, the system caching or IsScriptEnabled being set after the content was loaded... It just never worked...

Categories

Resources