Sunday, May 20, 2007

Automating Internet Explorer with Ruby: Without Watir

In a previous post, I discussed how to use the watir library to automate Microsoft Internet Explorer. I should also mention that you can also do this directly, using the win32ole library. Let's take a look at how to do this...

First, require the win32ole library...


require 'win32ole'

Create a new instance of Internet Explorer...

ie = WIN32OLE.new('InternetExplorer.Application')

(NOTE: You cannot use the WIN32OLE.connect method to connect to a running instance of Internet Explorer, as you would do, for example, with Excel or Word. I'll explain later how to do this via the Windows Shell. Stay tuned...)

You can show or hide the IE window by setting the Visible property...

ie.Visible = true

Navigate to a URL using the Navigate method...

ie.Navigate('http://google.com')

Wait until IE has completed loading the page, by checking the ReadyState property...

sleep(1) until ie.ReadyState == 4

When a web page is loaded into IE, the contents of the page are represented by the Document object. The document object's All method returns a collection of all elements within the document, such as input textboxes, links, buttons, etc. You may reference a document element by name, which you will find in the HTML code for that page. For example, viewing the source for the google.com top page shows us, among others things, that we have a textbox named 'q' and a button named 'btnG'...

input maxlength=2048 name=q size=55 title="Google Search" value=""
input name=btnG type=submit value="Google Search"

Let's enter a value into the textbox named 'q' by setting its Value property...

ie.Document.All.q.Value = 'ruby on windows'

...and then click the button named 'btnG', by calling its Click method...

ie.Document.All.btnG.click

...and wait until IE has completed loading the page...

sleep(1) until ie.ReadyState == 4

The Document.All.Tags method returns a collection of all elements with the specified HTML tag, such as 'a', 'tr', or 'input'. So, to get a collection of all links, you could do this...

links = ie.Document.All.Tags('a')

You could then iterate over this collection...

for link in links do
puts link.InnerText # print the link's text
puts link.href # print the link's URL
end

To quit IE, call the application object's Quit method...

ie.Quit

There is much more to automating IE than I what I have presented here, but this will hopefully get you started. As always, feel free to post a comment here or email me if there is a specific task or topic that you would like to see discussed here.

This is all about helping you make better use of Ruby on Windows.

Thanks for stopping by!


Digg my article

17 comments:

Chriss713 said...

Is there also an easy way how to automate other browsers such as Firefox or Opera?h

DFG said...

Yes it is ! FireWatir for Firefox and works very well - http://code.google.com/p/firewatir/downloads/list .

LeoB said...

I am a total beginner in Ruby. To learn a little bit easily I just took code from your blog article and created a file ie-check.rb:

require 'win32ole'
ie = WIN32OLE.new('InternetExplorer.Application')
ie.Visible = true
ie.Navigate('http://google.com/')
sleep(1) until ie.ReadyState = 4
ie.Quit

Then I ran this with

ruby -dw ie-check.rb

IE started and loaded the page as expected, but I got

C:\rubytest\ie>ruby -dw ie-check.rb
Exception `WIN32OLERuntimeError' at ie-check.rb:5 -
OLE error code:0 in Unknown
No Description
HRESULT error code:0x8002000e
Invalid number of parameters.
ie-check.rb:5:in `method_missing': (WIN32OLERuntimeError)
OLE error code:0 in Unknown
No Description
HRESULT error code:0x8002000e
Invalid number of parameters. from ie-check.rb:5

What is wrong here?

David Mullet said...

@leob:

Change this:

sleep(1) until ie.ReadyState = 4

To this:

sleep(1) until ie.ReadyState == 4

Ruby uses '==' to test for equality.

David

LeoB said...

David: Thanks. I think I could have wondered a long time about that "Invalid number of parameters" ... ;-)

I started testing Watir afterwards. It has some nice features for testing. I want to do some testing from my pc (or some other pc) at irregular intervals of some web pages I am responsible for.

One problem I immediately ran into then is how to hide the IE window. I hide it this way now

$ie = Watir::IE.new()
$ie.getIE.Visible = false

However doing it that way IE flashes bye. That could be quite inconvenient.

Another problem I wonder about is how to empty IE:s cache when I use Watir. I need to do that to check the performance of the web server.

David Mullet said...

@LeoB:

To hide the browser window from the start, run your watir script with the "-b" command line argument:

myTest.rb -b

I'm not aware of a means to programatically empty the browser cache directly. You could perhaps include code to delete files in the user's 'Temporary Internet Files' folder, though I haven't tried that.

David

LeoB said...

Thanks David, I tried on the mailing list to and got the answer

"Either pass -b to watir as a command line option, or set
$HIDE_IE = true before calling Watir::IE.new."

But it seems to be harder to clear the cache.

Todd said...

I'm having trouble getting IE automation to work on Vista x64 with 32-bit IE 7.

When I try to access the Document property, OLE returns the error code 0x80040005.

Also, the gohome method works, but returns error code 0x800704c7.

Do you have any idea as to what is going on here?

Todd said...

I just tested the Ruby WIN32OLE functionality with 32-bit Vista. Attempting to access Document gives the same error code as with 64-bit Vista.

Do you know if this capability has been tested with Vista? Both tests used the latest Ruby included with InstantRails.

Todd said...

Problem solved. You need to run as Administrator in order for it to work.

Anonymous said...

How do you open up multiple tabs with the WIN32OLE library?

David Mullet said...

@anonymous:

In IE7...

To navigate to a site in a new tab, pass the Navigate method a second parameter of 2048:

ie.Navigate('http://google.com', 2048)

To navigate to a site in a new window, pass the Navigate method a second parameter of 1:

ie.Navigate('http://google.com', 1)

David

Anonymous said...

Any way to click on a save or open dialog box? can you post an example of how to click on any of these buttons?

David Mullet said...

@Anonymous:

You can use Windows Scripting to activate a window and send keystrokes to it:

require 'win32ole'

wsh = WIN32OLE.new('Wscript.Shell')

if wsh.AppActivate("Save As")
wsh.SendKeys("c:\temp\myfile.xls{ENTER}")
end

I've written an article that covers this here.

David

Anonymous said...

This topic might be a little bit old, but I have got a question to Win32ole.

There is a page, where I can click several buttons and get to new pages. But when I try to read out these new pages, I only get the text of the old page, although I do see this new page. (well, this was a lot of pages ;)

Exemple:

# call a page
# read out via ie.Document.All.Tags("a")
# click on a button -> get a new page
# read out again
# get the same text ??

How can I update ie to get the text (html) of this new page?

harsha said...

Is there a way to access tabs in IE

Mahesh Shivankar said...

Can IE dialog boxes for downloading any file be automated ?