SendKey does not send full String in VBA (using IE) - html

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.

Related

Web Side Login / no debug.print shown in specific Window

I want to login a web side
After a lot of trial and errors I finally wrote a code that works pretty well.
.. but got probs
First I got a prob that occurs and said
no connection to server
This Prob I solved
Set ie = CreateObject("new:{D5E8041D-920F-45e9-B8FB-B1DEB82C6E5E}")
The next Prob is that when I ran the code Step by step (Trigger F8) the code runs pretty well.But Triggering F5 I got the Prob in Line
Set UserNameInput = LoginForm.getElementsByClassName("prePopulatedCredentials")(0)
This.. I do not understand
The next Prob is a debug.print "Prob"
Although I activated the Window (STR+G) debug.print is not shown.
Why want I see the debug Print result?
So.. I want to find out which Button I have to trigger by using the VBA Code
In my case I have 3 options
Search, new Search, go back or Sign In
For Sign In I found a solution for another web Side
Sub TestLogin()
Dim...
Dim LoginForm As MSHTML.HTMLFormElement
.. code
LoginForm.submit
For another Web Side
I want to find the buttons
Search, new Search, go back
The code is almost the same
Sub Get()
Dim...
Dim HTML Button AS MSHTML.IHTMLELEMENT
... Code
Set Buttons= HTMLDoc.GetElementsByTagName("button")
For Each HTMLButton In HTMLButtons
Debug.Print HTMLButton.className, HTMLButton.tagName, HTMLButton.Id, HTMLButton.innerText
Next Button
End Sub
In this case the code runs until the line
Set Buttons= HTMLDoc.GetElementsByTagName("button")
and it jumps over to End Sub
Here my Code for the first web side with the Prob Triggering the code with F8 or F5
Sub TestLogin()
Dim ie As SHDocVw.InternetExplorerMedium
Sub TestLogin()
Dim ie As SHDocVw.InternetExplorerMedium
Dim doc As MSHTML.HTMLDocument
Dim LoginForm As MSHTML.HTMLFormElement
Dim UserNameInput As MSHTML.HTMLInputElement
Dim PasswordInput As MSHTML.HTMLInputElement
Set ie = New SHDocVw.InternetExplorer
' Here I found a solution in the www regarding the Prob Net.Framework
Set ie = CreateObject("new:{D5E8041D-920F-45e9-B8FB-B1DEB82C6E5E}")
ie.Visible = True
ie.Navigate Sheet1.Range("B1").Text
Do While ie.ReadyState <> READYSSTATE_COMPLETE And ie.Busy
Loop
Set doc = ie.Document
Set LoginForm = doc.getElementById(Sheet1.Range("B4").Text)
Set UserNameInput = LoginForm.getElementsByClassName("prePopulatedCredentials")(0)
Set PasswordInput = LoginForm.getElementsByClassName("prePopulatedCredentials ")(1)
UserNameInput.Value = Sheet1.Range("B2").Text
PasswordInput.Value = Sheet1.Range("B3").Text
Stop
'LoginForm.submit
End Sub
An here the code for the 2nd Web Side with the Prob debug Print
Sub Get()
Dim ie As New SHDocVw.InternetExplorer
Dim HTMLDoc As MSHTML.HTMLDocument
Dim HTMLInput As MSHTML.IHTMLElement
Dim UserNameInput As MSHTML.HTMLInputElement
Dim VornameInput As MSHTML.HTMLInputElement
Dim HTMLButton As MSHTML.IHTMLElement
Dim HTMLButtons As MSHTML.IHTMLElementCollection
Dim SecurityWindow As Object
Set ie = New SHDocVw.InternetExplorer
Set ie = CreateObject("new:{D5E8041D-920F-45e9-B8FB-B1DEB82C6E5E}")
ie.Visible = True
ie.Navigate Tabelle1.Range("B1").Text
Do While ie.ReadyState <> READYSSTATE_COMPLETE And ie.Busy
Loop
Set HTMLDoc = ie.Document
Set UserNameInput = HTMLDoc.getElementById("sur")
Set VornameInput = HTMLDoc.getElementById("given")
UserNameInput.Value = Sheets1.Range("B2").Text
VornameInput.Value = Sheets1.Range("B3").Text
Stop
Set HTMLButtons = HTMLDoc.getElementsByTagName("btn")
For Each HTMLButton In HTMLButtons
Debug.Print HTMLButtons.className, HTMLButtons.tagName, HTMLButtons.ID, HTMLButtons.innerText
Next HTMLButton
End Sub
What have I done wrong or missed?
Thx for any help
And.. most important
Take all of you care
Best wishes, stay safe and healthy!
Pete
For your first issue:
It looks like a timing-related issue.
I suggest you make your code wait for some seconds before executing the problematic line of code.
It can help to fetch the value and solve this issue.
For your second issue:
As I informed you in my previous comment, you can create a new thread with detailed information. We will try to check it and try to provide you further suggestions for it.

VBA - losing control of internet exploror

I have a function that loads a website prompting a user to login. This works on everyone's computers except one person and I cannot figure it out. I get a runtime error on the line Do Until ieApp.ReadyState = 4: DoEvents: Loop that reads "Automation error. The object invoked has disconnected from its clients."
Function Firewall_Login() As Boolean
Dim ieApp As Object
Dim ieDoc As Object
Dim ieTable As Object
Dim ieDocResult As Object
Dim start_time
Set ieApp = CreateObject("internetexplorer.application")
start_time = Now()
ieApp.Navigate "http://awebsite.com/"
Do While ieApp.ReadyState = 4: DoEvents: Loop
Do Until ieApp.ReadyState = 4: DoEvents: Loop 'errors here just on the one computer
Set ieDoc = ieApp.Document
...
'do some stuff
...
ieDoc.Close
Set ieDoc = Nothing
ieApp.Quit
Set ieApp = Nothing
Firewall_Login = True
End Function
Seems like the object ieApp simply loses the instance of IE and can't do anything. Anyone have any suggestions?
All users are on the same version of IE -- 11.0.9600.18816
This code is taken from my blog. The code loops through shell windows looking to match the title bar which for IE will be the url. This way the reference is reacquired. Sometimes the reference can be lost due to a change of security zone etc.
Option Explicit
'* Tools - References
'* MSHTML Microsoft HTML Object Library C:\Windows\SysWOW64\mshtml.tlb
'* SHDocVw Microsoft Internet Controls C:\Windows\SysWOW64\ieframe.dll
'* Shell32 Microsoft Shell Controls And Automation C:\Windows\SysWOW64\shell32.dll
Private Function ReacquireInternetExplorer(ByVal sMatch As String) As Object
Dim oShell As Shell32.Shell: Set oShell = New Shell32.Shell
Dim wins As Object: Set wins = oShell.Windows
Dim winLoop As Variant
For Each winLoop In oShell.Windows
If "C:\Program Files (x86)\Internet Explorer\IEXPLORE.EXE" = winLoop.FullName Then
Dim sFile2 As String
sFile2 = "file:///" & VBA.Replace(sMatch, "\", "/")
If StrComp(sFile2, winLoop.LocationURL, vbTextCompare) = 0 Then
Set ReacquireInternetExplorer = winLoop.Application
GoTo SingleExit
End If
End If
Next
SingleExit:
End Function

VBA - problems with getting html from a website after hitting submit button

I am trying to scrap data out of a section of a webpage. To get into the section I need to fill in a captcha security code and hit a button, but that is alright because the security code is actually written in the html of the page. So, I am creating an IE object, driving it to the webpage, getting the captcha security code, writing it in the proper box, hitting the submit button and then getting the html document so I can scrap data out of it.
Nonetheless I am executing the steps exatcly in the order I mentioned, it seems that the html document that is being gotten is not the one from the page after I pass through the captcha validation, but from the page before the captcha validation.
Would anyone know what must I do to get the correct html document and conseuently be able to scrap the data I really want? Thank you.
The subprocedure's code follows next:
'Getting National fuel prices from ANP
Sub subANPNationalFuelPrices()
'Creating variables for the URL and the HTML files
Dim urlANP As String: urlANP = "http://www.anp.gov.br/preco/prc/Resumo_Semanal_Index.asp"
Dim htmlANP1 As HTMLDocument
'Creating the IE object
Dim IE As InternetExplorer
Set IE = New InternetExplorer
IE.Visible = True
'Making sure that the webpage is fully load
IE.navigate (urlANP)
Do While IE.readyState <> READYSTATE_COMPLETE
Application.StatusBar = "Getting your data"
DoEvents
Loop
Set htmlANP1 = IE.document
'Getting the Captcha Password
Dim strCaptchaPassword As String
Dim colMyCollection As IHTMLElementCollection
Set colMyCollection = htmlANP1.getElementById("divQuadro").all
Dim objLabel As IHTMLElement
For Each objLabel In colMyCollection
strCaptchaPassword = strCaptchaPassword & objLabel.innerText
Next objLabel
'Getting the input box object and getting it the correct password
Dim objInputBox As IHTMLElement
Set objInputBox = htmlANP1.getElementById("txtValor")
objInputBox.Value = strCaptchaPassword
'Getting the submit button object and clicking it
Dim objInputButton As IHTMLElement
Set objInputButton = htmlANP1.getElementById("image1")
objInputButton.Click
'Getting the true rich data HTML
Set htmlANP1 = IE.document
'Extracting the data from the html document
Dim rngValues As range: Set rngValues = Sheet1.range("B17")
Dim strValues(35) As String
Dim dblValues(35) As Double
Dim objElement1 As IHTMLElement
Set objElement1 = htmlANP1.getElementsByTagName("TABLE")(1)
Dim colCollection1 As IHTMLElementCollection
Set colCollection1 = objElement1.all
Dim intTempCount As Integer
Dim objTempElement As IHTMLElement
intTempCount = 32
For Each objTempElement In colCollection1
Sheet1.Cells(intTempCount, 3) = objTempElement.tagName
Sheet1.Cells(intTempCount, 4) = objTempElement.innerText
intTempCount = intTempCount + 1
Next objTempElement
End sub
You are not waiting for the new webpage to load after clicking the button on the captcha. Either check the ready state of IE again or end you code here be starting a timer which starts your code off again in X seconds AND then checks the ready state of IE and Document.
I do scraping on a system using iFrame so using IE.Readystate isn't very reliable. Usually I have to wait for another element to 'exist', but using IsObject(element) hasn't been very reliable either. What I've had to do is use a loop in my main code that calls a function so if I'm waiting for something to load and I know that after the page loads, there's an element with the ID "UserName", then I do this..
...
Do Until IsErr(doc, "UserName") = False: Loop
...
Function IsErr(doc As HTMLDocument, ID As String) As Boolean
IsErr = True
On Error GoTo ExitFunction:
Debug.Print left(doc.getElementById(ID).innerHTML, 1)
IsErr = False
Exit Function
ExitFunction:
End Function
I could just do a loop statement that keeps trying to debug it, but that would be a nightmare with the error handling so if you use a separate function for the printing, it can exit the function after the error, then the loop re-initiates the function and it will do this forever until the next element exists.

VBA HTML not running on all computers

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.

HTML Page Title in Excel VBA

Given an url, how can I get the title of the html page in VBA in Excel?
For example suppose I have three urls like :
http://url1.com/somepage.html
http://url2.com/page.html
http://url3.com/page.html
Now I need to get the title of these html pages in another column. How do I do it?
Remou's answer was VERY helpful for me, but it caused a problem: It doesn't close the Internet Explorer process, so since I needed to run this dozens of times I ended up with too many IEs open, and my computer couldn't handle this.
So just add
wb.Quit
and everything will be fine.
This is the code that works for me:
Function GetTitleFromURL(sURL As String)
Dim wb As Object
Dim doc As Object
Set wb = CreateObject("InternetExplorer.Application")
wb.Navigate sURL
While wb.Busy
DoEvents
Wend
GetTitleFromURL = wb.Document.Title
wb.Quit
Set wb = Nothing
End Function
I am not sure what you mean by title, but here is an idea:
Dim wb As Object
Dim doc As Object
Dim sURL As String
Set wb = CreateObject("InternetExplorer.Application")
sURL = "http://lessthandot.com"
wb.Navigate sURL
While wb.Busy
DoEvents
Wend
''HTML Document
Set doc = wb.document
''Title
Debug.Print doc.Title
Set wb = Nothing
if you use Selenium :
Sub Get_Title()
Dim driver As New WebDriver
debug.print driver.Title
End Sub