I am trying to download a spreadsheet, whose name changes each time the temporary is loaded when accessed, without dealing with IE save prompt. The intranet site routes through a portal, which requires windows authentication to log in, before taking me to my destination. What I have pieced together so far gets me through the windows authentication, enters the appropriate information and clicks the button to retrieve the query. Ideally I would like to pull the information directly, without save prompting, to my N: drive and simply save it as "File.xlsx"; navigating the download/save prompt would work as well, but I have no idea which would be easier or more efficient to accomplish.
Sub Automation()
Const URL1 = "https://website/q/?ICAction=ICQryNameExcelURL=PUBLIC.Z_FILE_DESIGN"
Dim IE As New SHDocVw.InternetExplorer
Dim HTMLDoc As HTMLDocument
Dim DValue As String
Set IE = New SHDocVw.InternetExplorerMedium
DValue = Format(Date, "mm/dd/yyyy")
With IE
.Navigate URL1
.Visible = True
End With
Do
DoEvents
Loop Until IE.ReadyState = 4 And Not IE.Busy
IE.Navigate "javascript: signinIWA();"
Do
DoEvents
Loop Until IE.ReadyState = 4 And Not IE.Busy
Set HTMLDoc = IE.Document
HTMLDoc.getElementById("InputKeys_Z_File").Value = "q32e751"
HTMLDoc.getElementById("InputKeys_EFFDT").Value = DValue
Do
DoEvents
Loop Until IE.ReadyState = 4 And Not IE.Busy
HTMLDoc.getElementById("#ICQryDownloadExcelFrmPrompt").Click
End Sub
If it helps at all, the code when inspecting the click button element:
</DIV></td>
</tr>
<input type='hidden' name='ICExcel' id='ICExcel' value='1' />
</table>
<a class='PSPUSHBUTTON' style='background-Color: transparent;border:0;' id = 'Left' role='presentation'><span style='background-Color: transparent;border:0;'><input type='button' class='PSPUSHBUTTON' value='View Results' id='#ICQryDownloadExcelFrmPrompt' onclick="submitAction_win4(this.form,'#ICQryDownloadExcelFrmPrompt');" tabindex='14' /></span></a>
</DIV>
<DIV id='win4divQUERYRESULT'><table cellpadding='2' cellspacing='0' width='90%'>
<tr><td>
</td></tr>
<tr><td>`
The one thing that does change each time accessed is the number "4" in the onclick action and queryresult line following. Also, when the temporary file is opened it always has the same basic name - Z_FILE_DESIGN, but includes a random number attached, eg. Z_FILE_DESIGN_12345. Any suggestions or assistance are greatly appreciated.
Related
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
I'm trying to use the Excel VBA to fill a web form and then scrape some data.
I am stuck on how to put in the value that I want to search for.
In the source code, there is no id or name that I can use.
I tried with a class name but it is not working.
" Source code:
<input type="text" style="height: 28px; width: 170px; padding-left: 5px;" ng-model="model.FieldValue" placeholder="Enter a Value" ng-show="model.searchOptions.length && model.searchOptions != 'SQE Quote Id'" class="ng-pristine ng-valid ng-touched">
Sub Macro1()
Dim i As Long
Dim URL As String
Dim IE As Object
Dim objElement As Object
Dim objCollection As Object
Dim html As HTMLDocument
Set IE = New InternetExplorerMedium
'Set IE.Visible = True to make IE visible, or False for IE to run in the background
IE.Visible = True
'Define URL
URL = "xxxx"
'Navigate to URL
IE.Navigate URL
' Statusbar let's user know website is loading
Application.StatusBar = URL & " is loading. Please wait..."
' Wait while IE loading...
'IE ReadyState = 4 signifies the webpage has loaded (the first loop is set to avoid inadvertently skipping over the second loop)
Do While IE.ReadyState = 4: DoEvents: Loop 'Do While
Do Until IE.ReadyState = 4: DoEvents: Loop 'Do Until
'
Set html = IE.Document
IE.Document.getElementById("searchOptions").Click (2)
IE.Document.getElementById("searchOptions").Value = "Access Qref"
IE.Document.getelemenetbyclassname("ng-pristine ng-valid ng-touched").Value = "00000"
'
End Sub
Try to put '.' between class names like below is working on my side.
IE.Document.querySelector("input.ng-pristine.ng-valid.ng-touched").Value = "00000"
Modified example:
Sub Macro1()
Dim i As Long
Dim URL As String
Dim IE As Object
Dim objElement As Object
Dim objCollection As Object
Dim html As HTMLDocument
Set IE = New InternetExplorerMedium
'Set IE.Visible = True to make IE visible, or False for IE to run in the background
IE.Visible = True
'Define URL
URL = "D:\Backup20190913\tests\353.html"
'Navigate to URL
IE.Navigate URL
' Statusbar let's user know website is loading
Application.StatusBar = URL & " is loading. Please wait..."
' Wait while IE loading...
'IE ReadyState = 4 signifies the webpage has loaded (the first loop is set to avoid inadvertently skipping over the second loop)
Do While IE.ReadyState = 4: DoEvents: Loop 'Do While
Do Until IE.ReadyState = 4: DoEvents: Loop 'Do Until
Set html = IE.Document
IE.Document.querySelector("input.ng-pristine.ng-valid.ng-touched").Value = "00000"
End Sub
Output:
The error is as it says. The method you are trying does not exist for that node. You are fine using a multi-valued class (more than one class name for the element; denoted by several strings separated by spaces within the class attribute of the element) inside of the correct method getElementsByClassName, rather than getelemenetbyclassname then you need to index into the returned collection in order to exercise the .click method.
IE.Document.getElementsByClassName("ng-pristine ng-valid ng-touched")(0).Value = "00000" '0 for first node
However, as in other answer, if using querySelector/querySelectorAll to match by css class selector then a multi-valued class must have the spaces between replaced with ".". Better still, try to select as few of those class names inside the multi-value as possible and the most selective which still match on the required node(s)
And please, I write this a lot on SO, use a proper page load wait:
While IE.busy Or IE.readystate <> 4: DoEvents: Wend
Can someone help please, i can't seem to get the below to work
Sub Automate_IE_Load_Page()
'This will load a webpage in IE
Dim i As Long
Dim URL As String
Dim IE As InternetExplorer
Dim objElement As Object
Dim objCollection As Object
'Create InternetExplorer Object
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
URL = "https://Whatever" 'Not putting the URL up here
IE.Navigate URL
Do Until IE.ReadyState = 4: DoEvents: Loop
IE.Document.getElementbyid("menuoptionCell_Excel2007+").Click '(Fails here)
'Set Button = IE.Document.getElementbyid("menuoptionCell_Excel2007+")
'Button.Click
End Sub
i have also tried
IE.Document.getElementsbyClass("contextMenuOptionTextCell")(0).Click
It is saying i need an object. I have tried different methods but none seem to work. I will say i am using the word "Button" loosely as its not actually a button, but not sure what it is called. Below are the identities used on the web page, and i'm not totally sure which i need to press, but neither seem to work
<td class="contextMenuOptionTextCell">
<span class="contextMenuOptionText">Excel 2007+</span></td>
<td id="menuoptionCell_Excel2007+" style="vertical-align: top; width: 16px;"></td>
thank you
Mike
I have some code which is meant to open an IE page and fill in the first drop-down to show "caravan". However my code is not selecting caravan from the drop-down.
The website is:
https://insurance.qbe.com.au/portal/caravan/form/estimate
When I right-click to inspect the source code of the drop-down I get directed to the following:
When I expand the source code below this, I see the following:
As you can see, the values associated with the drop-down are well below the source code I was initially directed to.
Here is the code I've been using to try and select 'caravan':
Sub GetQuote()
Dim IE As Object
Set IE = CreateObject("InternetExplorer.Application")
IE.navigate ("https://insurance.qbe.com.au/portal/caravan/form/estimate")
IE.Visible = True
Do
DoEvents
Loop Until IE.readystate = 4
Dim lists, l
Set lists = IE.document.getElementsByTagName("select")(0)
For Each l In lists
If InStr(1, l.className, "form-control ng-pristine ng-untouched ng-valid", 1) Then
l.SelectedIndex = 0
End If
Next
Application.Wait (Now + TimeValue("00:00:03"))
End Sub
With the above code I was trying to select 'caravan' by referencing the very last bit of the source code I pasted above (i.e. by getting all select tags and then checking all items within the tag until an item whose class name contains "form-control ng-pristine ng-untouched ng-valid" is found, and then selecting index 0 for the value associated with this item. And this obviously didn't work - so here's other code I have tried, again with no luck (it's a slight modification of the code above, by simply referencing the source code that I was initially directed to when I inspected the drop-down, and that would be the very first source code I pasted):
For Each l In lists
If InStr(1, l.className, "ui-select-search ui-select-toggle ng-pristine ng-valid ng-touched", 1) Then
l.SelectedIndex = 0
Does this offer any help, not sure if it's your solution, but added here for formatting.
Sub test()
Dim ie As SHDocVw.InternetExplorer
Dim htmlDoc As MSHTML.HTMLDocument
Dim inputCollection As MSHTML.IHTMLElementCollection
Dim inputElement As MSHTML.HTMLInputElement
Set ie = New SHDocVw.InternetExplorer
ie.navigate ("https://insurance.qbe.com.au/portal/caravan/form/estimate")
Do While ie.Busy Or ie.readyState <> READYSTATE_COMPLETE
DoEvents
Loop
ie.Visible = 1
Set htmlDoc = ie.document
Set inputCollection = htmlDoc.getElementsByTagName("INput")
For Each inputElement In inputCollection
Debug.Print inputElement.className
Next inputElement
' or like this
Set inputElement = htmlDoc.getElementsByClassName("ui-select-search ui-select-toggle ng-pristine ng-valid ng-touched")(0)
End Sub
I'm working with VBA to fill a form in a URL and submiting to get results.
When I submit the form with correct values and submit via VBA, I get results in another URL but on the same window.
The problem is that I don't know how to change html reference to start scrapping data with this new url.
Here is my code:
'to refer to the running copy of Internet Explorer
Dim IE As InternetExplorer
'to refer to the HTML document returned
Dim html As HTMLDocument
'open Internet Explorer in memory, and go to website
Set IE = New InternetExplorer
IE.Visible = False
IE.navigate "http://url..."
'Wait until IE is done loading page
Do While IE.READYSTATE <> READYSTATE_COMPLETE
Application.StatusBar = "Connecting with http://url..."
DoEvents
Loop
'show text of HTML document returned
Set html = IE.document
'close down IE and reset status bar
Set IE = Nothing
Application.StatusBar = ""
Set txtArea = html.getElementsByTagName("textarea")(0)
txtArea.Value = txtArea_data
Set formSubmit = html.getElementsByName("submit")(1)
formSubmit.Click
'-------------Get results
'Dim html_results As HTMLDocument
IE.navigate "http://new_url" 'Im not sure if I must do it this way...
'Wait until IE is done loading page
Do While IE.READYSTATE <> READYSTATE_COMPLETE
Application.StatusBar = "Connecting with http://new_url..."
DoEvents
Loop
Set html = IE.document
Dim trResults As IHTMLElementCollection
Set trResults = html.getElementsByClassName("tr")
MsgBox (trResults.Length) 'At this point, trResults always have 0 results...
Have you any idea to help me?
Thanks!
This is a new approach, and still don't work.
I've used IE.Visible = True, so I could check that I get many <tr> results on the results page.
Dim rowNumber As Long
Dim txtArea_data As String
Dim txtArea As Object
Dim formSubmit As Object
Dim IE As InternetExplorer
Dim html As HTMLDocument
Set IE = New InternetExplorer
IE.Visible = True
IE.navigate "http://url..."
Do While IE.READYSTATE <> READYSTATE_COMPLETE
Application.StatusBar = "Connecting with http://url..."
DoEvents
Loop
Set html = IE.document
rowNumber = 4
For rowNumber = 4 To 120 'Rows.Count
txtArea_data = txtArea_data & Cells(rowNumber, 1).Value & Chr(10)
Next rowNumber
Set txtArea = html.getElementsByTagName("textarea")(0)
txtArea.Value = txtArea_data
Set formSubmit = html.getElementsByName("submit")(1)
formSubmit.Click
'Wait until results
Do While IE.Busy: DoEvents: Loop
'-------------Get results
'At this point, the page URL with results has changed, but on the same tab. In the other code, I've used IE.navigate "http://new_url..." But a "Invalid file" message appears.
'-------------
'I suppose html var could be recharged with these new results data, but nothing happen...
Set html = IE.document
Dim trResults As IHTMLElementCollection
Set trResults = html.getElementsByClassName("tr")
MsgBox (trResults.Length) 'At this point, MsgBox returns O...
Set html = Nothing
Results page looks like:
<body>
<table id="tabla-a">
<thead>
<tr>
<th>...</th>
<th>...</th>
<th>...</th>
</tr>
</thead>
<tbody>
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
</tr>
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
</tr>
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
</tr>
</tbody>
</table>
</body>
Is there anything I could tell you to make to help you finding the problem?
Thanks!
EDIT
Oh my God! I've been using Set trResults = html.getElementsByClassName("tr") instead of Set trResults = html.getElementsByTagName("tr") !!!
Thanks for your time!
What should I do now? Edit the original question with the final solution or close the entire question?
I don't use Stackoverflow too much to ask questions...
Thanks!