XMLHTTP is pulling HTML from parent webpage - html

I am trying to pull historical weather data from wunderground- originally I tried to scrape the web data off the main webpage using the standard HTML elements etc. etc.. however then I discovered that if you add "?format=1" to the URL a browser will display more or less a csv which is much easier to parse into data tables...
However I was still using IE browser which can be quite slow if you have a lot of data to pull so I started looking into using an XMLHTTP object to help pull the data faster which is where I ran into my issue- as I mentioned adding "?format=1" to the end of the URL would return a nice slim csv, but when I use the XMLHTTP it pulls the HTML of the original page not the CSV!
It seems to me like when the XMLHTTP sends its request, the response comes back from the 'parent' site if you will and not the csv that I specified... I noticed that it pulls the HTML from the URL that ends in .html, like it cuts off at .html and that's why the response is from the .html page and not the CSV page.. so I tried looking into URL protocols to see if there was a way to force the XMLHTTP to request the csv URL but I am pretty far out of my element and couldn't find anything..
Code below- appreciate any help you can give me:
Public Sub downloadWebDataToCSV(URL As String)
Dim ADOStream As ADODB.Stream
Dim XMLHTTP As MSXML2.XMLHTTP60
Set XMLHTTP = New MSXML2.XMLHTTP60
XMLHTTP.Open "GET", URL, False
XMLHTTP.send
If XMLHTTP.Status = 200 Then
Set ADOStream = New ADODB.Stream
With ADOStream
.Open
.Type = adTypeBinary
.Write XMLHTTP.responseBody
.SaveToFile "C:\datafile.csv", 2
.Close
End With
End If
End Sub
Here are the parent and csv URLs as well if that helps-
Mainpage: https://www.wunderground.com/history/airport/KDAL/2003/10/15/DailyHistory.html
CSV:
https://www.wunderground.com/history/airport/KDAL/2003/10/15/DailyHistory.html?format=1
Thanks in advance,
TheSilkCode

I think you need to change the encoding of what is returned, then you can write directly to a CSV after cleaning up the format a bit. To change the format, you need to set a few request headers. See below.
Public Sub downloadWebDataToCSV()
Dim URL As String: URL = "https://www.wunderground.com/history/airport/KDAL/2003/10/15/DailyHistory.html?format=1"
Dim XMLHTTP As New MSXML2.XMLHTTP60
With XMLHTTP
.Open "GET", URL, False
.setRequestHeader "User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
.setRequestHeader "content-type", "text/html; charset=UTF-8"
.send
End With
If XMLHTTP.Status = 200 Then
Dim fso As Object: Set fso = CreateObject("Scripting.FileSystemObject")
Dim Fileout As Object: Set Fileout = fso.CreateTextFile("C:\users\megatron\desktop\vba.txt")
Dim myText As String: myText = Replace(XMLHTTP.responseText, "<br />", vbCrLf)
Fileout.Write myText
Fileout.Close
End If
End Sub

You can get the data via Weather API by the example URL:
http://api.wunderground.com/api/c991975b7f4186c0/history_20031015/q/airport/KDAL.json
As you can see, the URL consists of three variable parts: API key c991975b7f4186c0, date 20031015 and location airport/KDAL. If you make XHR the response returns in JSON format.
How to obtain API key and parse JSON respons you can see in this answer.
Read more about Weather API.

Related

MSXML2.XMLHTTP60 URL Request does not returning full Json Text

I am trying to extract one Json data from NSE web site.This invlovles cookies,before executing the MACRO codes atleast open once the URL https://www.nseindia.com/get-quotes/derivatives?symbol=TCS.
So that Cookies problem will not be faced.
After this when i copy this Url "https://www.nseindia.com/api/quote-derivative?symbol=TCS" and run it in the web browser,i am receiving all the Json text starts with "{"info":{"symbol":"TCS","companyName":"Tata Consultancy Services Limited","in" etc etc.
How ever when i tried to get the same via excel macro ,i am receiving only the partial Json text, here i am attaching my macro codes and partial Json text as a image
Private Function Getresponse(ByVal Url As String) As String
Const RunAsync As Boolean = True
Const Processcomplete As Integer = 4
Dim request As MSXML2.XMLHTTP60
Set request = New MSXML2.XMLHTTP60
Dim Response As String
With request
.Open "GET", Url, RunAsync
.setRequestHeader "Content-Type", "application/json"
.send
Do While request.readyState <> Processcomplete
DoEvents
Loop
Response = .responseText
End With
Getresponse = Response
End Function
Sub Test_GetResponse()
Debug.Print Getresponse("https://www.nseindia.com/api/quote-derivative?symbol=TCS")
End Sub
Any suggestion why full response is not received please?

Issue with sending JSON data from VBA

I am trying to create an Excel macro to send cell data to a URL using a POST request. I have chosen to format that data using JSON, because there is a lot of it to send. Here is my code for sending the JSON:
Dim jFullDictionary As New Dictionary ' This dictionary contains a Collection
...
Dim JsonURL As String
JsonURL = "http://myurl.com"
Dim JsonHTTP As New MSXML2.XMLHTTP
Set JsonHTTP = CreateObject("MSXML2.XMLHTTP")
Dim JsonString As String
JsonString = JsonConverter.ConvertToJson(jFullDictionary, Whitespace:=3)
With JsonHTTP
.Open "POST", JsonURL, False
.setRequestHeader "Content-type", "application/json"
.setRequestHeader "Accept", "application/json"
.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
.send JsonString ' This is where the program breaks
End With
Every time I run this, I get the error that says (something along the lines of)
Run time error: Could not find the resource specified
I have already looked at these StackOverflow threads, but I've gotten nowhere:
Error from VB excel macro code - msxml3.dll -2146697211 The system cannot locate the resource specified
Sending JSON POST request in VBA
Additionally, I have tried installing Tim Hall's project from here, but the installation doesn't work on my machine (might be because it's a work computer).
The error makes me think that it has something to do with the resources that I have loaded, but I'm not sure. If it's not that, then there is something wrong with my code. Any help would be appreciated, thank you.
Edit:
Here is the loop that I use to fill the jFullDictionary with my data:
Dim jDictionary As New Dictionary
Dim jCollection As New Collection
Dim jFullDictionary As New Dictionary
For i = 1 To excelRange.Rows.Count
For j = 1 To excelRange.Columns.Count
jDictionary("row") = i
jDictionary("name") = Cells(5, j) ' This assignment is arbitrary
jDictionary("value") = Cells(i + 1, j) ' so is this
jCollection.Add jDictionary
Set jDictionary = Nothing
Next j
Next i
jFullDictionary.Add "parametersList", jCollection

Json POST request in Excel vba

I am trying to get trains information (date, time and prices) using the website https://www.trainline.fr/search
I would like to use Excel VBA (I am trying the POST request method via MSXML2.XMLHTT) to send a JSon request and parse the answer in a table.
I don't know which part of the right panel of
to use in my code
The request sent looks like this :
{"search":{"departure_date":"2018-04-01T10:00:00UTC","return_date":null,"cuis":{},"systems":["sncf","db","idtgv","ouigo","trenitalia","ntv","hkx","renfe","benerail","ocebo","westbahn","leoexpress","locomore","busbud","flixbus","distribusion","city_airport_train","obb","timetable"],"exchangeable_part":null,"source":null,"is_previous_available":false,"is_next_available":false,"departure_station_id":"4916","via_station_id":null,"arrival_station_id":"233","exchangeable_pnr_id":null,"passenger_ids":["173716784"],"card_ids":["7118357"]}}
I am actually using the navigate method which is very much easier but I want to progress in a more efficient and interesting method.
My actual code :
Dim objHTTP As Object
Dim Json As String
Dim result As String
'here I am pulling in the request {"search":{"departure_date":"2018...
Json = Worksheets("Test").Range("A1")
Set objHTTP = CreateObject("MSXML2.XMLHTTP.6.0")
URL = "https://www.trainline.fr/api/v5_1/search"
objHTTP.Open "POST", URL, False
objHTTP.setRequestHeader "Content-type", "application/json"
objHTTP.send (Json)
result = objHTTP.responseText
Thank you for sharing your knowledge

VBA JSON POST Payload Issue

I'm trying to setup a API request to pull data from the Bureau of Labor Statistics. I succeeded in getting data using a get request, entering just the url and the series (as shown in the first code example). This works fine and I was able to parse out the JSON using Tim Hall's VBA-JSON converter and work with the data. My problem is that the get method returns only 3 years of data and I'd like to get more than that which requires a post method.
Sub GetCPItable()
Dim objhttp As Object
Dim strUrl As String
strUrl = "https://api.bls.gov/publicAPI/v1/timeseries/data/CUUR0000SA0"
Set objhttp = CreateObject("MSXML2.XMLHTTP")
With objhttp
.Open "get", strUrl, False
.Send
End With
MsgBox objhttp.ResponseText
End Sub
It seems (take this with a grain of salt, this is my first time working with api servers) like VBA is not passing my payload. I've checked my payload here and the JSON syntax appears correct and seems to be the correct syntax according to the page I first linked to. Yet the only things I recieve back from the api server is 404 not found errors. I've been trying different things to piece together what I'm missing all day from their source code examples (no VBA ofcourse) and posts here and elsewhere on the web and haven't made any progress. Here is a debugging version of the code that isn't working.
Sub GetCPItable()
Dim objhttp As Object
Dim body As String
'create our URL string and pass the user entered information to it
Dim strUrl As String
strUrl = "https://api.bls.gov/publicAPI/v1/timeseries/data"
Set objhttp = CreateObject("MSXML2.XMLHTTP")
With objhttp
.Open "POST", strUrl, False
.SetRequestHeader "Content-type", "application/json"
body = "{""seriesid"":""CUUR0000SA0""],""startyear"":""2008"",""endyear"":""2012""}"
.Send (body)
End With
MsgBox objhttp.ResponseText
End Sub
This is the error I get in response:
: responseText : "{
"status": "REQUEST_FAILED",
"responseTime": 0,
"message": [
"404 Error - Page Not Found"
],
"Results": [ ]
}" : String
Any help would be much appreciated. The only thing I can think to try next is using the V2 API but I'd like to avoid that if possible since it would require yearly reregistration.

Post JSON to web in excel vba

I want to POST some JSON with some VBA:
Dim sURL As String, sHTML As String, sAllPosts As String
Dim oHttp As Object
Dim blWSExists As Boolean
Set oHttp = CreateObject("MSXML2.XMLHTTP")
sURL = "some webste.com"
oHttp.Open "POST", sURL, False
oHttp.setRequestHeader "Content-type", "application/json"
oHttp.setRequestHeader "Accept", "application/json"
oHttp.Send (mType = OPEN_SYSTEM_TRADE & systemOwnerId = 10)
sHTML = oHttp.ResponseText
Worksheets("Open1").Range("A1").Value = sHTML
The predefined format to be sent to the website is a description in json as follows :
{"mType":"OPEN_SYSTEM_TRADE","systemOwnerId":10,"systemId":16, etc}
My oHttp.Send line must be wrong, as soon as i add more arguments, i get a compiler error
I publish this (not working) code cause its the best i could find on the web so far (all other get me stuck on other things that i don't understand ...
I also tried to put the json code in a cell, put the cell in a string, and send the string like this : oHttp.Send (string), which results in a Error 406 Not Acceptable reply from the website.
JSON can be very sensitive to how it's formatted, so I would make sure everything is quoted properly before it is sent. I would recommend splitting Body into a separate variable and debugging the value with http://jsonformatter.curiousconcept.com/ before sending.
Dim Body As String
Body = "{""mType"":""OPEN_SYSTEM_TRADE"",""systemOwnerId"":10}"
' Set breakpoint here, get the Body value, and check with JSON validator
oHttp.Send Body
I ran into many similar issues when working with Salesforce's REST API and combined my work into a library that may be useful to you: https://github.com/VBA-tools/VBA-Web. Using this library, your example would look like:
Dim Body As New Dictionary
Body.Add "mType", "OPEN_SYSTEM_TRADE"
Body.Add "systemOwnerId", 10
Dim Client As New WebClient
Dim Response As WebResponse
Set Response = Client.PostJson("somewebsite.com", Body)
Worksheets("Open1").Range("A1").Value = Response.Content