Automate editing a field that takes value from a suggester - vba

I tried automating a task on my CRM (using VBA on IE) where there is a field that prompts a suggester as soon as you start typing in it. Even if I enter the exact intended text, the script doesn't save the changes.
Here is the HTML code of the field to be edited:
<input class="itext" size="40" id="txtStrPoblacion" onkeyup="searchPoblacion(this.form, true);" autocomplete="off" value="Sector 14, Gurgaon, Gurgaon" type="text">
And, here is the script that I wrote:
Sub L3()
Dim IE As Object
Dim i As Long
Dim doc As HTMLDocument
Dim oHTML_Element As IHTMLElement
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
For i = 2 To 2
IE.navigate "https://in.nuptic.com/admin/admin-ModificarEmpresa.php?id_empresa=" + Cells(i, 2)
Do While IE.Busy
Application.Wait DateAdd("s", 1, Now)
Loop
Set doc = IE.document
doc.getElementById("txtStrPoblacion").Value = Cells(i, 3)
With IE.document
Set elems = .getElementsByTagName("input")
For Each e In elems
If (e.getAttribute("value") = "Save") Then
e.Click
Exit For
End If
Next e
End With
Next
MsgBox "Done"
End Sub

Related

VBA - Error 438 trying to automate website login

The program is trying to identify the login area.
The problem is that in the script of the web page there is no ID to refer to so I tried to get elements by Name but it doesn't work.
Sub test()
Dim IE As Object
Set IE = CreateObject("InternetExplorer.application")
IE.Visible = True
IE.navigate "https://freebitcoin.io"
Do While IE.Busy
Application.Wait DateAdd("s", 1, Now)
Loop
IE.document.getElementByName("email").Value = "tarnone#outlook.com"
End Sub
I have message "error 438 "object doesn't support this property or method"
There are a few elements with that class name - form-control email, thus the 0-th one is the one needed. And then with .Value the email could be set:
Sub TestMe()
Dim IE As Object
Set IE = CreateObject("InternetExplorer.Application")
IE.Visible = True
IE.Navigate "https://freebitcoin.io"
Do While IE.Busy
Application.Wait DateAdd("s", 1, Now)
Loop
Dim someElement As Object
Set someElement = IE.document.getElementsByClassName("form-control email")
someElement(0).Value = "mail#some.mail"
End Sub

I'm having trouble scraping this

I'm trying to understand why my references arent working well to scrape this data.
Here is the site as an example:
http://quote.morningstar.ca/Quicktakes/Financials/is.aspx?t=GNTX&region=USA&culture=en-CA&ops=clear
And as a target:
<div id="data_i6" class="rf_crow"><div id="Y_1" class="pos column6Width_noChart116px" style="overflow:hidden;white-space: nowrap;" rawvalue="741131269">741</div><div id="Y_2" class="pos column6Width_noChart116px" style="overflow:hidden;white-space: nowrap;" rawvalue="836611464">837</div><div id="Y_3" class="pos column6Width_noChart116px" style="overflow:hidden;white-space: nowrap;" rawvalue="939841654">940</div><div id="Y_4" class="pos column6Width_noChart116px" style="overflow:hidden;white-space: nowrap;" rawvalue="1010472512">1,010</div><div id="Y_5" class="pos column6Width_noChart116px" style="overflow:hidden;white-space: nowrap;" rawvalue="1100344312">1,100</div><div id="Y_6" class="pos column6Width_noChart116px" style="overflow:hidden;white-space: nowrap;" rawvalue="1115401551">1,115</div></div>
What I need to extract is the actual value in rawvalue="741131269" and the following is what I've gotten to work so far.
'Cells(1, 1) = Document.getElementsByClassName("rf_crow")'returns the rows of data into one cell
'Cells(1, 1) = Document.getElementById("Y_1").innerText 'returns the text for the year
'Cells(1, 1) = Document.getElementById("data_i1").innerText 'returns to first row of data
I know the above doesn't return what I want, because the comment tells you what it extracts into Excel. The sub-element doesn't seem to work as it does in other macros I've built. I thought something like this would work:
Cells(1, 1) = Document.getElementById("Y_1").getAttribute("rawvalue")
but that doesn't work, also, I tried:
Cells(1, 1) = Document.getElementById("data_i6").getElementById("Y_1").innertext
and that doesn't work either.
The solution is very easy. Just call it using it's attribute which is `rawvalue.
This is how you can go:
Using Hardcoded delay and for loop to check the availability of the desired value:
Sub GetValue()
Dim IE As New InternetExplorer, HTML As HTMLDocument, post As Object, elem As Object
With IE
.Visible = True
.Navigate "http://quote.morningstar.ca/Quicktakes/Financials/is.aspx?t=GNTX&region=USA&culture=en-CA&ops=clear"
While .Busy = True Or .ReadyState < 4: DoEvents: Wend
Set HTML = .Document
End With
''using hardcoded delay
Application.Wait Now + TimeValue("00:00:05")
For Each elem In HTML.getElementsByTagName("div")
If elem.innerText = "741" Then MsgBox elem.getAttribute("rawvalue"): Exit For
Next elem
End Sub
Using Explicit Wait:
Sub GetValue()
Dim IE As New InternetExplorer, HTML As HTMLDocument, post As Object
With IE
.Visible = True
.Navigate "http://quote.morningstar.ca/Quicktakes/Financials/is.aspx?t=GNTX&region=USA&culture=en-CA&ops=clear"
While .Busy = True Or .ReadyState < 4: DoEvents: Wend
Set HTML = .Document
End With
Do: Set post = HTML.querySelector("#data_i6 #Y_1"): DoEvents: Loop While post Is Nothing
MsgBox post.getAttribute("rawvalue")
End Sub
Output at this moment:
741131269
The following should illuminate some of the problems you were having.
.querySelectorAll
The exact element you mention is the second index returned by .querySelectorAll method of .document using the CSS selector #Y_1. The # means Id.
From that webpage it returns the following (sample shown - not all):
From the above you can see the string you want is returned by the index of 2 in the result.
querySelectorAll with Id? Isn't Id a unique identifier for a single element?
This Id, unexpectedly, is not unique to a single element on the page. It occurs a whopping 27 times:
This means you can use the .querySelectorAll method to return a nodeList of all matching items and take the item at index 2 to get your result.
Note:
If you want the long number next to rawvalue, 741131269, then parse the outerHTML of the returned element.
Debug.Print Replace(Split(Split(a.item(2).outerHTML, "rawvalue=")(1), ">")(0), Chr$(34), vbNullString)
.querySelector
Alternatively, you can target the id which is specific data_i6 with
.document.querySelector("#data_i6")
This CSS selector (#data_i6) returns the entire row as it has each year within. If using .querySelector you will only get the first item anyway which is year 1.
You can be more specific with the CSS selector and add the additional year Id to get just the year of interest:
#data_i6 #Y_1
Code: (querySelector method commented out next to querySelectorAll)
Option Explicit
Public Sub Get_Information()
Dim IE As New InternetExplorer
With IE
.Visible = True
.navigate "http://quote.morningstar.ca/Quicktakes/Financials/is.aspx?t=GNTX&region=USA&culture=en-CA&ops=clear"
While .Busy = True Or .readyState < 4: DoEvents: Wend
Dim a As Object, exitTime As Date
exitTime = Now + TimeSerial(0, 0, 2)
Do
DoEvents
On Error Resume Next
Set a = .document.querySelectorAll("#Y_1") ' .document.querySelector("#data_i6 #Y_1")
On Error GoTo 0
If Now > exitTime Then Exit Do
Loop While a Is Nothing
If a Is Nothing Then Exit Sub
Debug.Print Split(Split(a.item(2).innerText, "rawvalue=")(0), ">")(0) 'Split(Split(a.innerText, "rawvalue=")(0), ">")(0)
Debug.Print Replace(Split(Split(a.item(2).outerHTML, "rawvalue=")(1), ">")(0), Chr$(34), vbNullString) 'Replace(Split(Split(a.outerHTML, "rawvalue=")(1), ">")(0), Chr$(34), vbNullString)
.Quit
End With
End Sub
Try and declare "objCollection" as an object, strValue as string, and in the code below, replace in the first line the name of the http-request you declared:
Document.body.innerHTML = YourHTTPRequest.responseText
Set objCollection = Document.getElementsByClassName("rf_crow")
For Each objElement In objCollection
If objElement.ID = "Y_1" Then
strValue = objElement.getAttribute("rawvalue")
Exit For
End If
Next
Cells(1, 1) = strValue
Does this work for you?
Sub web_table_option_two()
Dim HTMLDoc As New HTMLDocument
Dim objTable As Object
Dim lRow As Long
Dim lngTable As Long
Dim lngRow As Long
Dim lngCol As Long
Dim ActRw As Long
Dim objIE As InternetExplorer
Set objIE = New InternetExplorer
objIE.Navigate "http://quote.morningstar.ca/Quicktakes/Financials/is.aspx?t=GNTX&region=USA&culture=en-CA&ops=clear"
Do Until objIE.ReadyState = 4 And Not objIE.Busy
DoEvents
Loop
Application.Wait (Now + TimeValue("0:00:03")) 'wait for java script to load
HTMLDoc.body.innerHTML = objIE.Document.body.innerHTML
With HTMLDoc.body
Set objTable = .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 With
objIE.Quit
End Sub

Issue with clicking on an img button by using alt in IE

I am currently trying to click on a specific img button on a site that does not have an Id so I am trying to click based on the alt. Below is from the DOM Explorer, the alt is in Japanese characters.
<a href="/e-navi/members/statement/index.xhtml?tabNo=0">
<img width="112" height="23" alt="翌月以降" src="https://image.card.jp.rakuten-static.com/r-enavi/WebImages/enavi/common/tab05_after_o.gif">
</a>
The code I am using to try and click the link is:
pUnicodeString = ChrW(32716) & ChrW(26376) & ChrW(20197) & ChrW(38477)
Set tags = ie.document.getElementsByTagName("a")
For Each tagx In tags
If tagx.getAttribute("alt") = pUnicodeString Then
tagx.Click
End If
Next
NOTE: I have also tried it with Set tags = ie.document.getElementsByTagName("img") as well.
When running the code I get the "Permission Denied" error on If tagx.getAttribute("alt") = pUnicodeString Then.
I have been searching on many sites and have tried many peoples past examples but none worked. Below is my full code for reference.
Sub csvfetch()
Dim ie As SHDocVw.InternetExplorer
Dim doc As MSHTML.HTMLDocument
Dim div As HTMLDivElement
Dim url As String
Dim form As Variant
Dim button As Variant
Dim tags As Object
Dim tagx As Object
url = "https://www.rakuten-card.co.jp/e-navi/?l-id=corp_de_enavi_index_001"
Set ie = New SHDocVw.InternetExplorer
With ie
.Visible = True
.navigate url
While .Busy
DoEvents
Wend
End With
While ie.Busy
DoEvents
Wend
Application.Wait (Now + TimeValue("0:00:02"))
'temp user/pass
user = Sheets("Pass").Cells(2, 2)
pass = Sheets("Pass").Cells(2, 3)
ie.document.getElementById("u").Value = user
ie.document.getElementById("p").Value = pass
'login
Set form = ie.document.getElementsByTagName("form")
Set button = form(0).onsubmit
form(0).submit
While ie.Busy
DoEvents
Wend
Set ElementCol = ie.document.getElementsByClassName("rf-button-alt rce-white-button rf-mini")
ElementCol.Item(0).Click
While ie.Busy
DoEvents
Wend
pUnicodeString = ChrW(32716) & ChrW(26376) & ChrW(20197) & ChrW(38477)
Set tags = ie.document.getElementsByTagName("a")
For Each tagx In tags
If tagx.getAttribute("alt") = pUnicodeString Then
tagx.Click
End If
Next
Set ie = Nothing
'Unload UserForm1
End Sub

Automate clicking buttons on one page and then another page using vba

I am trying to work on something that clicks a button\line on a page, then clicks on others when the new page loads. I can get my vba to click the first button/link, but then when trying to click the next I am getting the error
Run-time error 91: Object variable or With block variable not set
Now I have to be honest, the code I do have is from research, and by no means do I understand it fully, I have searched all over trying to rectify the 2nd click, but nothing seems to be working.
the code I have so far is
Public Sub SHAREREPORTING()
Dim IE As SHDocVw.InternetExplorer
Dim Button As Object
Dim Button2 As Object
Set IE = New InternetExplorerMedium
IE.Visible = True
IE.navigate "URL"
Do While IE.ReadyState <> READYSTATE_COMPLETE Or IE.Busy: DoEvents: Loop
Set Button = IE.Document.getElementById("b1_pki")
Button.Click
Application.Wait (Now + TimeValue("0:00:05"))
SendKeys "mypassword" , True
SendKeys "{ENTER}", True
Do While IE.ReadyState <> READYSTATE_COMPLETE Or IE.Busy: DoEvents: Loop
Set Button2 = IE.Document.getElementById("seite-itm-2")
Application.Wait (Now + TimeValue("0:00:05"))
Button2.Click
End Sub
the code for the 2 buttons ( I am calling them buttons/links, because I'm not too sure what they are, I don't understand javascript) I am trying to click at the moment is
Button1/Link1
<A onclick=loginViaPKI(); onkeypress=loginViaPKI(); id=b1_pki title="Log on with PKI - Button - To activate, press spacebar." class=urBtnEmph hideFocus style="WHITE-SPACE: nowrap" href="javascript:void(0);" ct="Button">Log on with PKI</A>
Button2/Link2
<TD onclick="return htmlbSL(this,7,'seite:sel_tab_2','','3','sel_tab_2')" id=seite-itm-2 class=urTbsLabelOff onkeydown="if (sapUrMapi_checkKey(event,'keydown',new Array('32'))){return htmlbSL(this,7,'seite:sel_tab_2','','3','sel_tab_2')};sapUrMapi_TabStrip_keySelect('seite',2,4,event);" noWrap><SPAN id=seite-itm-2-txt title="Bookmarks " class=urTbsTxtOff>Bookmarks </SPAN></TD>
The program requires references to the following:
1 Microsoft Internet Controls
2. Microsoft HTML Object Library
The Internet control is used to browse the webpage and the HTML Objects are used to identify the username and password textboxes and submit the text using the control button.
Dim HTMLDoc As HTMLDocument
Dim oBrowser As InternetExplorer
Sub Login_2_Website()
Dim oHTML_Element As IHTMLElement
Dim sURL As String
On Error GoTo Err_Clear
sURL = "https://www.google.com/accounts/Login"
Set oBrowser = New InternetExplorer
oBrowser.Silent = True
oBrowser.timeout = 60
oBrowser.navigate sURL
oBrowser.Visible = True
Do
' Wait till the Browser is loaded
Loop Until oBrowser.readyState = READYSTATE_COMPLETE
Set HTMLDoc = oBrowser.Document
HTMLDoc.all.Email.Value = "sample#vbadud.com"
HTMLDoc.all.passwd.Value = "*****"
For Each oHTML_Element In HTMLDoc.getElementsByTagName("input")
If oHTML_Element.Type = "submit" Then oHTML_Element.Click: Exit For
Next
' oBrowser.Refresh ' Refresh If Needed
Err_Clear:
If Err <> 0 Then
Debug.Assert Err = 0
Err.Clear
Resume Next
End If
End Sub

Use VBA to list all URL address of a web page

I used the below code for loading the web site http://www.flashscore.com/soccer/england/premier-league/results/.
After I found and click on the "Show more matches" link, all the football matches are loaded in the browser.
The below code will give as results only the first half of matches, the events showed before pressing the "Show more matches" link.
My question is how can I list all the events URL adress?
Sub Test_Flashscore()
Dim URL As String
Dim ie As New InternetExplorer
Dim HTMLdoc As HTMLDocument
Dim dictObj As Object: Set dictObj = CreateObject("Scripting.Dictionary")
Dim tRowID As String
URL = "http://www.flashscore.com/soccer/england/premier-league/results/"
With ie
.navigate URL
.Visible = True
Do Until .readyState = READYSTATE_COMPLETE: DoEvents: Loop
Set HTMLdoc = .document
End With
For Each objLink In ie.document.getElementsByTagName("a")
If Left(objLink.innerText, 4) = "Show" Or Left(objLink.innerText, 4) = "Arat" Then
MsgBox "The link was founded!"
objLink.Click
Exit For
End If
Next objLink
With HTMLdoc
Set tblSet = .getElementById("fs-results")
Set mTbl = tblSet.getElementsByTagName("tbody")(0)
Set tRows = mTbl.getElementsByTagName("tr")
With dictObj
'If if value is not yet in dictionary, store it.
For Each tRow In tRows
'Remove the first four (4) characters.
tRowID = Mid(tRow.ID, 5)
If Not .Exists(tRowID) Then
.add tRowID, Empty
End If
Next tRow
End With
End With
i = 14
For Each Key In dictObj
ActiveSheet.Cells(i, 2) = "http://www.flashscore.com/" & Key & "/#match-summary"
i = i + 1
Next Key
Set ie = Nothing
MsgBox "Process Completed"
End Sub
You need to wait a little while for the rest of the content to load - clicking the link fires off a GET request to the server, so that needs to return content and the content needs to be rendered on the page before you can grab it.
Clicking on that link takes you to fixtures. You can replace all that before dictionary with
.navigate "https://www.flashscore.com/football/england/premier-league/fixtures/"
That is:
Option Explicit
Public Sub GetInfo()
Dim IE As New InternetExplorer
With IE
.Visible = True
.navigate "https://www.flashscore.com/football/england/premier-league/fixtures/"
While .Busy Or .readyState < 4: DoEvents: Wend
'other code...using dictionary
'.Quit
End With
End Sub