5

Hello StackOverflow community,

I have a question about using Access VBA to manipulate IE.

Essentially, I am trying to write code that will open a specific webpage using IE, search that page for a particular link (the name of the target link will depend on the circumstances of the user), navigate to a new page by programmatically clicking that link, and then repeating the process by looking for a specific link/element on the resulting new page.

The display text for the ultimate target link will always be the same, but the page that it resides on will be different in every case.

My issue is with programmatically searching the second-level page for the elements that reside there...my results keep giving me only elements from the first-level page, even after the browser has loaded the new link.

Apologies if I'm doing a poor job describing the context of the question so far.

My code, essentially, is as follows:

Dim ie As Object, ieDoc As HTMLDocument

Set ie = CreateObject("InternetExplorer.Application")
ie.Visible = True

strHTML = "http://targetsite.com/first-level_page"

ie.navigate strHTML

'wait for browser
While ie.ReadyState <> READYSTATE_COMPLETE
DoEvents
Wend


'define first-level target link and search for it and then "click" it

Dim i As Integer
Dim txt As String, link As String, p As String

Set ieDoc = ie.Document

txt = "First-Level Target"
    Do Until link = txt Or i >= 1000
    i = i + 1
    link = ieDoc.Links(i).outerText
Loop

'I know the above loop is not exactly ideal in its current form, but it does give me a working first attempt at the functionality I'm trying to build.    

ieDoc.Links(i).Click

So far, so good. The code above works just as intended. It navigates correctly to the desired second-level page in all cases. Where I'm going wrong is when I try to search that second-level page for the final target element:

'wait for browser
While ie.ReadyState <> READYSTATE_COMPLETE
DoEvents
Wend

'Search for final target element (which always has the same name and anchor text on all second-level pages)
ieDoc.getElementsByName("final-target-name").Item.Click

The line above (based on .getElementsByName) works just fine if I try to use it on the first-level page. But it does nothing once I've navigated to any second-level page. I've also tried to replace it with a modified version of the loop above that searches for the link on the first-level page. Same result.

As a troubleshooting step, I've also replaced that line with a debug.print command to simply name all of the elements on the second-level page, and this always returns the element names from the first page instead.

I assume it's clear that I'm somehow failing to correctly update or redefine my HTMLdocument after I've followed the first link. I've setting ieDoc as nothing and then re-setting it as ie.document, but that doesn't work either.

Hopefully there is a simple command or syntax that I'm simply ignorant to. But for the life of me I havent been able to have VBA correctly refer to the HTML elements existing on the page after the first link is clicked.

Thanks in advance for any advice!

~JQN

John Q. Noob
  • 181
  • 1
  • 2
  • 18
  • 1
    Without testing, I might suggest to see if your `getElementsByName("target")` is getting more than one link, where maybe the first one is not active. Rather than accessing the element with `.Item`, add an index and try with `(1)` (which would access the second element got, i.e. the second level of your page). – Matteo NNZ Apr 15 '15 at 21:55
  • 1
    where is the code placed? I suppose its in the 2nd level page? – securecodeninja Apr 15 '15 at 21:55
  • 1
    After the navigation event you still have the same `ieDoc` reference, which points to a page which is no longer loaded. You need to refresh that reference `Set ieDoc = ie.Document` after any navigation is complete. – Tim Williams Apr 15 '15 at 23:40
  • @TimWilliams I apologize, I had a bit of a language failure in my second to last paragraph of the OP :) ...but I've tried re-setting ie.doc = ie.document, after the navigation, but without success. I've also tried doing so with and without the (I would assume completely superfluous) additional step of setting ieDoc = nothing after the navigation but before the re-set of ieDoc = ie.document. I'm getting the exact same beahvior in all cases. – John Q. Noob Apr 16 '15 at 12:53
  • @Roman I've got all of this code running in the "OnClick" event of a button in one of my Access forms. – John Q. Noob Apr 16 '15 at 12:56
  • @MatteoNNZ I've tried playing around with having getElementsByName reference multiple different indices (I've looped the index from 0 through 1000, which is >> total number of elements on the page), and am getting the same behavior as above. I've also used the debugger to capture the names of all the elements the code can see on (what should have been) the second-level page, and the second-level elements are missing entirely from that list. It doesn't look like this is a case of trying to point to the wrong index in a set with multiple items. It's like my code isnt seeing the 2nd page at all. – John Q. Noob Apr 16 '15 at 13:03
  • Thanks to all of you for taking the trouble to respond. I should also apologize, because I realize I've left information out of the OP that might have been helpful. I should have mentioned the following: When I take the exact same code that works as expected on the 1st-level page, and I try to duplicate it after the navigation to the 2nd-level page (eg the $ link = ieDoc.Links(i).outerText loop), I am getting run-time error 91 "Object variable or With block variable not set", although I am at a loss as to what is causing this. – John Q. Noob Apr 16 '15 at 13:13
  • Apologies yet again...I think I've found the source of runtime error 91, and it doesn't look like it has anything to do with the root issue. It's an artifact of my previously-mentioned poorly-designed loop. – John Q. Noob Apr 16 '15 at 13:33
  • ...On the first page, the loop has an exit condition ("Until link = txt") that is preventing i from attaining a value in excess of the total number of links on the page (hence the runtime error is never being triggered). The same exit condition is present in the code when I try to re-run the same loop on the second-level page, but since I'm not able to get my code to see the elements on the second page, that exit condition is never being met. As a result, the loop index is running past the total number of links on the page. Hence the runtime error. – John Q. Noob Apr 16 '15 at 13:33
  • I believe that this should probably close this topic for now...It's starting to become clear to me that my issues are all stemming from my lack of familiarity and understanding of the code that is driving the 1st-level webpage. I think the issue is that the links on that page are not actually bringing up a new document, they are simply redefining certain parameters that dictate how the page is displayed. So the 2nd-level page does not actually exist as a distinct HTML document--if that makes sense. – John Q. Noob Apr 16 '15 at 14:24
  • I also now realize that my ReadyState/DoEvents loop is not doing exactly what I thought it was after the navigation. It seems that by calling the first link in the manner that I am doing here, the ie readystate will always be equal to 1 and not 4. Not really a primary point of my issue, but more of a symptom that lets me know I dont understand enough about the objects I am trying to work with here! – John Q. Noob Apr 16 '15 at 14:26
  • I think I've got a bigger set of questions to solve than what I could politely rely on the SO community for help with at this time. :) Thanks again to all of you who took the trouble to comment! – John Q. Noob Apr 16 '15 at 14:26
  • Problem solved! As expected, my issue was with a general lack of understanding of the code driving the website. All is now well. Thanks again! – John Q. Noob Apr 20 '15 at 20:39

2 Answers2

2

You need to use a combination of @Matteo NNZ and @TimWilliams

If you know the "id" name of the element its easier to use getElementsByName("target").

if you don't know the "id" then loop anchor elements and search for the correct text. This narrows down to only Link or elements.

Set Anchors = IeDoc.getElementsByTagName("a")

then loop comparing .outertext or whatever sub field you need.

@TimWilliams: You need to load the found URL then set the newly loaded IeDoc inside the loop. Set the "ie" object to the new "ie" loaded page otherwise the 'ie' object will correctly remain the first page loaded. When you find your link you need to load the new page as you have already done.

'' throw away the first page loaded.
ie = nothing 
IeDoc = nothing

'' Set the new page loaded.
ie.navigate newHTML

'wait for browser
While ie.ReadyState <> READYSTATE_COMPLETE
DoEvents
Wend

Set IeDoc = ie.Document

Repeat the process as above for the second page

Here are some other resources about 'parsing HTML in vba': http://www.ozgrid.com/forum/showthread.php?t=184695 Parse HTML content in VBA

Community
  • 1
  • 1
durbo
  • 556
  • 4
  • 11
0

In this particular case, I was able to resolve the issue on the HTML side of things, although I think in general the answers posted by @Matteo NNZ , @TimWilliams , and @durbo would do the trick for just the Access/VBA side of the problem. Thanks again to all who took the time to respond!

John Q. Noob
  • 181
  • 1
  • 2
  • 18
  • 2
    John, this is not an answer to your question. Help the community by providing a proper answer about how your resolved your problem. Its about helping the people that come after you resolving similar issues. – durbo Jun 27 '15 at 02:41