Get value from web document input element with VBA - html

I am having difficult to retrieve value 300 from the input named points.
Here's my HTML and VBA code.
HTML:
<td id="myPower_val_9" style="visibility: visible;">
<input type="text" disabled="disabled" value="300" name="points"></input>
</td>
VBA:
Dim ie As Object
Dim myPoints As String
Set ie = CreateObject("InternetExplorer.Application")
With ie
.Visible = 0
.navigate "www.example.com"
While .Busy Or .readyState <> 4
DoEvents
Wend
End With
Dim Doc As HTMLDocument
Set Doc = ie.document
myPoints = Trim(Doc.getElementsByTagName("td")(0).getElementById("myPoints").innerText)
Range("A1").Value = myPoints

HTML Code
I'd try working out the code that manipulates the Document Object Model (DOM) in javascript in a web browser so you can make use of better web based debugging tools.
There are several issues here that a console or debugger could help out with:
You want to get the element ID myPoints but in HTML it's just called points
You want to get the element by ID, but you've only set the name property -
As long as name is unique to the element, you don't need to search for a td first
As you can see from <input></input>, input elements do not have innerText (the text inside the ><). Instead they have a value attribute
The element exposes it's attributes and other data through the properties on the object itself. So you can check the input's value by just looking at .value
Here's a javascript example of what you're trying to do:
var value = document.getElementsByName("points")[0].value;
console.log(value);
<input type="text" disabled="disabled" value="300" name="points" />
Open the console (F12), and you should see 300
VBA
To convert it to VBA code for Excel, just make sure you uses parentheses () for VB arrays instead of square brackets [] for JS arrays:
myPoints = Trim(Doc.getElementsByName("points")(0).Value)
That should work just fine.
References
Since I'm not sure at what point you're failing in VB, also make sure you have all the proper web references in place in your VBA script.
Go to Tools > References > and add "Microsoft HTML Object Library" and "Microsoft Internet Controls":
Demo
I created a demo in plunker so there would be a live site to go against instead of example.com.
Paste the following code into excel and everything should work fine:
Public Sub GetValueFromBrowser()
Dim ie As Object
Dim url As String
Dim myPoints As String
url = "http://run.plnkr.co/plunks/6UTb9kHRZ363Ivhh2BPE/"
Set ie = CreateObject("InternetExplorer.Application")
With ie
.Visible = 0
.navigate url
While .Busy Or .readyState <> 4
DoEvents
Wend
End With
Dim Doc As HTMLDocument
Set Doc = ie.document
myPoints = Trim(Doc.getElementsByName("points")(0).Value)
Range("A1").Value = myPoints
End Sub
Output:

CSS selector:
Use a CSS selector to get the element of input[name='points']
You don't show enough HTML to know if this is the only on the page. The above says elements with input tag having attribute name whose value is 'points'
CSS query:
VBA:
You apply the CSS selector with .querySelector method of document for a single element; .querySelectorAll for a nodeList of all matching elements i.e. if there is more than one on the page and you get the one of interest by index.
Debug.Print ie.document.querySelector("input[name='points']").getAttribute("value")

You need to use .getAttribute("name of attribute") to get an attributes value. In your case .getAttribute("value") will return 300.
Dim ie As Object
Dim myPoints As String
Set ie = CreateObject("InternetExplorer.Application")
With ie
.Visible = 1
.navigate "website URL"
While .Busy Or .readyState <> 4
DoEvents
Wend
End With
Dim Doc As HTMLDocument
Set Doc = ie.document
myPoints = Trim(Doc.getElementsByTagName("td")(0).getElementsByTagName("input")(0).getAttribute("value"))
Range("A1").Value = myPoints
Just on a side note. I don't know much about HTML and maybe someone can elaborate on this more. But if you want to test that HTML code you need to add in the < table> < tr> tags.
Something like this:
<table>
<tr>
<td id="myPower_val_9" style="visibility: visible;">
<input type="text" disabled="disabled" value="300" name="points"></input>
</td>
</tr>
</table>

Related

Check if website checkbox in checked with excel VBA

I am trying to make a VBA that can read the HTML and checked if a specific check box is checked and write either check or unchecked in a cell. But I am having difficulties with VBA as I do not use it as often, any advise will be appreciated.
HTML
<input id="foo1" type="checkbox" name="Device" value="iPad"
checked="checked">
VBA
Sub getValue()
Dim IE As Object: Set IE =
CreateObject("InternetExplorer.Application")
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Sheet1")
Dim Country As String
With IE
.Visible = False
.navigate ws.Range("A3").Value
Do
DoEvents
Loop Until .readyState = 4
End With
Set oShell = CreateObject("WScript.Shell")
Dim document
document.getElementById("checkBox(iPad)")
Item(0).Checked = True
End Sub
Try
Debug.Print ie.document.querySelector("#foo1").getAttribute("checked") ="checked"
I am not sure, without an URL to test with whether there is .Checked property you can evaluate for True ( ie.document.querySelector("#foo1").Checked)
Without more HTML hard to say if this will be able to access the required element. There may be forms/iframes/frames to negotiate.
This can also be done with looping all the input elements on the website until you find the one with the right name, this will of course be slower then a querySelector, but can be usefull if you need to change multiple input elements.
Dim objCollection as Object
Set objCollection = ie.Document.getElementsByTagName("input")
i = 0
'Loop through all elements and find the checkbox
While i < objCollection.Length
If objCollection(i).Name = "Device" Then
objCollection(i).Checked = False
End If
i = i + 1
Wend
If you only have 1 checkbox i would no doubt go with a querySelector as #QHarr

VBA access drop downs properly in a website

I'm having a bit of a problem. I'm hoping some VBA guru's can help me with. I have a website that has drop down options I'd like to be able to select. Right now my code is off and I'm not sure what I'm doing wrong. I looked over the website trying to find out what I was doing wrong but nothing I found that could answer my question directly. Any help would be greatly appreciated.
Here is what I have:
Private Sub CMReportExport()
Dim IEapp As Object
Dim WebUrl As String
Dim yearList As Object
Dim prefixList As Object
Dim versionList As Object
Set IEapp = CreateObject("InternetExplorerMedium.Application")
'Set IEapp = CreateObject("InternetExplorer.Application")
WebUrl = "http://reporthub/Enterprise/Pages/Report.aspx?ItemPath=%2fSupply+Chain%2fProduction%2fContribution+Margin%2fNonFood%2fNonFood+CM+RetailCat"
With IEapp
.Silent = True
.Visible = True
.navigate WebUrl
End With
While IEapp.Busy Or IEapp.readyState < 4: DoEvents: Wend '<== Ensure page loaded
Set yearList = IEapp.document.querySelectorAll("#ctl32_ctl04_ctl03_ddValue option") '<==apply CSS selector to get nodeList
Set prefixList = IEapp.document.querySelectorAll("#ctl32_ctl04_ctl05_ddValue option")
Set versionList = IEapp.document.querySelectorAll("#ctl32_ctl04_ctl07_ddValue option")
yearList.item(2).Selected = True 'Index into nodeList e.g. second item is at index 2 = year 2018
prefixList.item(2).Selected = True
versionList.item(1).Selected = True
'Set IEapp.getElementById("ctl32_ctl04_ctl03_ddValue").selectedvalue = 2 'Year
'Set IEapp.getElementById("ctl32_ctl04_ctl05_ddValue").selectedvalue = DA 'Prefix
'Set IEapp.getElementById("ctl32_ctl04_ctl07_ddValue").selectedvalue = 1 'Version
End Sub
The HTML elements (a chunk) are as follows:
<tr>
<td class="ParamLabelCell"><label for="ctl32_ctl04_ctl03_ddValue"><span>Year</span></label>
</td>
<td class="ParamEntryCell" style="padding-right:0px;"><div id="ctl32_ctl04_ctl03">
<select name="ctl32$ctl04$ctl03$ddValue" onchange="javascript:setTimeout('__doPostBack(\'ctl32$ctl04$ctl03$ddValue\',\'\')', 0)" id="ctl32_ctl04_ctl03_ddValue" disabled="disabled">
<option selected="selected" value="0"><Select a Value></option>
<option value="1">2019</option>
<option value="2">2018</option>
<option value="3">2017</option>
<option value="4">2016</option>
<option value="5">2015</option>
</select>
</div></td><td class="InterParamPadding"></td><td class="ParamLabelCell"><label for="ctl32_ctl04_ctl05_ddValue"><span disabled="disabled">Offer</span></label></td><td class="ParamEntryCell" style="padding-right:0px;"><div id="ctl32_ctl04_ctl05">
<select name="ctl32$ctl04$ctl05$ddValue" onchange="javascript:setTimeout('__doPostBack(\'ctl32$ctl04$ctl05$ddValue\',\'\')', 0)" id="ctl32_ctl04_ctl05_ddValue" disabled="disabled" class="EmptyDropDown">
</select>
</div>
</td>
</tr>
<tr IsParameterRow="true">
<td class="ParamLabelCell"><label for="ctl32_ctl04_ctl07_ddValue"><span disabled="disabled">Version</span></label></td>
<td class="ParamEntryCell" style="padding-right:0px;"><div id="ctl32_ctl04_ctl07">
<select name="ctl32$ctl04$ctl07$ddValue" id="ctl32_ctl04_ctl07_ddValue" disabled="disabled" class="EmptyDropDown">
</tr>
Caveat:
I can't test against that webpage and there is not enough HTML to know if there are forms/frames and the like to also negotiate. The following is based on the HTML snippet provided. Mileage may vary.
CSS selectors:
You can use CSS selectors to target elements. For example you can get all the year options with the following selector, and then index into the returned nodeList:
#ctl32_ctl04_ctl03_ddValue option
The above selector says all elements with option tag that have parent element with id ctl32_ctl04_ctl03_ddValue. "#" is the id selector.
There is not enough HTML to advise on the other elements you are targeting for sure but see my suggestions at the bottom. This illustrates the principle of using CSS selectors to target elements by page styling. More info on CSS selectors here and here.
CSS query results on HTML section provided:
Getting the nodeList and selected an option - VBA:
As more than one element is matched, querySelectorAll method is used to apply the selector and return the nodeList of matching elements.
For example:
While IEapp.Busy Or IEapp.readyState < 4: DoEvents: Wend '<== Ensure page loaded
Dim yearList As Object
Set yearList = IEapp.document.querySelectorAll("#ctl32_ctl04_ctl03_ddValue option") '<==apply CSS selector to get nodeList
yearList.item(1).Selected = True 'Index into nodeList e.g. second item is at index 1 = year 2019
Assuming similar pattern for your other two option lists:
Dim prefixList As Object, versionList As Object
Set prefixList = IEapp.document.querySelectorAll("#ctl32_ctl04_ctl05_ddValue option")
Set versionList = IEapp.document.querySelectorAll("#ctl32_ctl04_ctl07_ddValue option")
Then index into those.
If problems with While IEapp.Busy Or IEapp.readyState < 4: DoEvents: Wend then try the following instead:
While IEapp.readyState < 4: DoEvents: Wend
Dim waitUntil As Date
waitUntil = Now + TimeValue("00:00:11") '<==Adjust additional wait time in seconds here
Do
DoEvents
Loop Until Now >= waitUntil
XMLHttpRequest (XHR)
You are currently using IE browser which is a slow method for scraping. It may be possible for you to retrieve the required info by issuing an XHR POST request. I can't test against that page but you can find more info here and here.

Interaction With WebPage VBA

I'm creating a code that allows me to open a specific site and enter value in element with the name searchByTagName=searchByTRSMP and then Type search to load the new window
But the problem that button search doesn't have a TagName or IdName only this
<td width="13%" align="center" rowSpan="1" colSpan="1">
<input name="" onclick="Javascript:document.forms[0].submit();return false;" type="image" srx="/cmh/cmh/xxxxxx" border="0"></input>
Anyone Can Light me on pressing that button with only those conditions
this Mycode :
Sub ToComb()
Dim ie As Object
Dim itm As IHTMLElement
Set ie = CreateObject("InternetExplorer.Application")
ie.Visible = True
ie.navigate "http://XXXX-
XXXX.eu.airbus.XXXXXp:XXXXX/cmh/consultation/preSearchTRSTDMAS.do?
clearBackList=true&CMH_NO_STORING_fromMenu=true"
While ie.Busy Or ie.readyState <> 4: DoEvents: Wend
Set itm = ie.document.getElementsByName("searchByTRSMP")(0)
If Not itm Is Nothing Then itm.Value = "k20734"
Set Doc = ie.document
Set tags = ie.document.getElementsByTagName("")
For Each tagx In tags
If tagx.Value = "Next" Then
tagx.Click
Exit For
End If
Next
End Sub
GetElementsByTagname mean search for an element by the type of an HTML element (such as, div, p or in your example - input).
You can get all your inputs tags (elements), iterate them and identify the required input, based on it's (for example) srx attribute:
Set tags = ie.Document.GetElementsByTagname("Input")
For Each tagx In tags
If tagx.src= "/cmh/cmh/xxxxxx" Then
tagx.Click
End If
Next
In addition, the final src of the input might changed from the actual code, because you use a relative path. Check the actual src with a MsgBox:
For Each tagx In tags
MsgBox tagx.src
I assume it will be different, such as prefix of http and so on:
If tagx.src = "http://xxxx
xxxx.eu.airbus.xxx:xxxx/cxxx/xxx/image/button_search.gif" Then

VBA - getElementById works for simple website but not another?

So I'm currently stuck at getting a VBA script to retrieve the value of an input box from this Sudoku website. However, I was able to get the value from a paragraph element with the id of "contact" from my own simpler website, using the same code (after switching the url and id names, of course).
Any attempts to research further brings up articles/blogs that discuss what I've done correctly so far, so I suspect I am not researching it properly.
Here is my code:
Sub GetTable()
Dim ieApp As InternetExplorer
Dim ieDoc As Object
Dim sudokuCell As Object
Dim url, id, content As String
Dim i As Integer
Set ieApp = New InternetExplorer
ieApp.Visible = True
url = "http://www.websudoku.com/"
ieApp.navigate url
Do While ieApp.Busy: DoEvents: Loop
Do Until ieApp.READYSTATE = READYSTATE_COMPLETE: DoEvents: Loop
Set ieDoc = ieApp.document
If ieDoc Is Nothing Then
MsgBox ("Nothing")
'Else
' MsgBox ("Something")
End If
For i = 0 To 8
Set sudokuCell = ieDoc.getElementById("f00")
content = sudokuCell.innerText
MsgBox (content)
Next i
ieApp.Quit
Set ieApp = Nothing
End Sub
And here is an example of the html for a cell which is blank:
<td class="g0" id="c00"><input class="d0" size="2" autocomplete="off"
name="8iz6n11" maxlength="1" onblur="j8(this)" id="f00"></td>
And here is one for cell that is prefilled with a number:
<td class="f0" id="c10"><input class="s0" size="2" autocomplete="off"
name="s8iz6n21" readonly="" value="7" id="f10"></td>
I have tried both the "c00" an "f00" without success. Also, while I believe the problem at hand is I am not retrieving the element, I am concerned that the .innerText property won't retrieve the values.
First: The website is using FRAME, so you are not accessing the frame document in the VBA code actually. You need to navigate to the actual URL given below - change your url variable as the following (which is the frame's src property):
url = "http://view.websudoku.com/?"
Second: Those are INPUT elements you are trying to get values, you should be better using Value property instead innerText
content = sudokuCell.Value
Third and last: I have no idea what your code is supposed to do inside the loop as it will keep reading f00 element value as is. However I believe you'll loop through the input elements and just hit the wall here about the FRAME issue I explained above, so I assume loop is your part and have no trouble about it.

HTML object library / pull

I have the following code in an HTML web page, and I am trying to use the html object library via vba engine to pull the value from within this tag:
<input name="txtAdd_Line1" disabled="disabled" size="30" maxLength="50" value="123 N 1ST ST"/>
I figure I have to use .getelementsbytagname or .getelementsbyname, but I am not sure how to grab the value. Does anyone have any ideas?
Here's an example with comments, subtitute in your actual address:
Sub Example()
'Declare needed variables
Dim ie, elements
Dim x As Long
'Create IE Applction
Set ie = CreateObject("InternetExplorer.Application")
'Navigate to the website
ie.navigate "C:\test.html" 'Substitute your actual address
'Wait for website to finish loading
Do While ie.ReadyState <> 4
Loop
'Find the elements
Set elements = ie.document.getelementsbyName("txtAdd_Line1")
'Display the value of each returned element
For x = 0 To elements.Length - 1
MsgBox elements(x).Value
Next
'Quit IE
ie.Quit
End Sub
Based on your comment most likely just looking at the document wasn't retrieving the actual layer of the tree you wanted, try this:
Set HTMLDoc = ie.document.frames("MainFrame").document
With HTMLDoc
'This returns an (object) which contains an array of all matching elements
a = .getElementsByName("txtAdd_Line1")
end with
For x = 0 to a.length
msgbox a(x).value
next
You can use a CSS selector of input[name='txtAdd_Line1'] . This says element with input tag having attribute name with value 'txtAdd_Line1'.
CSS selector:
You apply a CSS selector using the .querySelector method of document e.g.
Msgbox ie.document.querySelector("input[name='txtAdd_Line1']").innerText