0

I'm attempting to have Excel open a web site, populate some fields, submit, and download the resulting data in a file.

My code never gets very far, however, because it looks like Excel doesn't recognize "getelementsbytagname" as an existing operation. I assume this is the issue because it does not correct the case to GetElementsByTagName like it does for everything else.

My References in the editor include Microsoft Internet Controls and Microsoft HTML Object Library. Is there another one that I need to activate?

The code is just a modified version of something found online.

Private Sub IE_automation()
'Retrieve data from Enterprise Reporting with IE
Dim i As Long
Dim IE As Object
Dim objElement As Object
Dim objCollection As Object

'Create Internet Explorer Object
Set IE = CreateObject("InternetExplorer.Application")

'Comment out while troubleshooting
'IE.Visible = False

'Send the form data to URL as POST binary request
IE.Navigate "http://corpprddatawhs1/Reports/Pages/Report.aspx?ItemPath=%2fInventory%2fInventory+By+Branch"

'Set statusbar
Application.StatusBar = "Webhost data is loading. Please wait..."

'Wait while IE loading
Do While IE.busy
    Application.Wait DateAdd("s", 1, Now)
Loop

'Find 2 input tags:
'   1. Text field
'   <input type="text" class="null" name="ct132$ct104$1ct105$txtValue" size="30" value="" />
'
'   2. Button
'   <input type="submit" value="View Report" />

Application.StatusBar = "Searching form submission. Please wait..."

Set objCollection = IE.document.getelementsbytagname("input")
  • Yeah, sure, although I'd be surprised if this has anything to do with the code and everything to do with the compiler not recognizing "getelementsbytagname." But I'll put my code up if you think it'll help. – Rob Schwenck Dec 22 '17 at 18:56
  • Yeah, I see now that IE.document may not be the right way to go. The error for that is -2147467259(80004005) Method of object failed. Replacing it with HTMLDocument throws a 438, object doesn't support the property or method. – Rob Schwenck Dec 22 '17 at 19:26
  • But the getelementsbytagname is still not capitalizing correctly as if the compiler isn't recognizing it as a method at all. It does exist in the Object Browser. – Rob Schwenck Dec 22 '17 at 19:28
  • Do you get intellisense when you retype the dot between `document` and `getelementsbytagname`? If so, all is good. If not, all that means is that `document` is an `Object` and indeed, the compiler doesn't care what you type; calls against `Object` are always late-bound/resolved at run-time. Capitalization makes no difference, VBA is case-insensitive. Type `Dim getElementsByTagName`, hit ENTER, then delete that declaration: poof, fixed. If `document` is `Object`, declare a local variable for `IE.document`, using the correct type - you'll get intellisense for its members then. – Mathieu Guindon Dec 22 '17 at 19:32
  • If intellisense is the menu that pops up after hitting "." after something like "Application" then no, I'm not getting intellisense. – Rob Schwenck Dec 22 '17 at 19:37
  • Ctrl+i on `document` says what? `Object`? I don't use that library, so I'm not sure what the correct type is, but if you cast it to, e.g. a `HtmlDomDocument` (no idea if that's the correct type) by declaring a variable of that type and assigning it to `IE.document`, then `thatVariable.` should bring up *that menu that pops up after hitting "."* – Mathieu Guindon Dec 22 '17 at 19:39
  • @Mat'sMug should it be Document or HTMLDocument? IE is an object and set as an IE application. My expectation of the code I borrowed is that "document" was to refer to the page that loaded and getelements... would populate the collection objCollection. Typing that, I thought maybe that ought to be type collection, changed it all over and reran. Negative. Same 438 error. – Rob Schwenck Dec 22 '17 at 19:44
  • I don't know, I don't use that library. You can find out what the correct type is with `Debug.Print TypeName(IE.document)` – Mathieu Guindon Dec 22 '17 at 19:45
  • Not sure what cntrl+i is supposed to do; it only makes an error sound for me. – Rob Schwenck Dec 22 '17 at 19:57
  • Duh, just noticed you have everything late-bound (`As Object`) - which means *everything* is only ever resolved at run-time. If you can see the members in the Object Browser, then you're referencing the library - and if you're referencing the library, then there's no reason to declare anything `As Object` and to `CreateObject` - just use the types you're referencing, and `New` up your browser instance. – Mathieu Guindon Dec 22 '17 at 20:06

2 Answers2

0

My References in the editor include Microsoft Internet Controls and Microsoft HTML Object Library.

Then you have no need to do this:

Dim IE As Object
Dim objElement As Object
Dim objCollection As Object

Set IE = CreateObject("InternetExplorer.Application")

Declaring everything As Object is a technique called late-binding. In that paradigm you create a new instance of an object by passing a ProgID to the CreateObject function.

Late-bound code is, by definition, resolved at run-time: the compiler is happy with the Object interface, and the onus is on you to use the correct members.

With late-bound code you can't get IntelliSense or auto-complete, because the compiler has no idea what you're up to: all it's seeing is Object.

When you actually reference a type library, you can use early binding, which means the types and member calls are resolved at compile-time instead of run-time. But for this to work, you need to use the types you're referencing. Otherwise you're late-binding against a type library that's referenced... and late-bound code doesn't require a reference (just that some version of the type library is registered on the machine that's running the code).

Dim browser As InternetExplorer
Set browser = New InternetExplorer

browser.Navigate url

'...

Dim dom As HTMLDocument
Set dom = browser.Document

Dim inputElements As HTMLElementCollection
Set inputElements = dom.getElementsByTagName("input")

And now you're coding against an HTML DOM just like you would against any Excel worksheet, with IntelliSense and parameter info and all the goodies.

This is suspicious:

Do While IE.busy
    Application.Wait DateAdd("s", 1, Now)
Loop

That wait-loop isn't even looking at the browser's ReadyState. Try this instead:

Do Until IE.ReadyState = 4 And IE.Busy = False
    DoEvents
Loop

See this post for an allegedly fail-safe way to go about it.

Your code otherwise looks fine though, so my money is on the wait-loop.

Mathieu Guindon
  • 69,817
  • 8
  • 107
  • 235
0

Even though VBA is case-insensitive, all the methods/properties under document are case-sensitive.

A safe way to call them with late-binding is to use CallByName:

Set items = CallByName(IE.document, "getElementsByTagName", VbMethod, "input")
michael
  • 929
  • 6
  • 19