JSON and getElementByID return nothing - vba

am trying to get data from this web page to fill a word form using the following vba code
Private Sub Update_Click()
Dim CCv As ContentControl
Dim request As Object
Dim response As String
Dim html As New HTMLDocument
Dim website As String
Dim LGP As Variant
website = "https://www.ebi.ac.uk/chembl/compound_report_card/CHEMBL1112/"
Set request = CreateObject("MSXML2.XMLHTTP")
request.Open "GET", website, False
request.setRequestHeader "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT"
request.send
response = StrConv(request.responseBody, vbUnicode)
html.body.innerHTML = response
LGP = html.getElementById("Bck-CalcCompProp-ALogP").innerText
For Each CCv In ActiveDocument.ContentControls
Select Case CCv.Title
Case "LogP"
CCv.Range.Text = LGP
Case "Hydrogen bonding"
CCv.Range.Text = ""
Case "Dipole interactions"
CCv.Range.Text = ""
End Select
Next CCv
End Sub
the element data always return nothing, only if i downloaded the page that i can return the data, and i have no luck trying to parse json
could any on pls help to write a working code

Related

Can't get innertext from object

I am using below code, to retrive the total number of products on a given page, but get a runt-time error 428 on gg = ohtml.innertext
Sub testp()
numpage = GetNumberofPages("https://sheetmaterialswholesale.co.uk/sheet-materials/")
End Sub
Function GetNumberofPages(numpage As String)
Set xhr = New MSXML2.XMLHTTP60
Set html = New MSHTML.HTMLDocument
With xhr
.Open "GET", numpage, False
.setRequestHeader "User-Agent", "Mozilla/5.0"
.send
html.body.innerHTML = .responseText
End With
Dim ohtml As Object
Set ohtml = html.querySelectorAll(".noOfProducts")
Dim gg As String
gg = ohtml.innerText
gg = Replace(gg, ",", "")
nmpage = Round(Val(gg) / 36, 0) + 1
'nmpage = Val(Mid(Text, aa + 66, 5))
GetNumberofPages = nmpage
End Function
Any tips how to solve this?
The class you are using doesn't exist on the page and querySelectorAll returns a nodeList which doesn't have a .innerText property.
You can retrieve the page specific product count with the following css selector list which identifies the li elements associated with each product. Take the .Length property of the returned nodeList to get the number of products on the page
Debug.Print oHtml.querySelectorAll(".products li.product").Length
If you actually want the number of pages, calculated using the total product results count, then you can extract this total result count, as shown below, and use the results per page count as the denominator in the page count calculation.
Option Explicit
Public Sub testp()
MsgBox GetNumberOfPages("https://sheetmaterialswholesale.co.uk/sheet-materials/")
End Sub
Public Function GetNumberOfPages(ByVal numpage As String) As Long
Dim xhr As MSXML2.XMLHTTP60
Dim html As MSHTML.HTMLDocument
Set xhr = New MSXML2.XMLHTTP60
Set html = New MSHTML.HTMLDocument
With xhr
.Open "GET", numpage, False
.setRequestHeader "User-Agent", "Mozilla/5.0"
.send
html.body.innerHTML = .responseText
End With
'Dim ohtml As Object
Dim ohtml As MSHTML.IHTMLDOMChildrenCollection
Set ohtml = html.querySelectorAll(".products li.product")
Dim numProductsPerPage As Long, numProducts As Long, numPages As Long
numProductsPerPage = ohtml.Length 'assuming page you pass into function is representative
numProducts = CInt(html.querySelector(".cat-parent .count").innerText)
numPages = WorksheetFunction.Ceiling_Math(numProducts / numProductsPerPage)
GetNumberOfPages = numPages
End Function

I need error handling with XML variable lookup when our website is down or the client PC does not have Internet access

I need some way to ignore The following call out when the user does not have internet access or our website is down.
Dim RemoteURL = "https://sample.com/InfoApp/notify.xml"
Dim X = XDocument.Load(RemoteURL)
How can I have this section skip so error mess of continue or quit does not show up?
Dim RegID = My.Computer.Registry.GetValue("HKEY_CURRENT_USER\Software\MyAPP", "ID", Nothing)
Dim RemoteURL = "https://sample.com/InfoApp/notify.xml"
Dim X = XDocument.Load(RemoteURL)
Dim ID = X.<notify>.<ID>.Value
My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Software\MyAPP", "ID", ID)
Alert.Show()
You could use a function like this to check if there is a connection:
Function CheckInternet() As Boolean
Dim req As Object
Set req = CreateObject("MSXML2.serverXMLHTTP")
req.Open "GET", "http://www.google.com", False
req.Send
If req.Status <> 200 Then
CheckInternet = False
Else
CheckInternet = True
End If
End Function
It will create a request to google in this case. If the status is 200, everything is ok. Otherwise chance is high that there is no connection, or that google.com is offline. You can also fill in your own URL here of course.

VBA Macro, type mismatch error

I'm trying to get JSON data in excel and parse it. However, I'm getting an error: Type Mismatch.
Does anyone know how I can resolve this? I can't figure out what I'm doing wrong.
This is the link to the API I'm using: https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD
Here is the code:
Public Sub exceljson()
Dim https As Object, JSON As Object, i As Integer
Set https = CreateObject("MSXML2.XMLHTTP")
https.Open "GET", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD", False
https.Send
Set JSON = ParseJson(https.responseText)
i = 2
For Each Item In JSON
Sheets(1).Cells(i, 1).Value = Item("USD")
i = i + 1
Next
MsgBox ("complete")
End Sub
If you confirm you have correctly imported JsonConverter module and Dictionary Class and refer to Microsoft Scripting Runtime, then the following code will work:
Public Sub exceljson()
Dim https As Object, Json As Object, i As Integer
Dim Item As Variant
Set https = CreateObject("MSXML2.XMLHTTP")
https.Open "GET", "https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD", False
https.Send
Set Json = JsonConverter.ParseJson(https.responseText)
i = 2
For Each Item In Json.Items
Sheets(1).Cells(i, 1).Value = Item
i = i + 1
Next
MsgBox ("complete")
End Sub
Hope it helps!
updated
You should analyze the Json data responsed by the sever, the value of "Data" is a Dictionary. So you should use a Dictionary in For Each Loop.
The following codes will get all the data, I just use the "high" key as example. You can easily output other keys into excel.
Public Sub exceljson()
Dim https As Object, Json As Object, DataItem As Dictionary, i As Integer
Set https = CreateObject("MSXML2.XMLHTTP")
https.Open "GET", "https://min-api.cryptocompare.com/data/histominute?fsym=BTC&tsym=USD&limit=60&aggregate=3&e=CCCAGG", False
https.Send
'Use this debug command to see the whole response text
'Debug.Print https.responseText
Set Json = JsonConverter.ParseJson(https.responseText)
i = 2
For Each DataItem In Json("Data")
'Use "high" as example, you can output other key/values
Sheets(1).Cells(i, 1).Value = DataItem("high")
i = i + 1
Next
MsgBox ("complete")
End Sub

Passing Conexion String to VBA Macro

I have always found you a great help when I have questions. This time it's something related to Excel VBA.
I have a macro that brings back data from a website. You simply have to hard code the connection string into it.( xmlHttp.Open "GET", "http://www.example.com", False )
Sub GET_HTML_DATA()
Dim xmlHttp As Object
Dim TR_col As Object, TR As Object
Dim TD_col As Object, TD As Object
Dim row As Long, col As Long
Set xmlHttp = CreateObject("MSXML2.XMLHTTP.6.0")
xmlHttp.Open "GET", "http://www.example.com", False
xmlHttp.setRequestHeader "Content-Type", "text/xml"
xmlHttp.send
Dim html As Object
Set html = CreateObject("htmlfile")
html.body.innerHTML = xmlHttp.responseText
Dim tbl As Object
Set tbl = html.getElementById("curr_table")
row = 1
col = 1
Set TR_col = html.getElementsByTagName("TR")
For Each TR In TR_col
Set TD_col = TR.getElementsByTagName("TD")
For Each TD In TD_col
Cells(row, col) = TD.innerText
col = col + 1
Next
col = 1
row = row + 1
Next
End Sub
I was wondering if and how can this code be changed to accept a parameter as the connection string so I can call on it Run "GET_HTML_DATA(parameter)"
I have tried to declare a parameter in the parenthesis and include that in place of www.example.com but when I run the macro it tells me The macro may not be available in this workbook..."
Am I doing it right or is there another way I do not know?
In your sub in the parenthesis you need to declare the parameter as (input As String) and then use "input" in your code. Then you can use that Run "GET_HTML_DATA(parameter)". Alternatively, I guess you can simply put all your code in a simple function if you would have to return some output like
Function myFunction(input As String) As Double
//code goes here
End Function

Call web service in excel

In a VBA module in excel 2007, is it possible to call a web service? If so, any code snippets? How would I add the web reference?
Yes You Can!
I worked on a project that did that (see comment). Unfortunately no code samples from that one, but googling revealed these:
How you can integrate data from several Web services using Excel and VBA
STEP BY STEP: Consuming Web Services through VBA (Excel or Word)
VBA: Consume Soap Web Services
Here's an overview from MS:
Consuming Web Services in Excel 2007
For an updated answer see this SO question:
calling web service using VBA code in excel 2010
Both threads should be merged though.
In Microsoft Excel Office 2007 try installing "Web Service Reference Tool" plugin. And use the WSDL and add the web-services. And use following code in module to fetch the necessary data from the web-service.
Sub Demo()
Dim XDoc As MSXML2.DOMDocument
Dim xEmpDetails As MSXML2.IXMLDOMNode
Dim xParent As MSXML2.IXMLDOMNode
Dim xChild As MSXML2.IXMLDOMNode
Dim query As String
Dim Col, Row As Integer
Dim objWS As New clsws_GlobalWeather
Set XDoc = New MSXML2.DOMDocument
XDoc.async = False
XDoc.validateOnParse = False
query = objWS.wsm_GetCitiesByCountry("india")
If Not XDoc.LoadXML(query) Then 'strXML is the string with XML'
Err.Raise XDoc.parseError.ErrorCode, , XDoc.parseError.reason
End If
XDoc.LoadXML (query)
Set xEmpDetails = XDoc.DocumentElement
Set xParent = xEmpDetails.FirstChild
Worksheets("Sheet3").Cells(1, 1).Value = "Country"
Worksheets("Sheet3").Cells(1, 1).Interior.Color = RGB(65, 105, 225)
Worksheets("Sheet3").Cells(1, 2).Value = "City"
Worksheets("Sheet3").Cells(1, 2).Interior.Color = RGB(65, 105, 225)
Row = 2
Col = 1
For Each xParent In xEmpDetails.ChildNodes
For Each xChild In xParent.ChildNodes
Worksheets("Sheet3").Cells(Row, Col).Value = xChild.Text
Col = Col + 1
Next xChild
Row = Row + 1
Col = 1
Next xParent
End Sub
Excel 2013 Read Data from a web service and bash the JSON till you can get what you want out of it (given the JSON will always be in the same format).
This code should just work without the need for any plugins.
You will need your own free API key from the currency converter website though.
I used it to load the USD to GBP value into a cell on my sheet.
Option Explicit
Sub Test_LateBinding()
Dim objRequest As Object
Dim strUrl As String
Dim blnAsync As Boolean
Dim strResponse As String
Set objRequest = CreateObject("MSXML2.XMLHTTP")
strUrl = "https://free.currconv.com/api/v7/convert?q=USD_GBP&compact=ultra&apiKey=[MY_API_KEY]"
blnAsync = True
With objRequest
.Open "GET", strUrl, blnAsync
.SetRequestHeader "Content-Type", "application/json"
.Send
While objRequest.readyState <> 4
DoEvents
Wend
strResponse = .responsetext
End With
Dim responseArray() As String
responseArray = Split(strResponse, ":", -1)
Dim value As String
value = responseArray(1)
Dim valueArray() As String
valueArray = Split(value, "}", -1)
Dim finalValue As String
finalValue = valueArray(0)
Sheet2.Cells(22, "C") = finalValue
End Sub