So I have this code I'm working on for my deptarment that goes to a website inputs data , clicks run and downloads the csv file to the worksheet. It works just fine on my PC and on my profile on the computers the other department uses. We are both using same versions of windows, excel , and IE. When i have someone from the other department run the macro it opens the website but never enters the data into the fields despite the site being the exact same coding as when i'm logged in.
Sub testmetric()
Dim appIE As Object
Dim Obj As Object
On Error Resume Next
Sheets("Audit").Select
Selection.AutoFilter
Sheets("Audit").Cells.Clear
Application.ScreenUpdating = False
Application.ScreenUpdating = True
Set appIE = CreateObject("InternetExplorer.Application")
sURL = "http://cctools/rportal/main.php?p=agentavaya"
' Instructes the macro to open IE and navigate to sURL.
With appIE
.Navigate sURL
.Visible = True
Application.Wait Now + TimeValue("00:00:02")
Set HTMLDOC = .Document
End With
Application.Wait Now + TimeValue("00:00:02")
appIE.Document.getElementById("agentLob").selectedIndex = "3"
appIE.Document.getElementById("timezone").selectedIndex = "1"
appIE.Document.getElementById("sdate").Value = Range("Date_Start")
appIE.Document.getElementById("edate").Value = Range("Date_End")
appIE.Document.getElementById("stenure").Value = Range("TenStart")
appIE.Document.getElementById("etenure").Value = Range("TenEnd")
Application.Wait Now + TimeValue("00:00:02")
For Each Btninput In appIE.Document.getElementsByTagName("INPUT")
If Btninput.Value = " Run " Then
Btninput.Click
Exit For
End If
Next
Application.Wait Now + TimeValue("00:00:02")
Call CSV
appIE.Quit
Sheets("Audit").Select
Range("A1").Select
Sheets("audit").Paste
End Sub
Sub CSV()
sCSVLink = "http://cctools/rportal/csvexport.php"
sfile = "csvexport.php"
ssheet = "Sheet10"
Set wnd = ActiveWindow
Application.ScreenUpdating = False
Workbooks.Open Filename:=sCSVLink
Windows(sfile).Activate
ActiveSheet.Cells.Copy
wnd.Activate
Range("A1").Select
Sheets("Audit").Paste
Application.DisplayAlerts = False
Windows(sfile).Close False
Application.DisplayAlerts = True
Application.ScreenUpdating = True
Sheets("Audit").Select
Range("A1").Select
Sheets("audit").Paste
End Sub
When this code is ran by a member of the other department it just opens the website inputs nothing and doesn't press the RUN button on the website.
Any ideas on what could be causing this? What setting or anything. I verified that both PC's VBA references in are there and no "Locations are missing paths" .
You are never checking to see if the web page has finished loading!
Your On Error Resume Next statement is also hiding any errors and preventing you from taking the appropriate remedial action by fixing the code. Please report back with the specific error number and line which raises the error. I have an idea which line and which error, and my answer is intended for that:
Type 91 error on line: Set HTMLDOC = .Document
Why?
While you are waiting, Application.Wait is a really ineffective method to wait for the browser to load, and 2 seconds may not always be enough time anyways. The best way I can think of to handle this, assuming you're getting a type 91 error, is like so:
How to make a ready-waiting loop for Browser control
Basically you need to put the thread in a loop until the browser has loaded the page. In pseudo-code, you're doing:
Do Until Browser Is Loaded
DoEvents 'etc.
Loop
Using the WinAPI Sleep Function
You will need to use the WinAPI Sleep function (a lot of people use DoEvents or Application.Wait but I have found here that Sleep is preferable.
Because it is a Declare, you must put it in an ordinary module, it can't go in a class or userform module.
'## This needs to go in an ordinary code module
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Calling the WinAPI Sleep Function
Sleep 250 'sleep for 1/4 of a second, or Sleep 1000 to sleep for a full second, etc.
Putting it all together
You will need to put a Do ... Loop that calls on this function immediately after the .Navigate method.
'## This goes in where you do Navigate method:
With appIE
.Navigate sURL
Do
Sleep 250
Loop While Not .ReadyState <> 4 'READYSTATE_COMPLETE
Set HTMLDoc = .Document
End With
If it still doesn't work...
Yes, there's always an exception. I do very little web-based automation, and most of what I do is just tinkering with stuff here to help people out. What I have noticed is that increasingly websites are served dynamically (AJAX maybe?) and that in these cases, the browser may be .ReadyState = READYSTATE_COMPLETE and even .Busy = False, yet the .Document is still Nothing.
IF that happens, you could put a secondary loop, like:
Dim numberOfAttempts
Do While .Document Is Nothing
Sleep 250
numberOfAttempts = numberOfAttempts + 1
If numberOfAttempts > 100 Then
MsgBox "This is taking too long, try again later."
Exit Do
End If
Loop
You may want to add an iterator/counter as I have done there and simulate a timeout otherwise this could potentially go in to an infinite loop.
Thanks for all the great tips going to implement plenty of them. The true error behind this was a Windows settings. UAC :
http://windows.microsoft.com/en-us/windows7/products/features/user-account-control
Setting it down to the bottom "never notify" fixed it immediately.
Related
Hi: I'm using excel to get values from this webpage: https://www2.agenciatributaria.gob.es/es13/h/iexmmmfi.html
How can I get the code for excel VBA to get the fiels for NIF, EJF, MOD and CEL?
I tried with getelementbyid("NIF") and "name" but with no results
Thanks!
Previos thread: Excel VBA: Get inner text of HTML table td
This is the code I use:
Sub AEAT()
Dim IE As Object
Application.ScreenUpdating = False
Set IE = CreateObject("InternetExplorer.Application")
IE.Navigate "https://www2.agenciatributaria.gob.es/es13/h/iexmmmfi.html"
Application.Wait (Now + TimeValue("0:00:02"))
IE.Document.getElementById("NIF").Value = Range("A1").Value
Application.Wait (Now + TimeValue("0:00:01"))
IE.Document.getElementById("EJF").Value = "2016"
Application.Wait (Now + TimeValue("0:00:01"))
IE.Document.getElementById("MOD").Value = "347"
Application.Wait (Now + TimeValue("0:00:01"))
IE.Document.getElementById("CEL").Value = Range("a4").Value
Application.Wait (Now + TimeValue("0:00:01"))
IE.Document.getElementById("env_button").Click
End Sub
Okie, so I don't have a Excel in Windows VM, so I tested your code using VBScript. So the solution should work. You have 3 problems
Navigate doesn't wait for Page for to load
Your site installs a ActiveX control, which needs to be loaded first
Even when you fix #1 and #2, you will get an exception "The client disconnected" and the object will not be usable anymore
Solution
Add the site to Trusted Sites in your IE Setting.
Open IE manually and install the ActiveX control
Sub AEAT()
Dim IE
Set IE = CreateObject("InternetExplorer.Application")
IE.visible = True
hwnd = ie.hwnd
IE.Navigate "https://www2.agenciatributaria.gob.es/es13/h/iexmmmfi.html"
msgbox ("wait")
Set oShell = CreateObject("Shell.Application")
For Each Wnd In oShell.Windows
If hwnd = Wnd.hwnd Then Set ie = Wnd
Next
IE.Document.getElementById("NIF").Value = "123"
End Sub
Call AEAT
I have put msgbox to insert wait for now, but you can fix that yourself by using below in excel
Do
DoEvents
Loop Until ie.ReadyState = READYSTATE_COMPLETE
PS: reference from below URLs
Internet Explorer VBA Automation Error: The object Invoked has disconnected from its clients
Error "The object invoked has disconnected from its clients" - automate IE 8 with python and win32com
I'm currently trying to select a file to upload automatically on a website using VBA. I am stuck at the file choice, when the file browser windows pops up. Using SendKeys I try to send the full path the the file I'm trying to upload (filepath1, it is pretty long), but the SendKeys function only ever returns half of the string path or so, and doesn't respect the enter commands. The SendKeys function also works one time of out two.. leaving the search bar empty from time to time. I've seen a lot of people complaining about this on the net but no other solution then to pause the application between calls, which is what I did.
I've used Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) in a module to define the Sleep 1 calls.
Can anyone help me out here? Any help will be much appreciated thank you!
Sub GenerateKML_Macro()
' GenerateKML Macro
Dim IE As New InternetExplorer
Dim ExplorerInput As HTMLInputElement
Dim ExplorerButton As Object
Dim IEDoc As HTMLDocument
Dim NextThingy As Object
Dim iBox As HTMLIFrame
Dim iframeDoc As HTMLDocument
Dim filepath1 As Variant
Dim name_of_file As Variant
filepath1 = "...\Excel_Template\Template.xlsx"
name_of_file = "Template.xlsx"
'Load
IE.navigate "https://www.earthpoint.us/ExcelToKml.aspx"
'Show
IE.Visible = True
'Wait
WaitIE IE
'Select document
Set IEDoc = IE.document
WaitIE IE
Set iBox = IEDoc.all("iframe1")
Set iframeDoc = iBox.contentDocument
Set ExplorerButton = iframeDoc.all.Item("FileUpload1")
'ExplorerButton.Click
Sleep 1
ExplorerButton.Focus 'can't set ExplorerButton.value directly for security reasons
Sleep 1
Application.Wait Now
Sleep 1
SendKeys (filepath1)
Sleep 1
SendKeys ("{ENTER}")
Sleep 1
SendKeys (name_of_file)
Sleep 1
SendKeys ("{ENTER}")
Sleep 1
'Wait
WaitIE IE
'Close
'IE.Quit
'Unload
Set IE = Nothing
End Sub
Sub WaitIE(IE As InternetExplorer)
'Loop until page is loaded
Do Until IE.readyState = READYSTATE_COMPLETE
DoEvents
Loop
End Sub
Ps: However many times I ran the application the SendKeys never managed to select the Template.xlsx file I'm trying to reach. I devided the search path in two variable to make it clearer, but nothing came out of it.
I'm looking for a code to put values from an Excel to a Webpage.
Sub FillInternetForm()
Dim IE As Object
Set IE = CreateObject("InternetExplorer.Application")
IE.navigate "http://xxxxxxxx/"
IE.Visible = True
While IE.Busy
DoEvents
Wend
IE.document.getElementById("xxxxx").Value = "xxxx"
End Sub
The error comes in on IE.document.getElementById("xxxxx").Value = "xxxx line and it says Method 'Document' of object 'IWebBrowser 2' failed.
I'm looking for suggstions to solve this question: I made a lot of research and nothing works :/
Thanks in advance :)
Ana,
Here is a working example. You can easily customized this little bit of code to work for you. One time you must be aware of is that I added a reference to my project under TOOLS -> Preferences -> Microsoft Internet Controls. Also another word of caution is on this line Set Elements on this line, if you are looking for something that does not exists you will end up with an error. This working example I put together goes to stack overflow and finds the elements below footer-menu.
Let me know if something does not make sense.
Sub TryInternetExplorer()
'Reference to system32\shdocvw.dll 'Microsoft Internet Controls
Dim IEApp As InternetExplorer
Set IEApp = New InternetExplorer
IEApp.Visible = True
IEApp.Navigate "https://iam.pearson.com/auth/XUI/#login/"
While IEApp.ReadyState <> READYSTATE_COMPLETE And IEApp.ReadyState <> READYSTATE_LOADED
DoEvents
Wend
'wait for the form to load
Do
Set form = IEApp.Document.getElementsByTagName("FORM")(0) '1st table
DoEvents
Loop While form Is Nothing
IEApp.Document.getElementsByName("callback_0")(0).Value = "Miguel"
IEApp.Document.getElementsByName("callback_1")(0).Value = "pass"
IEApp.Document.getElementsByName("callback_2")(0).Click
Set Document = Nothing
Set IEApp = Nothing
End Sub
In order to fix the following code, I tried to split it up into a smaller part. So, I have the following code that drives me crazy for hours in Sheet1:
Sub Scrapping_Data()
Dim IE As Object, EURUSD1 As String, EURUSD2 As String
Application.ScreenUpdating = False
Range("A:B").Clear
Set IE = CreateObject("internetexplorer.application")
With IE
.Navigate "http://uk.investing.com/currencies/streaming-forex-rates-majors"
.Visible = False
End With
Do
DoEvents
Loop Until IE.readyState = READYSTATE_COMPLETE
Set FOREX = IE.document.getElementById("pair_1")
EURUSD1 = FOREX.Cells(1).innerHTML
EURUSD2 = FOREX.Cells(2).innerHTML
IE.Quit
Set IE = Nothing
Range("A1").Value = EURUSD1
Range("B1").Value = EURUSD2
End Sub
I run it for the first time and it worked fine. But when I run it for the second time, the error the run-time error '91' occurred. So I clicked F8, but nothing happened the code worked fine and I checked Sheet1 there were values in Cells(1,1) and Cells(1,2). I then run it again and the error the run-time error '13' occurred this time. Again I clicked F8, but nothing happened the code worked fine. When I kept running the code, the errors still occurred and clicking F8 didn't help to find the problem. What is wrong with my code? How to fix it?
What I don't get it here too is my laptop is getting slow every time I run the code and I have to manually restart it many times.
The following requires that you go into the VBE's Tools ► References and place checkmarks beside Microsoft HTML Object library and Microsoft XML v6.0.
This is an xmlhttprewuest equivalent of an Internet Explorer object web scrape to the same URL.
Option Explicit
Sub tournamentFixtures()
'declare the objects with early binding
Dim htmlBDY As New HTMLDocument, xmlHTTP As New MSXML2.XMLHTTP60
'declare the regular variables
Dim sURL As String, ws As Worksheet
'set a var object to the destination worksheet
Set ws = Worksheets("Sheet1")
'assign the URL to a string var
sURL = "http://uk.investing.com/currencies/streaming-forex-rates-majors"
'isolate all commands to the MSXML2.XMLHTTP60 object
With xmlHTTP
'initiate the URL
.Open "GET", sURL, False
'set hidden header information
.setRequestHeader "User-Agent", "XMLHTTP/1.0"
'get the page data
.send
'safety check to make sure we got the web page's data
If .Status <> 200 Then GoTo bm_safe_Exit
'if here you got the page data - copy it to the local var
htmlBDY.body.innerHTML = .responseText
End With
'localize all commands to the page data
With htmlBDY
'check if the element ID exists
If Not .getElementById("pair_1") Is Nothing Then
'it exists - get the data directly to the worksheet
With .getElementById("pair_1")
ws.Range("A1") = .Cells(1).innerText
ws.Range("B1") = .Cells(2).innerText
End With
Else
'it doesn't exist - bad page data
MsgBox "there is no 'pair_1' on this page"
End If
End With
bm_safe_Exit:
'clean up all of the objects that were instantiated
Set htmlBDY = Nothing: Set xmlHTTP = Nothing: Set ws = Nothing
End Sub
I have commented virtually every line so you can follow what is happening. This may need some tweaking. I ran it ~40 times and it failed once but that could have been my own Internet connection. Consider this a starting point where you can do your own research to accomplish your goals. If you continue to have problems with this new code, please do not paste this into another question and ask why it doesn't work without doing some research and attempting a solution yourself. StackOverflow is a site for professional and enthusiast programmers.
I gave up trying to offer solutions to web scraping problems because page technology changes too fast to keep up on a peripheral level. You have to be involved in the immediate changes to be able to respond to them quickly and my own interests lie elsewhere. I responded to this request because you actually supplied the URL to test against (something few people asking questions actually think is important - go figure) and I thought the static dimming of the var would help.
The construction and destruction of an InternetExplorer object takes time; up to a few seconds even on the fastest sytems. You can wait an appropriate amount of time for it to relinquish all of the .DLLs et al it has loaded or you can declare your IE as a static object that will be reused on subsequent reruns of the sub procedure.
Option Explicit
Sub Scrapping_Data()
Static IE As Object
Dim EURUSD1 As String, EURUSD2 As String
Application.ScreenUpdating = False
With Worksheets("Sheet1") 'KNOW what worksheet you are on!!!!!
.Range("A:B").Clear
End With
If IE Is Nothing Then
Set IE = CreateObject("internetexplorer.application")
With IE
.Visible = True
'.Visible = False
.Silent = True
End With
End If
With IE
.Navigate "http://uk.investing.com/currencies/streaming-forex-rates-majors"
Do While .ReadyState <> 4: DoEvents: Loop
With .document.getElementById("pair_1")
EURUSD1 = .Cells(1).innerHTML
EURUSD2 = .Cells(2).innerHTML
End With
End With
With Worksheets("Sheet1") 'KNOW what worksheet you are on!!!!!
.Range("A1") = EURUSD1
.Range("B1") = EURUSD2
End With
IE.Navigate "about:blank"
End Sub
The caveat here is that you will have to destruct the InternetExplorer object yourself at some point in the future. Closing the workbook will close the VBA project but leave the IE object 'orphaned'.
Given all of the HTML5 debris that comes along with that web page, have you considered moving to xmlhttprequest? And if you are wondering then yes, that would be a new question under a different set of [tags].
I'm trying to collect data from a website, which should be manageable once the source is in string form. Looking around I've assembled some possible solutions but have run into problems with all of them:
Use InternetExplorer.Application to open the url and then access the inner HTML
Inet
use Shell command to run wget
Here are the problems I'm having:
When I store the innerHTML into a string, it's not the entire source, only a fraction
ActiveX does not allow the creation of the Inet object (error 429)
I've got the htm into a folder on my computer, how do I get it into a string in VBA?
Code for 1:
Sub getData()
Dim url As String, ie As Object, state As Integer
Dim text As Variant, startS As Integer, endS As Integer
Set ie = CreateObject("InternetExplorer.Application")
ie.Visible = 0
url = "http://www.eoddata.com/stockquote/NASDAQ/AAPL.htm"
ie.Navigate url
state = 0
Do Until state = 4
DoEvents
state = ie.readyState
Loop
text = ie.Document.Body.innerHTML
startS = InStr(ie.Document.Body.innerHTML, "7/26/2012")
endS = InStr(ie.Document.Body.innerHTML, "7/25/2012")
text = Mid(ie.Document.Body.innerHTML, startS, endS - startS)
MsgBox text
If I were trying to pull the opening price off from 08/10/12 off of that page, which is similar to what I assume you are doing, I'd do something like this:
Set ie = New InternetExplorer
With ie
.navigate "http://eoddata.com/stockquote/NASDAQ/AAPL.htm"
.Visible = False
While .Busy Or .readyState <> READYSTATE_COMPLETE
DoEvents
Wend
Set objHTML = .document
DoEvents
End With
Set elementONE = objHTML.getElementsByTagName("TD")
For i = 1 To elementONE.Length
elementTWO = elementONE.Item(i).innerText
If elementTWO = "08/10/12" Then
MsgBox (elementONE.Item(i + 1).innerText)
Exit For
End If
Next i
DoEvents
ie.Quit
DoEvents
Set ie = Nothing
You can modify this to run through the HTML and pull whatever data you want. Iteration +2 would return the high price, etc.
Since there are a lot of dates on that page you might also want to make it check that it is between the Recent End of Day Prices and the Company profile.