A colleague sent me a VBA script that runs within Microsoft Excel that, from my perspective (as someone who has never written VBA code before), appears to do a few relatively simple things:
Open up Internet Explorer, and navigate to a specific page
Fill out a few HTML form elements in that page using cells from the Excel Spreadsheet
Fire off a Javascript routine to popup a new window
Fill out a few fields on that popup window
Submit the form on the popup window
This is the code they wrote that's supposed to do that:
Dim IE As Object
Set IE = CreateObject("InternetExplorer.Application")
IE.Navigate "https://myurl.com/mylandingpage"
IE.Visible = True
Application.Wait (Now + TimeValue("0:00:20"))
IE.Document.All("name").Value = ThisWorkbook.Sheets("sheet1").Range("t2")
IE.Document.All("address").Value = ThisWorkbook.Sheets("sheet1").Range("w2")
IE.Document.All("phone_number").Value = ThisWorkbook.Sheets("sheet1").Range("x2")
IE.Navigate "javascript:helpModLvl('/mylandingpage/popup_window','pop_up_form')"
Ret = FindWindow(vbNullString, "pop_up_form")
Application.Wait (Now + TimeValue("0:00:10"))
IE.Document.All("id").Value = ThisWorkbook.Sheets("sheet1").Range("H2")
IE.Document.All("new_address").Value = ThisWorkbook.Sheets("sheet1").Range("I2")
IE.Document.All("submit").Click
Application.Wait (Now + TimeValue("0:00:05"))
End Sub
For the sake of argument, assume that the landing page does have fields named name, address, and phone_number, and that the popup window has fields id, new_address, and submit, the latter of which is a proper button.
My concern is that even though they query for the popup window, they never actually use it (note that Ret is never used again after it gets assigned, and as a result, the later calls to set values for id, and so on, never actually manifest, because they're still iterating on the original webpage.
Is my understanding of this code correct? Should calls after the popup window is created be based on the handle Ret, or should I expect the code to be correct as-is?
Related
This is first time I am trying to extract an excel report from a webpage. Sequence of how my code should work is as under:
Initial URL - brings home page of the website (userid and password saved in browser to autologin) - image1
Click on "Reports"
New page appears (image2)
select from dropdown_module.
Select appropriate from dropdown_reports.
selection in dropdown_reports creates a new dropdown_project.
select from dropdown_project
click on drownload reports (image3)
give path for downloading.
image41
image12
image23
image34
I am able to reach upto point 3, but not able to proceed ahead.
On using inspect element on dropdown_module i get the code (image4)
My using so far is as under:
Set IE = CreateObject("InternetExplorer.Application")
URL = Range("hr_url").Value
IE.Visible = True
IE.navigate URL
Application.StatusBar = " is loading. Please wait..."
Do While IE.readyState = 4: DoEvents: Loop
Do Until IE.readyState = 4: DoEvents: Loop
Application.StatusBar = " Loaded"
Set doc = IE.document
For Each element In doc.all
If InStr(element.ID, "08191") > 0 Then
If InStr(element.ID, "AppPress:12") Then
element.Focus
element.Click
End If
End If
Next element
Application.Wait (5)
Do
DoEvents
Loop Until IE.readyState <> 4
Set doc = IE.document
For Each element In doc.all
If InStr(element.ID, "0261") > 0 Then
If InStr(element.ID, "AppPress:6") Then
MsgBox "element is found"
element.Options(0).Selected = True
End If
End If
Next element
The code isnt able to find the dropdown element and select the 0 index required. Can anyone suggest what is wrong here?
I was not aware that scraping was posible with VBA. (Scraping is the way the technique of extracting info from the web with software is called)
You should find this question useful:
Scraping data from website using vba
I am not aware of the posibilities off doing this with VBA that might be limited to internet explorer among other limitations. The little things I've done for that have been with python and a library called beautifulSoup, that is amazing!
https://www.crummy.com/software/BeautifulSoup/bs4/doc/
If you feel curious enough you might want to dive into it, as it is quite simple, and googling what you want to do might take you very far, also if you want to create an excel file with the info you extract.
Hope that helps
I am trying to automate the pulling of a report from a client portal.
Figured out how to juggle instances if IE, how to navigate through Iframes. Few other hurdles.
I am down to 1 button that I cannot click without using sendkeys to tab all the way up the page.
The (lightly sanatized) HTML for the element im trying to hit is:
<span class="logoff_container" id="logoff">
<span tabindex="0" title="Log off" class="logofflink logofflinkNormal" id="buttonlogoff" onmouseover="logofflink._handlers.onlogofflinkMouseHover('buttonlogoff');" onmouseout="logofflink._handlers.onlogofflinkOut('buttonlogoff');" onmousedown="logofflink._handlers.onlogofflinkMouseDown('buttonlogoff');" onfocus="logofflink._handlers.onlogofflinkMouseHover('buttonlogoff');" onblur="logofflink._handlers.onlogofflinkOut('buttonlogoff');">
<span class="button_inner">Log off</span></span></span>
Using this sendkeys logic, I can successfully make the logoff dialogue box open:
''Logout
For i = 1 To 32
Application.SendKeys "+{Tab}"
Application.Wait (Now + TimeValue("0:00:01") * 0.55)
Next i
Application.Wait (Now + TimeValue("0:00:03"))
Application.SendKeys "~"
I want to be able to make the logout dialogue box appear with this:
IE.document.getElementByID("buttonlogoff").Click
As a go between, I have tried this, and it does not work (the element focuses. The class of the element changes. The logout window does not open).:
Set LogOffButton = IE.document.getElementById("buttonlogoff")
LogOffButton.Focus
Application.SendKeys "~"
I have poked and prodded ad nauseum. I can say with 100% certainty that getElementByID is successfully getting the HTML Span element. I've tried every sequence of .FireEvent prior to the click. I've tried grabbing the HTML table cell element that these elements reside within and clicking that.
I for the life of me cannot figure out why a both right and left clicks with a mouse opens the window, keyboard tabbing and hitting enter opens the window, application.sendkeys and waiting for a minute (almost always) works, but .focus > SendKeys and .click on the element don't open the window.
Any chance for some guidance on how to crack this puzzle?
The button has no click event, it has an onmousedown event. You can try to trigger this with the following line of code (set the right string for browser.document):
Call TriggerEvent(browser.document, LogOffButton, "onmousedown")
And this procedure:
Private Sub TriggerEvent(htmlDocument As Object, htmlElementWithEvent As Object, eventType As String)
Dim theEvent As Object
htmlElementWithEvent.Focus
Set theEvent = htmlDocument.createEvent("HTMLEvents")
theEvent.initEvent eventType, True, False
htmlElementWithEvent.dispatchEvent theEvent
End Sub
I need a code that loops through options in a < select > object on a web page, selects each option and clicks "Show" button to show some data related to the selected option. I started with this code:
Set periodSelector = ie.document.getElementById("period")
For Each Period In periodSelector.Options
Period.Selected = True
Application.Wait (Now + TimeValue(waittime))
Next Period
It works well - the browser selects each option just fine. But when I add button.click to show the data related to the selected option, an error "Permission denied" occurs on the second selector loop (seems like it cannot use .select command anymore).
Set periodSelector = ie.document.getElementById("period")
For Each Period In periodSelector.Options
Period.Selected = True
Application.Wait (Now + TimeValue(waittime))
ie.document.getElementsByTagName("input")(17).Click
Application.Wait (Now + TimeValue(waittime))
Next Period
I guess it is due to same origin policy. Probably, when I click on the "Show" button, the page gets refreshed (although it is not really reloaded - the button uses scripts to retrieve some information and show it in a table below the button).
How can I avoid this same origin policy issue and loop through the dropdown options?
In cases like this I try a slightly different approach which is to work off the page and not a variable. You can get your number of options from an initial variable, but after that keep working off the current document which may have refreshed. Amongst other things, you want to avoid underlying stale element exceptions.
Dim periodSelector As Object, i As Long, optionsLength As Long
Set periodSelector = ie.document.querySelectorAll("#period option")
optionsLength = periodSelector.Length -1
For i = 0 to optionsLength
ie.document.querySelectorAll("#period option").item(i).Selected = True
Application.Wait Now + TimeValue(waittime)
ie.document.getElementsByTagName("input")(17).Click
Application.Wait Now + TimeValue(waittime) '<== this I would replace with proper page load wait While ie.Busy Or ie.readyState < 4: DoEvents: Wend
Next
Good Morning,
I’m hoping that some kind soul out there can help me with a roadblock I’ve encountered in my quest to manipulate a website with VBA. I am using MS Excel 2010 and Internet Explorer 11.0.56.
I’m somewhat comfortable with VBA but have never used it to navigate to a website, enter information and click on buttons. I’ve managed to muddle through as follows:
In Column A of my Excel spreadsheet, I have a list of 10 digit case numbers.
The code below will open IE, navigate to the desired website, pause while I log in, then navigate to the search screen, enter in the first case number and press the SEARCH button (yes, I have the case number in this example hard coded in with no looping, but that stuff I can handle so please ignore):
Sub Button_Click()
Dim objIE As Object
Set objIE = New InternetExplorerMedium
objIE.Top = 0
objIE.Left = 0
objIE.Width = 800
objIE.Height = 600
objIE.AddressBar = 0
objIE.StatusBar = 0
objIE.Toolbar = 0
objIE.Visible = True
objIE.Navigate ("https://somewebsite.com")
MsgBox ("Please log in and then press OK")
objIE.Navigate ("https://somewebsite.com/docs")
Do
DoEvents
Loop Until objIE.ReadyState = 4
objIE.Document.all("caseNumber").Value = "1234567890"
objIE.Document.getElementById("SearchButton").Click
Exit Sub
Do
DoEvents
Loop Until objIE.ReadyState = 4
MsgBox ("Done")
End Sub
That will bring me to this screen
The file number entered in the search field will return any number of files in a dynamic table with a checkbox to the left of each file.
For this example, let’s say I am ONLY concerned with the file called “CC8” under the “Type” column. There will only ever be one instance of “CC8” for a given file number.
What I need help with is, through VBA, how do I search through this table, find the “CC8” line, and then have the checkbox to the left automatically checked?
When I inspect the “CC8” element in IE, this is the HTML associated with it (highlighted in gray; the entire table is under class “listing list-view clearfix”)
see here
The HTML for the checkbox related to the “CC8” item is below:
HTML code here
The “id” for both has the same sequence of numbers, but one starts with “viewPages” and the other “doc”.
Can anyone help me out as to what I need to add to my code to get this checkbox checked? Thank you!
Note:
Please post the actual HTML using the snippet tool.
Generally:
Without HTML to properly test, I am assuming that the following 2 nodeLists are the same length, meaning that when the search text is found in aNodeList then the assumption is the same index can be used to target the corresponding checkbox in the bNodeList:
Dim aNodeList As Object, i As Long
With objIE.document
Set aNodeList = .querySelectorAll("a[target='_blank']")
Set bNodeList = .querySelectorAll("[title='Search Result: Checkbox']")
End With
For i = 0 To aNodeList.Length - 1
If aNodeList.item(i).innerText = "CC8" Then
bNodeList.item(i).Click
Exit For
End If
Next
You could also potentially use the following instead as you say the viewPages prefixes each item:
Set aNodeList = .querySelectorAll("a[id^='viewPages']")
Other observations:
Traditional checkboxes would have a checked attribute and syntax of
bNodeList.item(i).Checked = True, but as I can't see that attribute in your element I am assuming a .Click suffices.
I'm writing VBA code in Excel to generate various reports.
Once it's done I would really like (and I would be looked at like a hero by my fellow co-worker) to input my results directly on our corporate intranet.
So I've started educating myself on how to use VBA to interact with Internet Explorer. I know get the basics so I can do cool stuff (but unusefull in this case ) like loading a web site. But when I try to input values in a text box on this page on the Intranet, I can't go any where.
I'm suspecting that the problem is caused by the fact that the adress I'm accessing is ending with .asp extension.
Here's the code I'm using below
Beware that I will most probably have other questions following this first one. You might just become my new-web-geek-bestfrient ;-)
Sub interaction()
'Variables declaration
Dim IE As New InternetExplorer
Dim IEDoc As HTMLDocument
Dim ZoneMotsClés As HTMLInputElement
'page to be loaded, it's on a corporate intranet
IE.navigate "http://intranet.cima.ca/fr/application/paq/projets/index.asp"
IE.Visible = True
Do ' Wait till the Browser is loaded
Loop Until IE.readyState = READYSTATE_COMPLETE
Set IEDoc = IE.document
'this is the text zone that I'm trying to input value into
Set ZoneMotsClés = IEDoc.getElementById("txtMotCle")
'this is where it crashes. At this point I'm only trying to enter a project number into
'the "txtMotCle" 'text zone
ZoneMotsClés.Value = "Q141763B"
'.....
Set IE = Nothing
Set IEDoc = Nothing
End Sub
So at this point (when I try to input the value in the text box I get a:
error 91 object variable or with block variable not set
and here's the html code of the section on the page I'm trying to write in.
<INPUT onfocus="javascript:document.frmMyForm.TypeRecherche.value='simple';"
style="FONT-SIZE: 9px; FONT-FAMILY: verdana" maxLength=250 size=60 name=txtMotCle>
This time I tried the suggestions of the 2 contributors (Tx Jeeped and Tim Williams) but still getting the same error 91.
Now I tried that modification (tx SeardAndResQ)
'this is the text zone that I'm trying to input into
'Set ZoneMotsClés = IEDoc.all("txtMotCle")
ID = "txtMotCle"
Set ZoneMotsClés = IEDoc.getElementById(ID)
'this is where it crashes. At this point I'm only trying to enter a project number into the "txtMotCle"
'text zone
ZoneMotsClés.Value = "Q141763B"
Same result. I'm not sure I made it the way #searchAndResQ meant it