Error 91 when Internet Explorer Save prompt is shown - excel

My goal is to open a site, input into the forms, save a report through a button, and then loop around and continue for the next entry. I am using the Microsoft WinHTTP, HTML object library, and Internet Controls.
This works so long as I have no "Open/Save As" prompt in Internet Explorer. It successfully loops through the results and clicks the report button, then restarts. However, once the prompt appears, it causes a break in line " svalue1.Value = ws.Cells(Lastrow, 1).Value " reporting Error 91, object not found, that I can't for the life of me understand. Why would the save prompt break a VBA script?
Commented out is some of the fixes I've tried, but nothing seems to resolve this issue. Am I missing something obvious?
Thank you for taking the time to help a newbie out with this! :)
Enum READYSTATE
READYSTATE_UNINITIALIZED = 0
READYSTATE_LOADING = 1
READYSTATE_LOADED = 2
READYSTATE_INTERACTIVE = 3
READYSTATE_COMPLETE = 4
End Enum
Sub Test()
Dim ws As Worksheet: Set ws = Sheets("Sheet1") 'set the Sheet you are using here
Dim ie As New InternetExplorerMedium
'Set ie = New InternetExplorerMedium
Dim HTML As HTMLDocument
Dim i As Long
Lastrow = ws.Range("A1").End(xlDown).Row
'get the last row with a value in column A
strURL = "www.coollinkExample.com" 'set your initial URL here
ie.Visible = True
ie.navigate strURL
Do While (ie.Busy Or ie.READYSTATE <> READYSTATE.READYSTATE_COMPLETE)
DoEvents
Loop
Set HTML = ie.document
'-----------------INIT-----------------
'For i = 1 To Lastrow Step 1 'loop from row 1 to Last
Do While i < Lastrow 'loop from row 1 to Last
'Do While (ie.Busy Or ie.READYSTATE <> READYSTATE.READYSTATE_COMPLETE)
'DoEvents
'Loop BUGS WHEN SAVE PROMPT IS UP?
'-----------------BODY-----------------
'Do your data scraping here, then below go back to your initial URL to repeat the process
delay 5
Set svalue1 = HTML.getElementById("userNameText")
ie.document.getElementById("userNameText").Focus
svalue1.Value = ws.Cells(Lastrow, 1).Value 'enter the value from current cell
delay 2
ie.document.getElementById("btnSearchUser").Focus
HTML.getElementsByName("btnSearchUser").Item.Click
delay 3
ie.document.getElementById("rptUsers_ctl00_ddlUserOptions").Focus
HTML.getElementsByName("rptUsers_ctl00_ddlUserOptions").Item.Click
delay 3
ie.document.getElementById("rptUsers_ctl00_ddlUserOptions_lnkTranscript").Focus
HTML.getElementsByName("rptUsers_ctl00_ddlUserOptions_lnkTranscript").Item.Click
delay 3
ie.document.getElementById("__ta").Focus
HTML.getElementsByName("__ta").Item.Click
delay 2
ie.document.getElementById("__tj").Focus
HTML.getElementsByName("__tj").Item.Click
delay 4
With ie.document.getElementById("ctl00_ContentPlaceHolder1_btnExport")
.Focus
.Click
End With
delay 5
Application.SendKeys "%{S}"
delay 3
'-----------------END-----------------
ie.navigate strURL
delay 5
'Exit For
'Next i
i = i + 1
Loop
End Sub
'// This function below works fine.
Private Sub delay(seconds As Long)
Dim endTime As Date
endTime = DateAdd("s", seconds, Now())
Do While Now() < endTime
DoEvents
Loop
End Sub

You have ie.navigate strURL at the end of the loop but are not waiting for the page to load fully.
Option Explicit
Sub Test()
Dim ws As Worksheet
Dim ie As InternetExplorerMedium
Dim doc As HTMLDocument, strURL As String
Dim i As Long, lastrow As Long
strURL = "www.coollinkExample.com" 'set your initial URL here
Set ie = New InternetExplorerMedium
ie.Visible = True
Set ws = Sheets("Sheet1")
With ws
lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = 1 To lastrow
' navigate to site
ie.navigate strURL
Do While ie.Busy Or ie.READYSTATE <> 4 'READYSTATE.READYSTATE_COMPLETE)
DoEvents
Loop
Set doc = ie.document
delay 5
doc.getElementById("userNameText").innerText = Trim(.Cells(i, "A"))
delay 3
doc.getElementById("btnSearchUser").Click
delay 3
doc.getElementById("rptUsers_ctl00_ddlUserOptions").Click
delay 3
doc.getElementById("rptUsers_ctl00_ddlUserOptions_lnkTranscript").Click
delay 3
doc.getElementById("__ta").Click
delay 3
doc.getElementById("__tj").Click
delay 3
doc.getElementById("ctl00_ContentPlaceHolder1_btnExport").Click
delay 5
Application.SendKeys "%(S)"
delay 3
Next i
End With
ie.Quit
MsgBox "Done", vbInformation
End Sub

Related

Paste table from web into range of cells

I am trying to get a table from a website into my excel sheet. Since the website has a log in and I need to click a few buttons to get to the table, I am using VBA.
The code I have so far is just a test, it is not the actual website that I am trying to log into.
So far, the code is able to launch the website and get the inner text from the table, but it only pastes it into a single cell. How can I paste the table by keeping the same formatting?
Sub test()
Set IE = CreateObject("InternetExplorer.application")
IE.Visible = True
IE.navigate ("https://www.w3schools.com/html/html_tables.asp")
Do
If IE.readyState = 4 Then
IE.Visible = True
Exit Do
Else
DoEvents
End If
Loop
'get data
Dim tbl As HTMLTable
Set tbl = IE.document.getElementById("customers")
Cells(1, 1) = tbl.innerText
End Sub
You may perform webscraping using the following code enhancement, it work perfectly :
Sub test()
Dim IE As Object
Set IE = CreateObject("InternetExplorer.application")
IE.Visible = True
IE.navigate ("https://www.w3schools.com/html/html_tables.asp")
Do
If IE.readyState = 4 Then
IE.Visible = True
Exit Do
Else
DoEvents
End If
Loop
'get data
Dim tbl As HTMLTable
Dim class1 As IHTMLElement, rowText As IHTMLElement, item As IHTMLElement
Dim rowNum As Long, colNum As Long
Set class1 = IE.document.getElementById("customers").children(0)
rowNum = 0
For Each rowText In class1.children
rowNum = rowNum + 1
colNum = 0
For Each item In rowText.children
colNum = colNum + 1
Sheet1.Cells(rowNum, colNum).Value = item.innerText
Next
Next
End Sub

Transform InternetExplorer to XML

I just discovered xml or xmlhttp and this is entirely new to me.
I am trying to create a macro wherein it would go through all the list of websites in column J starting at row 2 (header at row 1). Get the information that I want from each website, then display them in column K, which is right next to the websites where the information was taken from.
Column J has a list of websites, starting at J2. Let's say it would go all the way down to J10. From each website, there is a certain information I want to get, so the macro will visit the website at J2, get that information and paste it in K2, then visit the website in J3, paste that information in K3, and so on. I already have an existing list of website at column J, which also happens to be dynamic.
This is the current code that I have using IE that I want to convert into xml/xmlhttp.
Sub CommandButton1_Click()
Dim ie As Object
Dim lastrow As Integer
Dim i As Integer
Dim myURL As String
Dim sdd As String
Dim add As Variant
Dim html As Object
Dim mylinks As Object
Dim mylink As Object
Dim result As String
' Create InternetExplorer Object
Set ie = CreateObject("InternetExplorer.Application")
lastrow = Sheet1.Cells(Rows.Count, "J").End(xlUp).Row
For i = 2 To lastrow
myURL = Sheet1.Cells(i, "J").Value
' Hide InternetExplorer
ie.Visible = False
' URL to get data from
ie.navigate myURL
' Loop until page fully loads
Do While ie.readystate <> READYSTATE_COMPLETE
Loop
' Information i want to get from the URLs
sdd = ie.document.getelementsbyclassname("timeline-text")(0).innerText
' Format the result
add = Split(sdd, "$")
Range("K3") = add(1)
' Close InternetExplorer
ie.Quit
'Return to Normal?
ie.Visible = True
End
Next
' Clean up
Set ie = Nothing
Application.StatusBar = ""
End Sub
I am trying to get the "85100", not the $85,100
<span class="font-size-base font-normal">Est.</span>
<span itemprop="price" content="85100">
$85,100
</span>
I'm hoping you could help me with this problem.
Thank you in advance.
I would structure something like as follows, where the IE object is created outside the loop. You use css selectors throughout. You may need a timed loop to ensure element is present on page. Use a proper page load wait as shown.
Use an explicit worksheet name to put the worksheet in a variable to work with.
You might want to add a test that myURL has http/https in it as you may have blank cells in range and only want to work with likely urls values.
Option Explicit
Public Sub CommandButton1_Click()
Dim ie As Object, lastrow As Long, i As Long
Dim myURL As String, sdd As String, ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1") ' <change as required
Set ie = CreateObject("InternetExplorer.Application")
lastrow = ws.Cells(Rows.Count, "J").End(xlUp).Row
With ie
.Visible = False
For i = 2 To lastrow
myURL = ws.Cells(i, "J").Value
.navigate2 myURL
While .Busy Or .readyState < 4: DoEvents: Wend
sdd = .document.querySelector(".price").getAttribute("content")
ws.Cells(i, "K") = sdd
Next
.Quit
End With
'Application.StatusBar = ""
End Sub
With a timed loop:
Public Sub CommandButton1_Click()
Dim ie As Object, lastrow As Long, i As Long, t As Date, ele As Object
Const MAX_WAIT_SEC As Long = 10
Dim myURL As String, sdd As String, ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1") ' <change as required
Set ie = CreateObject("InternetExplorer.Application")
lastrow = ws.Cells(rows.Count, "J").End(xlUp).Row
With ie
.Visible = False
For i = 2 To lastrow
myURL = ws.Cells(i, "J").Value
.Navigate2 myURL
While .Busy Or .readyState < 4: DoEvents: Wend
t = Timer
Do
On Error Resume Next
Set ele = HTMLDoc.querySelector(".price")
On Error GoTo 0
If Timer - t > MAX_WAIT_SEC Then Exit Do
Loop While ele Is Nothing
If Not ele Is Nothing Then
sdd = ele.getAttribute("content")
ws.Cells(i, "K") = sdd
End If
Next
.Quit
End With
'Application.StatusBar = vbnullstring
End Sub

Run Through A List Then Paste Result To Its Next Cell

I was able to create a macro wherein it would go through all the list of websites in column J starting at row 2 (header at row 1). Get the information that I want from each website, then display them in column K, which is right next to the websites where the information was taken from.
The only problem is that, I cant make the macro go to each of the websites.
I dont know what is wrong with the code.
Sub CommandButton1_Click()
Dim ie As Object
Dim lastrow As Integer
Dim i As Integer
Dim myURL As String
Dim sdd As String
Dim add As Variant
Dim html As Object
Dim mylinks As Object
Dim mylink As Object
Dim result As String
' Create InternetExplorer Object
Set ie = CreateObject("InternetExplorer.Application")
lastrow = Sheet1.Cells(Rows.Count, "J").End(xlUp).Row
For i = 2 To lastrow
myURL = Sheet1.Cells(i, "J").Value
' Hide InternetExplorer
ie.Visible = False
' URL to get data from
ie.navigate myURL
' Loop until page fully loads
Do While ie.readystate <> READYSTATE_COMPLETE
Loop
' Information i want to get from the URLs
sdd = ie.document.getelementsbyclassname("timeline-text")(0).innerText
' Format the result
add = Split(sdd, "$")
Range("K3") = add(1)
' Close InternetExplorer
ie.Quit
'Return to Normal?
ie.Visible = True
End
Next
' Clean up
Set ie = Nothing
Application.StatusBar = ""
End Sub
$85,100 is the information I want to get from one of the URLs.
<span class="font-size-base font-normal">Est.</span>
<span itemprop="price" content="85100">$85,100</span>
Don't quit IE until you've completed the loop. Simply navigate to the next URL and record the new page's information on the same row as the URL was collected from.
Sub CommandButton1_Click()
Dim lastrow As Long, i As Long
Dim sdd As String, myURL As String, result As String
Dim add As Variant
Dim ie As Object, html As Object, mylinks As Object, mylink As Object
' Create InternetExplorer Object
Set ie = CreateObject("InternetExplorer.Application")
' Hide InternetExplorer
ie.Visible = False
lastrow = Sheet1.Cells(Rows.Count, "J").End(xlUp).Row
For i = 2 To lastrow
'collect next web page url
myURL = Sheet1.Cells(i, "J").Value
' URL to get data from
ie.navigate myURL
' Loop until page fully loads
Do While ie.readystate <> READYSTATE_COMPLETE
'allow other process through the message queue
DoEvents
Loop
' Information i want to get from the URLs
sdd = ie.document.getelementsbyclassname("timeline-text")(0).innerText
' Format the result
add = Split(sdd, "$")
Sheet1.Cells(i, "K") = add(1)
Next i
'Return to Normal?
ie.Visible = True
' Close InternetExplorer
ie.Quit
' Clean up
Set ie = Nothing
Application.StatusBar = ""
End Sub
I've also added DoEvents within your page load wait loop. This allows other processes to execute instead of tying up resources in the single threaded VBA process.
there is something you have to take note of while programming. Always try to echo a visible result.
Do this before the loop after the lastrow
msgbox lastrow
E.g in between the for loop, do something like
msgbox sdd
You should be able to get where the errors lie.
I hope this helps.

Retrieving a URL from Internet Explorer with VBA

I have written some VBA code in Excel to retrieve the latitude and longitude from a Google Maps URL and paste it into a cell in my worksheet. My problem is in retrieving the URL from internet explorer. Below I have two examples of my code, one macro returns an about:blank as though the object doesn't have the LocationURL property, and the other example seems like it is saving all of my previous searches, so it cycles through all of my previous searches and pastes the very first searches' URL. Example 2 uses a shell suggestion that I found online to reassign the properties to the oIE object. I can get both to slightly work, but neither will do exactly what I need from the macro.
Cell(8,8) is a hyperlink to google maps where I'm searching an address, and Cell(8,9) is where I want to paste the URL after google maps has redirected and has the latitude and longitude in the URL.
Example 1:
Sub CommandButton1_Click()
Dim ie As Object
Dim Doc As HTMLDocument
Set ie = CreateObject("InternetExplorer.Application")
ie.Visible = True
ie.Navigate "http://www.google.com/maps?q=" & Range("I7").Value
Do
DoEvents
Loop Until ie.ReadyState = 4
Set Doc = ie.Document
Cells(8, 9).Value = ie.LocationName
End Sub
Example 2:
Sub Macro()
Dim oIE, oShell, objShellWindows, strPath, X
strPath = Cells(8, 8)
Set oIE = CreateObject("InternetExplorer.Application")
'This is to resolve oIE.navigate "about:blank" issue
oIE.Top = 0
oIE.Left = 0
oIE.Width = 500
oIE.Height = 500
oIE.Navigate strPath
Do While oIE.Busy And oIE.ReadyState < 2
DoEvents
Loop
'Reassigning oIE.LocationName & vbCrLf & oIE.LocationURL values after redirect in IE
Set oShell = CreateObject("WScript.Shell")
Set objShellWindows = CreateObject("Shell.Application").Windows
For X = objShellWindows.Count - 1 To 0 Step -1
Set oIE = objShellWindows.Item(X)
If Not oIE Is Nothing Then
If StrComp(oIE.LocationURL, strPath, 1) = 0 Then
Do While oIE.Busy And oIE.ReadyState < 2
DoEvents
Loop
oIE.Visible = 2
Exit For
End If
End If
Cells(8, 9).Value = oIE.LocationURL
Set oIE = Nothing
Next
Set objShellWindows = Nothing
Set oIE = Nothing
End Sub
Thanks,
Andrew
Is this as simple as looping until the document.URL changes? In my timed loop I wait for the string safe=vss in the original page load to disappear.
Option Explicit
Public Sub GetNewURL()
Dim IE As New InternetExplorer, newURL As String, t As Date
Const MAX_WAIT_SEC As Long = 5
With IE
.Visible = True
.navigate2 "http://www.google.com/maps?q=" & "glasgow" '<==Range("I7").Value
While .Busy Or .readyState < 4: DoEvents: Wend
t = Timer
Do
DoEvents
newURL = .document.URL
If Timer - t > MAX_WAIT_SEC Then Exit Do
Loop While InStr(newURL, "safe=vss") > 0
Debug.Print newURL
End With
End Sub

VBA: copy data from website into excel

I have a VBA code that selects info from drop-down menus on a government website and then submits the query. The requested data then opens up in another IE page. I am trying to copy this data into excel; however, I am unable to do so.
My code currently copies the text on the first IE page that contains the drop-down menus. The government website is: http://www.osfi-bsif.gc.ca/Eng/wt-ow/Pages/FINDAT.aspx
I have look all over the internet for a solution but nothing seems to work...
Here is my code:
Sub GetOsfiFinancialData()
Dim UrlAddress As String
UrlAddress = "http://ws1.osfi-bsif.gc.ca/WebApps/FINDAT/DTIBanks.aspx?T=0&LANG=E"
Dim ie As Object
Set ie = CreateObject("internetexplorer.application")
With ie
.Silent = True
.Visible = False
.navigate UrlAddress
End With
Do Until Not ie.Busy And ie.readyState = 4
DoEvents
Loop
Application.Wait (Now() + TimeValue("00:00:05"))
'Select Bank
ie.document.getElementById("DTIWebPartManager_gwpDTIBankControl1_DTIBankControl1_institutionTypeCriteria_institutionsDropDownList").Value = Z005
'open window with financial data
Dim objButton
Set objButton = ie.document.getElementById("DTIWebPartManager_gwpDTIBankControl1_DTIBankControl1_submitButton")
objButton.Focus
objButton.Click
'select new pop-up window
marker = 0
Set objshell = CreateObject("Shell.Application")
IE_count = objshell.Windows.Count
For x = 0 To (IE_count - 1)
On Error Resume Next ' sometimes more web pages are counted than are open
my_title = objshell.Windows(x).document.Title
If my_title Like "Consolidated Monthly Balance Sheet" & "*" Then 'compare to find if the desired web page is already open
Set ie = objshell.Windows(x)
marker = 1
Exit For
Else
End If
Next
Do Until Not ie.Busy And ie.readyState = 4
DoEvents
Loop
Application.Wait (Now() + TimeValue("00:00:05"))
Dim doc As MSHTML.HTMLDocument
Dim tables As MSHTML.IHTMLElementCollection
Dim table As MSHTML.HTMLTable
Dim clipboard As MSForms.DataObject
Set doc = ie.document
Set tables = doc.getElementsByTagName("body")
Set table = tables(0)
Set clipboard = New MSForms.DataObject
'paste in sheets
Dim test
Set test = ActiveWorkbook.Sheets("Test")
clipboard.SetText table.outerHTML
clipboard.PutInClipboard
test.Range("A1").PasteSpecial xlPasteAll
clipboard.Clear
MsgBox ("Task Completed")
End Sub
Your help is greatly appreciated!
You were using the current test with document.Title. I found that For Each of all windows looking for the full title worked in combination with copy pasting the pop-up window outerHTML. No additional wait time was required.
Inside the For Each Loop, after you reset the IE instance to the new window, you can obtain the new URL with ie.document.url. As you already have the data loaded you might as well just copy paste it straight away in my opinion.
Code:
Option Explicit
Public Sub GetOsfiFinancialData()
Dim UrlAddress As String, objButton, ie As Object
UrlAddress = "http://ws1.osfi-bsif.gc.ca/WebApps/FINDAT/DTIBanks.aspx?T=0&LANG=E"
Set ie = CreateObject("internetexplorer.application")
With ie
.Silent = True
.Visible = False
.navigate UrlAddress
While .Busy Or .readyState < 4: DoEvents: Wend
.document.getElementById("DTIWebPartManager_gwpDTIBankControl1_DTIBankControl1_institutionTypeCriteria_institutionsDropDownList").Value = "Z005"
Set objButton = .document.getElementById("DTIWebPartManager_gwpDTIBankControl1_DTIBankControl1_submitButton")
objButton.Focus
objButton.Click
Dim objShellWindows As New SHDocVw.ShellWindows, currentWindow As IWebBrowser2
For Each currentWindow In objShellWindows
If currentWindow.document.Title = "Consolidated Monthly Balance Sheet - Banks, Trust and Loan" Then
Set ie = currentWindow
Exit For
End If
Next
Dim clipboard As Object
Set clipboard = GetObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
clipboard.SetText ie.document.body.outerHTML
clipboard.PutInClipboard
ThisWorkbook.Worksheets("Sheet1").Cells(1, 1).PasteSpecial
.Quit
End With
End Sub
References (VBE > Tools > References):
Microsoft Internet Controls
I don't have time to get into all the stuff about controlling one browser from another, but I think you can figure that part out, especially since you made some great progress on this already. Get URL#2 from URL#1, like you are doing, but with some better data controls around it, and then do this...
Option Explicit
Sub Web_Table_Option_One()
Dim xml As Object
Dim html As Object
Dim objTable As Object
Dim result As String
Dim lRow As Long
Dim lngTable As Long
Dim lngRow As Long
Dim lngCol As Long
Dim ActRw As Long
Set xml = CreateObject("MSXML2.XMLHTTP.6.0")
With xml
.Open "GET", "http://ws1.osfi-bsif.gc.ca/WebApps/Temp/2f40b7ef-d024-4eca-a8a3-fb82153efafaFinancialData.aspx", False
.send
End With
result = xml.responseText
Set html = CreateObject("htmlfile")
html.body.innerHTML = result
Set objTable = html.getElementsByTagName("Table")
For lngTable = 0 To objTable.Length - 1
For lngRow = 0 To objTable(lngTable).Rows.Length - 1
For lngCol = 0 To objTable(lngTable).Rows(lngRow).Cells.Length - 1
ThisWorkbook.Sheets("Sheet1").Cells(ActRw + lngRow + 1, lngCol + 1) = objTable(lngTable).Rows(lngRow).Cells(lngCol).innerText
Next lngCol
Next lngRow
ActRw = ActRw + objTable(lngTable).Rows.Length + 1
Next lngTable
End Sub

Resources