Web automation IFrame trouble - vba

I'm currently working as a temp in the HR department of a major hospital. In order to convince the powers that be of the need to upgrade from the "trial version" to the "salary + benefits" subscription model of my employment contract I've decided to take on a bit of a project.
The excel spreadsheet will log into a vendor website and download a report with a list of employees currently out on sick leave, then it will log into the website of our insurance company and pull information on STD claims for use by payroll (this is currently done manually by a 70 yr old lady who types at 30 WPM..... and no, she does not even use basic copy and paste).
Everything works just fine up until the point where I click the button to download the report. I'm having trouble figuring out the syntax to download the spreadsheet. Switching to chrome and using Selenium isn't an option, due to our IT departments blinding levels of bureaucracy.
Here is the code I have so far. Office 16.0 office library, HTML object library, and microsoft internet controls are included in references.
Module 1
Option Private Module
Public Function OpenReport(doc As HTMLDocument) As Long
On Error GoTo Failed
doc.getElementsByClassName("k-button k-button-icontext k-grid-view")(3).Click
OpenReport = 1
Done:
Exit Function
Failed:
OpenReport = 0
End Function
Module 2
Dim IE As Object
Dim doc As HTMLDocument
Dim i As Long
Dim rWin As HTMLDivElement
Set IE = CreateObject("InternetExplorer.application")
IE.Visible = True
IE.navigate "https://leavexpert.com/"
Do While IE.Busy
Application.Wait DateAdd("s", 1, Now)
Loop
Set doc = IE.document
'inputs a username and password then clicks the login button
doc.getElementById("UserName").Value = "*****"
doc.getElementById("Password").Value = "*****"
doc.getElementsByClassName("validateAndSubmit k-button")(0).Click
Do While IE.Busy
Application.Wait DateAdd("s", 1, Now)
Loop
'having the program wait while IE.busy does not seem to work, so wrapping the button click in it's
'own function and using error handling to return a 1 or 0 on success or failure is my creative work
'around
IE.navigate "https://leavexpert.com/Reports"
i = 0
Do While i = 0
i = OpenReport(doc)
Application.Wait DateAdd("s", 1, Now)
Loop
Set rWin = doc.getElementsByClassName("k-widget k-window")(0)
'this gives me some output which tells me im on the right track.
Debug.Print rWin.className
Debug.Print rWin.innerHTML
Debug output
k-widget k-window k-state-focused
<div class="k-window-titlebar k-header" style="margin-top: -27px;"> <span class="k-window-title"
id="reportWindow_wnd_title">Case Detail</span><div class="k-window-actions"><a class="k-window-action
k-link" role="button" href="#"><span class="k-icon k-i-maximize" role="presentation">Maximize</span>
</a><a class="k-window-action k-link" role="button" href="#"><span class="k-icon k-i-close"
role="presentation">Close</span></a></div></div><div tabindex="0" class="k-window-content k-content
k-window-iframecontent" id="reportWindow" role="dialog" aria-labelledby="reportWindow_wnd_title"
data-role="window"><div class="k-loading-mask" style="left: 0px; top: 0px; width: 100%; height:
100%;"><span class="k-loading-text">Loading...</span><div class="k-loading-image"></div><div
class="k-loading-color"></div></div><iframe title="Case Detail" class="k-content-frame"
src="/Areas/Reports/ReportViewer.aspx?reportId=1005" frameborder="0">This page requires frames in
order to show content</iframe></div><div class="k-resiz
e-handle k-resize-n"></div><div class="k-resize-handle k-resize-e"></div><div class="k-resize-handle
k-resize-s"></div><div class="k-resize-handle k-resize-w"></div><div class="k-resize-handle k-resize-
se"></div><div class="k-resize-handle k-resize-sw"></div><div class="k-resize-handle k-resize-ne">
</div><div class="k-resize-handle k-resize-nw"></div>
A screenshot of the HTML of the element i need to click to download.
screenshot
UPDATE: Slow day, so I've got downtime to do some testing.
Here is some updated code at the end of my sub
Do While i = 0
i = OpenReport(doc)
Application.Wait DateAdd("s", 1, Now)
Loop
Set doc = IE.document
'New stuff starts here, I'll move the declarations once I have it
'working.
Application.Wait DateAdd("s", 30, Now)
Set doc = IE.document
Dim rWin As HTMLDivElement
Set rWin = doc.getElementsByClassName("k-widget k-window")(0)
For i = 0 To 11
Debug.Print rWin.getElementsByTagName("div")(i).innerText
Next
End Sub
New debug output.
Case Detail
MaximizeClose
MaximizeClose
This page requires frames in order to show content
Iframe screenshot

IT WORKS!!!!! IT WORKS!!!!! IT WORKS!!!! I had to set IE to always allow popups from this website, but after that......... IT WORKED!!!!!!!!!!!! Now to figure out how to handle the open/save box.
'standard declarations
Dim IE As Object
Dim doc As HTMLDocument
Dim i As Long
Dim iWin As HTMLIFrame
Set IE = CreateObject("InternetExplorer.application")
IE.Visible = True
IE.navigate "https://leavexpert.com/"
Do While IE.Busy
Application.Wait DateAdd("s", 1, Now)
Loop
Set doc = IE.document
'This part puts in the login details and clicks the login button
doc.getElementById("UserName").Value = "*******"
doc.getElementById("Password").Value = "*******"
doc.getElementsByClassName("validateAndSubmit k-button")(0).Click
'wait for the website to finish loading
Do While IE.Busy
Application.Wait DateAdd("s", 1, Now)
Loop
'Go to the report section of the website
IE.navigate "https://leavexpert.com/Reports"
Set doc = IE.document
'Having the program wait while IE.busy does not seem to work, so wrapping the button click in it's own function
'and using error handling to return a 1 or 0 on success or failure is my creative work around
i = 0
Do While i = 0
i = OpenReport(doc)
Application.Wait DateAdd("s", 1, Now)
Loop
'Not quite sure if i need to set the doc variable here or not. I read somewhere that you need to do it every time you change webpages.
'Don't know if opening a child window counts, but better safe than sorry.
Set doc = IE.document
'Set the iWin object to the report window.
Set iWin = doc.getElementsByClassName("k-content-frame")(0)
'Wait for the report to finish loading. I know the program is looking at the correct object, because the debug printouts match when the window
'finishes loading.
Do While iWin.readyState <> "complete"
Application.Wait DateAdd("s", 1, Now)
Loop
Application.Wait DateAdd("s", 1, Now)
'This is the line that clicks the button!!!!!
iWin.contentDocument.querySelector("a[title=Excel][onclick*=EXCELOPENXML]").Click

Related

VBA - Logging into Website - Login Button

Good afternoon all,
Please forgive me, I am new to VBA and have been practicing within my workbooks but for my work would be highly useful to branch out to Webscraping.
The following is my code.
Sub pullsalesdatafromonline()
Dim IE As Object
Dim doc As HTMLDocument
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
IE.navigate "https://www.peoplestuffuk.com/WFMMCDPRD/Login.jsp"
Do While IE.Busy Or IE.readyState <> 4
Application.Wait DateAdd("s", 1, Now)
Loop
Set doc = IE.document
doc.getElementById("txtUserID").Click
doc.getElementById("txtUserID").Value = Usernameinserted
doc.getElementById("txtPassword").Click
doc.getElementById("txtPassword").Value = PasswordInserted
doc.getElementById("Login").Click
IE.navigate "https://www.peoplestuffuk.com/WFMMCDPRD/LoginSubmit.jsp"
IE.navigate "https://www.peoplestuffuk.com/WFMMCDPRD/ModuleSelection.jsp"
IE.navigate "https://www.peoplestuffuk.com/WFMMCDPRD/dashboard/main/dashboardmain.jsp"
IE.navigate "https://www.peoplestuffuk.com/WFMMCDPRD/rrd/matrixReport.jsp?fromPM=N"
End Sub
Here is the element that I am trying to scrape from;
<INPUT onclick=javaScript:submitForm() class=button-t type=button value=Login>
<SPAN id=Login_span class=buttonbox></SPAN>
I've looked at several other links that have looked into firing the .onclick event but, can't quite seem to figure it out.
The error in VBA highlights the:
IE.navigate "https://www.peoplestuffuk.com/WFMMCDPRD/ModuleSelection.jsp"
line. When my username and password enter, the page refreshes/ tries to exectute and then empties the Login and password info and leaves me on the Login page.
Would greatly appreciate someone's input.
Thank you
If you had a demo username and password to share then there was an efficient way of logging in using xhr. However, as for your current attempt concern, they are not the ids you used them within .getElementById(). Given that the following approach should log you in. Make sure to uncomment the delay, if the script fails to do the doing.
Sub pullsalesdatafromonline()
Dim IE As Object, doc As HTMLDocument
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
IE.navigate "https://www.peoplestuffuk.com/WFMMCDPRD/Login.jsp"
While IE.Busy Or IE.readyState < 4: DoEvents: Wend
Application.Wait Now + TimeValue("00:00:03")
Set doc = IE.document
doc.querySelector("[name='txtUserID']").innerText = "username"
doc.querySelector("[name='txtPassword']").innerText = "password"
' Application.Wait Now + TimeValue("00:00:03")
doc.querySelector("input[value='Login']").Click
End Sub

How do I get around breaking InternetExplorer Object with Application.SendKeys

I thought I was well on my way to success. What I'm attempting to do is Load a URL in IE, input some data, then run a report.
To accomplish this, I've created an InternetExplorer object, used that object to turn on visibility, and navigate to my URL.
Upon getting to the page, I have to supply some data to let the report generator do what it needs to do, then press enter. Once I'm to this point I need to do some navigation to different URLs until I arrive at the report page. To accomplish this, I'm attempting to return to using my InternetExplore object (IE) to navigate, but any time I use IE.anything the 462 error pops.
My question is two fold:
The object was good to begin with, I have to assume it was the use of Application.Send or Application.Wait that has somehow broke my object, why?
What did I do wrong?
Suggestions on how to resolve this?
Dim text As String
Dim IE
Set IE = CreateObject("InternetExplorer.Application")
'
IE.Visible = True
IE.Navigate "http://~~~~~~~~~.net/reports/views/result/reportResult.faces"
'
text = "somedata"
.
Application.Wait (Now + TimeValue("00:00:02"))
Application.SendKeys (text), True
'
Application.Wait (Now + TimeValue("00:00:02"))
Application.SendKeys vbCrLf, True
'
Application.Wait (Now + TimeValue("00:00:02"))
IE.Navigate "http://~~~~~~~~~.net/reports/views/myMrs/myFavorites.faces"
The end product was completely different than where I was headed. Thanks to those who provided input, especially Sorceri who turned me on to focusing on the elements.
Below is the finished code segment (I have more things I do after this but this gets me where I needed to go).
Private Sub OpenReport()
Dim text As String
Dim x As Integer
Dim IE
Set IE = New InternetExplorerMedium
text = "somecode"
'Load link
IE.Visible = True
IE.Navigate "http://~~~~~~~~~/reports/views/result/reportResult.faces"
'Wait for page to load
Do While IE.Busy Or IE.ReadyState <> 4
DoEvents
Loop
'fill in the pcode
IE.Document.getelementbyid("code").Value = text
'Click Submit
IE.Document.getElementsByClassName("btn btn-lg btn-primary btn-block")(0).Click
'Wait for page to load
Do While IE.Busy Or IE.ReadyState <> 4
DoEvents
Loop
'Click on Favorites
IE.Document.getElementsByClassName("myMRSFavoritesLink")(0).Click
'Wait for page to load
Do While IE.Busy Or IE.ReadyState <> 4
DoEvents
Loop
'Click on report
IE.Document.getElementsByName("myFavoritesForm:treeTable_tableId:1:infoButton101644806j_id__v_19")(0).Click
'Wait for page to load
Do While IE.Busy Or IE.ReadyState <> 4
DoEvents
Loop
Click on execute report
IE.Document.getElementsByName("setParametersForm:startReportButton")(0).Click
End Sub

Error on search, With automation error

I've got a bit of code know that works with pulling information from a cell and paste it into a search engine to search. Which works fine as a tested on both google and bing pulls back what I want to search.
Now I've changed the code which I think is correct to an internal website but now get and run-time error and automation error. It will load the site fine, Just not search through it.
I'm no expert at this so still trying to learn VBA. Also if you can advise any pointers on the best way to troubleshoot things likes.
As at the moment, the only way I figure it out is to break each line see what it does and find the fault. But this is a bit beyond me.
The only thing I think it could be but might be wrong is missing a reference
I've got the HTML Object library and Internet controls.
Run time error
This is the code from the site for the search box.
<input class="genInput" type="text" size="32" name="xx_quicksearch" value="" id="quicksearchbox">
This is my code,
Sub Test()
Dim ie As Object
Dim form As Variant
Dim button As Variant
Dim LR As Integer
Dim var As String
LR = Cells(Rows.Count, 1).End(xlUp).Row
For x = 2 To LR
var = Cells(x, 1).Value
Set ie = CreateObject("internetexplorer.application")
ie.Visible = True
With ie
.Visible = True
.navigate "*******"
While Not .readyState = READYSTATE_COMPLETE
Wend
End With
'Wait some to time for loading the page
While ie.Busy
DoEvents
Wend
Application.Wait (Now + TimeValue("0:00:02"))
ie.document.getElementById("quicksearch").Value = var
'code to click the button
Set form = ie.document.getElementsByTagName("form")
Application.Wait (Now + TimeValue("0:00:02"))
Set button = form(0).onsubmit
form(0).submit
'wait for page to load
While ie.Busy
DoEvents
Wend
Next x
End Sub
The id is different from what you posted. In: ie.document.getElementById("quicksearch").Value = var try typing "quicksearchbox" rather than just "quicksearch"

How to pause Excel VBA and wait for user interaction before loop

I have a VERY basic script I am using with an excel spreadsheet to populate a form. It inserts data into the fields then waits for me to click the submit button on each page. Then it waits for the page to load and fills in the next set of fields. I click submit, next page loads, etc. Finally, on the last two pages I have to do some manual input that I can't do with the spreadsheet. Code thus far is shown below.
My question is, at the end of what I have there now, how can I make the system wait for me to fill out that last page, then once I submit it realize that it has been submitted and loop back to the beginning, incrementing the row on the spreadsheet so that we can start over and do the whole thing again for the next student?
As you will probably be able to tell I am not a programmer, just a music teacher who does not savor the idea of filling out these forms manually for all 200 of my students and got the majority of the code you see from a tutorial.
Function FillInternetForm()
Dim IE As Object
Set IE = CreateObject("InternetExplorer.Application")
'create new instance of IE. use reference to return current open IE if
'you want to use open IE window. Easiest way I know of is via title bar.
IE.Navigate "https://account.makemusic.com/Account/Create/?ReturnUrl=/OpenId/VerifyGradebookRequest"
'go to web page listed inside quotes
IE.Visible = True
While IE.busy
DoEvents 'wait until IE is done loading page.
Wend
IE.Document.All("BirthMonth").Value = "1"
IE.Document.All("BirthYear").Value = "2000"
IE.Document.All("Email").Value = ThisWorkbook.Sheets("queryRNstudents").Range("f2")
IE.Document.All("Password").Value = ThisWorkbook.Sheets("queryRNstudents").Range("e2")
IE.Document.All("PasswordConfirm").Value = ThisWorkbook.Sheets("queryRNstudents").Range("e2")
IE.Document.All("Country").Value = "USA"
IE.Document.All("responseButtonsDiv").Click
newHour = Hour(Now())
newMinute = Minute(Now())
newSecond = Second(Now()) + 3
waitTime = TimeSerial(newHour, newMinute, newSecond)
Application.Wait waitTime
IE.Document.All("FirstName").Value = ThisWorkbook.Sheets("queryRNstudents").Range("a2")
IE.Document.All("LastName").Value = ThisWorkbook.Sheets("queryRNstudents").Range("b2")
IE.Document.All("Address1").Value = "123 Nowhere St"
IE.Document.All("City").Value = "Des Moines"
IE.Document.All("StateProvince").Value = "IA"
IE.Document.All("ZipPostalCode").Value = "50318"
End Function
I would use the events of the IE, more specifically the form, something like this, using MSHTML Controls library.
Private WithEvents IEForm As MSHTML.HTMLFormElement
Public Sub InternetExplorerTest()
Dim ie As SHDocVw.InternetExplorer
Dim doc As MSHTML.HTMLDocument
Set ie = New SHDocVw.InternetExplorer
ie.Visible = 1
ie.navigate "http://stackoverflow.com/questions/tagged/vba"
While ie.readyState <> READYSTATE_COMPLETE Or ie.Busy
DoEvents
Wend
Set doc = ie.document
Set IEForm = doc.forms(0)
End Sub
Private Function IEForm_onsubmit() As Boolean
MsgBox "Form Submitted"
End Function

IE page doesn't update - VBA

As far as I can see, there's nothing wrong with this code. Indeed, on one of my computers it works just fine, but on two others, it doesn't! All three run Excel 2003 on different versions of windows (7, 8.1 and 10).
What it is supposed to do is activate a search, then load the results page and print the innerHTML of the results page. One one machine (win 8.1) it does just that. On the other two, it prints the innerHTML of the search page.
Do I just have to abandon my trusty Excel 2003? Or is it a problem with my windows install? The W10 machine is a clean install of W10.
I am at my wits end over this! so please help me. :)
'This uses early binding
'In menu at top of page - Tools...Reference.... Microsoft Internet Controls and Microsoft HTML Object Library must both be ticked
Sub main()
sUrl = "https://www.insolvencydirect.bis.gov.uk/FIP1/"
Dim IE As InternetExplorer
Dim doc, element
Set IE = New InternetExplorer
IE.Visible = True
For iii = Asc("A") To Asc("B") ' *** test use B *** Do A-Z
aaa = Chr(iii)
IE.navigate sUrl
Do
DoEvents
Loop Until IE.readyState = READYSTATE_COMPLETE
Set doc = IE.document
doc.getElementById("IPSurname").Value = aaa
doc.forms.Item(0).elements(7).Click
'loading new page with data
Do While IE.Busy Or IE.readyState <> 4
DoEvents
Loop
Set doc = IE.document
MyBit = doc.body.innerHTML
Debug.Print MyBit
Next
End Sub
choose some element tag from the page and do that :
.
.
IE.navigate sUrl
Do
DoEvents
Loop Until IE.readyState = READYSTATE_COMPLETE
Set doc = IE.document
Do While True
If ie.document.getElementsByTagName("element tag").Length > 0 Then
Exit Do
End If
Application.Wait DateAdd("s", 1, Now)
Loop
.
.
.