Sunday, April 5, 2009

Handling the faulty WebBrowser control

The last post dealt with using the WebBrowser control to communicate with a website. Today I will take that post a step further and explain how to workaround the faulty responses the WebBrowser control returns regarding its status when loading a page. In the last post, we saw that the following code allows us to communicate with a website, navigating our control to a specific URL, and even sending POST data along with our request:

Sub Brws()
Dim URL As String, PostData() As Byte
URL = "https://www.google.com"

PostData = "name=ben&lname=cavallaro"
PostData = StrConv(PostData, vbFromUnicode)
Me.WebBrowser1.Silent = True
Me.WebBrowser1.Navigate URL, 0, "", PostData, ""
Do
DoEvents
Loop Until Me.WebBrowser1.ReadyState = 4
End Sub


Today we will take this a step further, refining our code for checking whether the browser is done loading and also setting a variable equal to the html code of the page the control has navigated to.

Starting with the easier of the two, all we need to do to read the html from the page is use this line of code at any point after you have successfully completed the WebBrowser.Navigate command.

varname = Me.WebBrowser1.Document.Body.innerHTML

where varname is the variable you want to set equal to the html code, and your WebBrowser control is accessing the "Document" property of the WebBrowser control which allows you access to a number of the elements of the document itself. More info on this can be found at MSDN. For our purposes, this simple line of code pulls all the html from the page. However, because our WebBrowser control does not return a reliable result on whether it has finished loading the page, sometimes setting a variable equal to the Document.Body.innerHTML will return an error "91" because the page has not finished loading and therefore the property is not yet set. To deal with this, we will use error handlers and labels in our code.
An error handler tells your code snippet what to do when an error occurs. By default, an error in vba will trigger a Message box with the error number and a description of the error and then the program will terminate. Other options include "On Error Resume Next" which will simply ignore errors and move forward with the code, skipping the line that caused the error, "On Error Goto 0" which will end code execution silently when an error occurs, or "On Error Goto labelname" where "labelname" is a name you've chosen. By doing this, you will have to build your own error handler. In this case, we want to use "On Error Goto LabelName" to set up our own error handler. It will look like this:

Sub Brws()
On Error Goto errhandler
Dim URL As String, PostData() As Byte
URL = "https://www.google.com"

PostData = "name=ben&lname=cavallaro"
PostData = StrConv(PostData, vbFromUnicode)
Me.WebBrowser1.Silent = True
Me.WebBrowser1.Navigate URL, 0, "", PostData, ""
Do
DoEvents
Loop Until Me.WebBrowser1.ReadyState = 4

RD:
abc = Me.WebBrowser1.Document.body.innerhtml
Exit Sub

ERRHANDLER:
If err.number = "91" Then
Resume RD
Else
Msgbox err.number & err.description
End If
End Sub

This bit of code incorporates labels and GoTo statements as well as an error handler. In the beginning we tell the code to goto "errhandler" if an error occurs. at the END of our code we define our errhandler section using a label "ERRHANDLER:".
Essentially, our errorhandler stops the code from reporting any error #91's, and instead loop back to around to the point in the code that is causing that error. In this way, we can create a loop that keeps attempting to set the variable "abc" to the value of innerHTML until it can successfully do so. If it's not an error #91, the errorhandler reports the error and then ends (because there is no more code to execute - which is why the errorhandler is placed at the end of the code).
Note that in our error handler we use the code "Resume RD" to goto our label "RD:". During a break operation like an error handler, we use "Resume" instead of "GoTo" to direct the code back to a label. Also not that after the last command PRIOR to our error handler code, we insert the "Exit Sub" code so that our code does not continue into our error handler unless directed to do so.

No comments:

Post a Comment