I have spent about 15 days trying to make a scraper in VBA, I've been making decent progresses day after day but these last two days I got stuck in the very last step to get the data.
This is a continuation of my previous post, which gave me a good guide to start.
Here's the process I want to simulate usign MSXML (not Internet Explorer)
Open https://beacon.schneidercorp.com/
Select "Iowa State"
Select "Boone County, IA"
Click on the popup link "Property Search"
In the top red ribbon, click on the "Comp Search" label
At the bottom of the resulting page, in the "Agricultural Comparables Search" section check the "Sale Date" checkbox
Select 5 months in the "Sale Date" combobox
Click on the "Search" button at the bottom of the "Agricultural Comparables Search" section
In the resulting page, look for "Parcel ID" identified as "088327354400002" and click on the link on the "Recording" column (value "2020-0418")
I could achieve the first 8 steps but I haven't been able to get URL of the results that should be get from that last link held in "2020-0418"
As I did to get from the 8th to the 9th step, I noticed that inside the Development ToolKit's "Network" Tab, the website sent a POST request, as shown below.
**General**
Request URL: https://beacon.schneidercorp.com/Application.aspx?AppID=84&LayerID=795&PageTypeID=3&PageID=579&Q=1926372975
Request Method: POST
Status Code: 302
Remote Address: 52.168.93.150:443
Referrer Policy: no-referrer-when-downgrade
**Response Headers**
alt-svc: quic=":443"; ma=2592000; v="44,43,39"
cache-control: private
content-encoding: gzip
content-length: 187
content-type: text/html; charset=utf-8
date: Sat, 27 Jun 2020 00:46:42 GMT
location: /Application.aspx?AppID=84&LayerID=795&PageTypeID=3&PageID=551&Q=1603287013
status: 302
vary: Accept-Encoding
**Request Headers**
:authority: beacon.schneidercorp.com
:method: POST
:path: /Application.aspx?AppID=84&LayerID=795&PageTypeID=3&PageID=579&Q=1926372975
:scheme: https
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed- exchange;v=b3;q=0.9
accept-encoding: gzip, deflate, br
accept-language: es-ES,es;q=0.9
cache-control: max-age=0
content-length: 395
content-type: application/x-www-form-urlencoded
cookie: _ga=GA1.2.1299682399.1590279064; MODULES508=; MODULESVISIBILE508=18469; MODULES1024=; MODULESVISIBILE1024=29489%7C29501; MODULES501=; MODULESVISIBILE501=10310; _gid=GA1.2.449363625.1593013300; ASP.NET_SessionId=4xwgdh2cqto0kugirkani4vp; _gat=1
origin: https://beacon.schneidercorp.com
referer: https://beacon.schneidercorp.com/Application.aspx?AppID=84&LayerID=795&PageTypeID=3&PageID=579&Q=1926372975
sec-fetch-dest: document
sec-fetch-mode: navigate
sec-fetch-site: same-origin
sec-fetch-user: ?1
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
Query String Parameters (source view)
AppID=84&LayerID=795&PageTypeID=3&PageID=579&Q=1926372975
**Form Data (source view)**
__EVENTTARGET=ctlBodyPane%24ctl02%24ctl01%24gvwAgCompResults%24ctl05%24lnkRecording&__EVENTARGUMENT=&__VIEWSTATE=cbg8zdrx99ofbjcpw9%2FCE8J0v2SY5W86N%2Fbx%2FU0CsnNPy9D3bcg%2F5YstkCGTwd03lObnZbF9%2B5QuO1lP658HYgyXsOmpImGVjhn47teNdO788MngiEN9qzZbzrOv8jZAd93B8QXltxoPV5dLVu0%2BELpETwwTteNsmbKNEr1IpBz2aSxsN1spJUTKy42SUE37HkdUqVpsQlCPHPyIomJH4b6CoepL2uG9y45pMbUYFZxPG5ob&__VIEWSTATEGENERATOR=569DB96F
Next, I show a sample of my code
Sub ScrapingTest()
Dim XMLpagina As New MSXML2.ServerXMLHTTP60
Dim htmlDoc As New MSHTML.htmlDocument
Dim strURL As String, strBodyRequest As String
Dim strETarget As String, strVState As String
Dim strT1 As String, strT2 As String, strT3 As String
Dim strPageID As String, strPageTypeID As String
'====================
'FOR VIEWING PURPOSES I ONLY SHOW A SHORT VERSION OF MY ORIGINAL CODE,
'TRYING TO CUT AS MUCH AS POSSIBLE...
'====================
'OPENING Comp Search Website - STEP 6
strURL = "https://beacon.schneidercorp.com/Application.aspx?AppID=84&LayerID=795&PageTypeID=2&PageID=578"
'SEND GET REQUEST
XMLpagina.Open "GET", strURL, False
XMLpagina.send
htmlDoc.body.innerHTML = XMLpagina.responseText
Call generarCopiaHtml(XMLpagina)
'GETTING THE VALUES TO BE SEND ON THE REQUESTBODY OF THE NEXT REQUEST
'GET THE EVENTTARGET
strETarget = "ctlBodyPane$ctl02$ctl01$btnSearch" 'I DON'T SCRAPE FOR THIS BECAUSE IT'S ALWAYS THE SAME
'GET THE VIEWSTATE VALUE
strT1 = "<input type='hidden' name='__VIEWSTATE' id='__VIEWSTATE' value='"
strT1 = Replace(strT1, "'", """")
strT2 = "' />"
strT2 = Replace(strT2, "'", """")
strVState = extraeVerg(XMLpagina.responseText, strT1, strT2) 'THIS CUSTOM FUNCTION EXTRACTS A TEXT LAYING BETWEEEN strT1 AND strT2
'SETS THE REQUESTBODY
strBodyRequest = "__EVENTTARGET=ctlBodyPane%24ctl02%24ctl01%24btnSearch"
strBodyRequest = strBodyRequest & "&__EVENTARGUMENT="
strBodyRequest = strBodyRequest & "&__VIEWSTATE=" & strVState
strBodyRequest = strBodyRequest & "&__VIEWSTATEGENERATOR=569DB96F"
strBodyRequest = strBodyRequest & "&ctlBodyPane%24ctl02%24ctl01%24chkUseSaleDate=on"
strBodyRequest = strBodyRequest & "&ctlBodyPane%24ctl02%24ctl01%24cboSaleDate=5" 'DEFINES HOW MANY MONTHS THE SEARCH WILL GO THROUGH
strBodyRequest = strBodyRequest & "&ctlBodyPane%24ctl02%24ctl01%24txtSaleDateHigh_VCS3Ag=" & Month(Now) & "%2F" & Day(Now) & "%2F" & Year(Now)
strBodyRequest = strBodyRequest & "&ctlBodyPane%24ctl02%24ctl01%24txtCSRPointsHigh="
'OPENING Comp Search Website(SHOWING RESULTS)- STEP 9
'SEND THE REQUEST
XMLpagina.Open "POST", strURL, False
XMLpagina.setRequestHeader "Content-type", "application/x-www-form-urlencoded"
XMLpagina.setRequestHeader "Content-Length", Len(strBodyRequest)
XMLpagina.send strBodyRequest
'GENERATE A LOCAL COPY OF THE RESPONSE
Call generarCopiaHtml(XMLpagina)
'BUILDING THE URL FOR THE NEXT REQUEST
strT1 = "{'Name':'Comp Results','PageId':"
strT1 = Replace(strT1, "'", """")
strT2 = ",'PageTypeId':"
strT2 = Replace(strT2, "'", """")
strT3 = ",'Icon"
strT3 = Replace(strT3, "'", """")
strPageID = extraeVerg(XMLpagina.responseText, strT1, strT2)
strPageTypeID = extraeVerg(XMLpagina.responseText, strT1 & strPageID & strT2, strT3)
'THE strURL MUST BE EXACTLY LIKE "https://beacon.schneidercorp.com/Application.aspx?AppID=84&LayerID=795&PageTypeID=3&PageID=579"
strURL = "https://beacon.schneidercorp.com/Application.aspx?AppID=84&LayerID=795&PageTypeID=" & strPageTypeID & "&PageID=" & strPageID
'GETTING THE VALUES TO BE SEND ON THE REQUESTBODY
strT1 = "<input type='hidden' name='__VIEWSTATE' id='__VIEWSTATE' value='"
strT1 = Replace(strT1, "'", """")
strT2 = "' />"
strT2 = Replace(strT2, "'", """")
strVState = extraeVerg(XMLpagina.responseText, strT1, strT2)
'SETS THE REQUESTBODY
strETarget = "ctlBodyPane$ctl02$ctl01$gvwAgCompResults$ctl45$lnkRecording" 'THIS VALUE MIMICS THE CLICK ON THE RECORD "2020-0418" RELATED TO THE PARCEL ID "088327354400002"
strBodyRequest = "__EVENTTARGET=" & Application.WorksheetFunction.EncodeURL(strETarget)
strBodyRequest = strBodyRequest & "&__EVENTARGUMENT="
strBodyRequest = strBodyRequest & "&__VIEWSTATE=" & strVState
strBodyRequest = strBodyRequest & "&__VIEWSTATEGENERATOR=569DB96F"
'SEND THE REQUEST
XMLpagina.Open "POST", strURL, False
XMLpagina.setRequestHeader "Content-type", "application/x-www-form-urlencoded"
XMLpagina.setRequestHeader "Content-Length", Len(strBodyRequest)
XMLpagina.send strBodyRequest
'GENERATE A LOCAL COPY OF THE RESPONSE
Call generarCopiaHtml(XMLpagina)
'ON THIS POINT I SHOULD BE GETTING INSIDE THE "Results" WEBSITE WITH AN URL LIKE THIS
' "https://beacon.schneidercorp.com/Application.aspx?AppID=84&LayerID=795&PageTypeID=3&PageID=551"
'WHICH GIVES A LIST OF THE PARCELS INVOLVED IN THE SALE, BUT IT STILL SHOWS THE LAST PAGE RESULTS...
'I CAN'T SEE WHAT AM I DOING WRONG...
End Sub
My real goal is to repeat this process to get data from some specific sales of all Iowa State Counties, but when I do the first all other won't be a problem.
Can someone show me what am I doing to wrong to make this work?
PS1: I apologize for another question related to the same problem, that I made about ten days ago, which was wrong from top to bottom, I was so tired then that I wrote some crazy stuff.
PS2: Out there seems to be a lot of information about this, but whether I'm not prepared enough to get the solution or my case is not too frequent.
Related
Using VBA, I am able to authenticate the user and obtain 'code' successfully using my sandbox account. However, when I attempt to exchange the permission token for an access token, I get status code 400, Bad Request (unsupported_grant_type). I searched for similar problems and tried many suggestions to no avail. I have been successful in using the implicit grant process, but would like to now switch to code grant. I validated the Base64 conversion using an online tool. It worked fine. The process looks very simple and straight forward. Any help is much appreciated.
The VBA code I'm using follows:
strURL = "https://account-d.docusign.com/oauth/token"
strAuthorization = Base64EncodeString(gstrIntegrationKey & ":" & gstrSecretKey)
Set objJSON = New Dictionary
objJSON.Add "grant_type", "authorization_code"
objJSON.Add "code", strCode
strJSON = JsonConverter.ConvertToJson(objJSON)
Set objHTTP = New MSXML2.XMLHTTP60
objHTTP.Open "POST", strURL, False
objHTTP.setRequestHeader "Content-Type: ", "application/x-www-form-urlencoded"
objHTTP.setRequestHeader "Accept: ", "application/json"
objHTTP.setRequestHeader "Authorization: ", "Basic " & strAuthorization
objHTTP.send strJSON
Do Until objHTTP.ReadyState = 4
DoEvents
Loop
strResponse = Replace(objHTTP.responseText, "null", """null""")
If objHTTP.Status <> 200 Then
If Not DocuSignErr(strResponse, objHTTP.Status, objHTTP.statusText) Then Stop
GoTo FailedExit
End If
The body should be form URL encoded not JSON encoded. Instead of using the Dictionary and running it through JsonConverter.ConvertToJson, you should encode it in as a form (e.g., value1=a&value2=b). So, you can do something like this:
strURL = "https://account-d.docusign.com/oauth/token"
strAuthorization = Base64EncodeString(gstrIntegrationKey & ":" & gstrSecretKey)
Set objHTTP = New MSXML2.XMLHTTP60
objHTTP.Open "POST", strURL, False
objHTTP.setRequestHeader "Content-Type: ", "application/x-www-form-urlencoded"
objHTTP.setRequestHeader "Accept: ", "application/json"
objHTTP.setRequestHeader "Authorization: ", "Basic " & strAuthorization
objHTTP.send "grant_type=authorization_code&code=" & strCode
...
I'm trying to download files(PDFs) silently from a website with VBA. So far I login without issue entering UserName & Password on the initial screen, navigate to the reports page within the site, get my list of files successfully in a table. I get the URL of the file in question without issue. Here's where I hit a wall. I do download a file but get a security warning when i open it that I must be logged in to view it. I can simulate this warning by pasting a URL into any browser when I'm not logged in & they look the same. So I'm downloading but not authenticating.
The code just on the download issue:
Dim strCookie As String
Dim strResponse As String
Dim xobj As Object
Dim WinHttpReq As Object
Dim WinHttpReq2 As Object
Dim oStream As Object
' Set xobj = New WinHttp.WinHttpRequest
strDocLink = "https://atlasbridge.com" & strDocLink & "&RT=PREVMAIL"
Debug.Print strDocLink
' launch tab & goto url/doc
' try to download the link(this is the url of the file)
' strDocLink
Set WinHttpReq = CreateObject("WINHTTP.WinHTTPRequest.5.1")
strUrl = "https://atlasbridge.com/search/AgencyReports.aspx"
WinHttpReq.Open "GET", strUrl, False
WinHttpReq.Option(WinHttpRequestOption_EnableRedirects) = False
WinHttpReq.setRequestHeader "Referer", "https://atlasbridge.com/search/AgencyReports.aspx"
WinHttpReq.setRequestHeader "User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
WinHttpReq.setRequestHeader "Connection", "keep-alive"
WinHttpReq.setRequestHeader "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
WinHttpReq.setRequestHeader "Accept-Language", "en-US,en;q=0.5"
WinHttpReq.Send
If WinHttpReq.Status = 200 Then
strResponse = WinHttpReq.responseText
Debug.Print strResponse
strCookie = WinHttpReq.getResponseHeader("Set-Cookie") ' this only gets the cookie; cookie seems include the session id
resp = WinHttpReq.getAllResponseHeaders
' resp = WinHttpReq.responseBody
' strCookie = WinHttpReq.getResponseHeader("Cookie") ' doesnt find the requested header
Debug.Print strCookie
Debug.Print resp
End If
' then open second session & try to get document
Set WinHttpReq2 = CreateObject("WINHTTP.WinHTTPRequest.5.1")
WinHttpReq2.Open "GET", strDocLink, False
WinHttpReq2.setRequestHeader "User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
WinHttpReq2.setRequestHeader "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
WinHttpReq2.setRequestHeader "Accept-Language", "en-US,en;q=0.5"
WinHttpReq2.setRequestHeader "Referer", "https://atlasbridge.com/search/AgencyReports.aspx"
WinHttpReq2.setRequestHeader "Connection", "keep-alive"
WinHttpReq2.setRequestHeader "Host", "atlasbridge.com:443" '
WinHttpReq2.setRequestHeader "Accept-Encoding", "gzip, deflate, br"
' WinHttpReq2.setRequestHeader "Transfer-Encoding", "chunked"
' doesnt like this one causes error on the .send
WinHttpReq2.setRequestHeader "Cache-Control", "private"
WinHttpReq2.setRequestHeader "Upgrade-Insecure-Requests", "1"
WinHttpReq2.setRequestHeader "Content-Type", "application/pdf"
WinHttpReq2.setRequestHeader "Cookie", strCookie
WinHttpReq2.Send
If WinHttpReq2.Status = 200 Then
Set oStream = CreateObject("ADODB.Stream")
oStream.Open
oStream.Type = 1
oStream.Write WinHttpReq2.responseBody
oStream.SaveToFile "C:\Users\MyUserName\Desktop\DownloadedMail\atlasreportdownload.ashx.pdf", 1 ' 1 = no overwrite, 2 = overwrite
oStream.Close
End If
I've tried a few different things, but I don't believe I'm getting the full cookie & session ID.
The cookie I get back in WinHttpReq.getResponseHeader("Set-Cookie") or getAllResponseHeaders looks like:
NSC_bumbtcsjehf.dpn_TTM_443_MCWT=ffffffffc3a00a0a000000000005e445a4a423660;Version=1;Max-Age=2400;path=/;secure;httponly
But when I use LiveHeaders in Firefox I see:
Cookie: ASP.NET_SessionId=z2e4adilfjgiyynx2mntnh1k; NSC_bumbtcsjehf.dpn_TTM_443_MCWT=ffffffffc3a00a0a000000000005e445a4a423660; AuthToken=0be22946-a97a-442e-bd93-c80f0c96a525; AtlasLastMessage=1173; lc_sso7549731=1546651094987; __lc.visitor_id.7549731=S1546651090.26728e19e6
But I can't seem to expose that full cookie with AuthToken & Session ID, etc. when I Debug.Print the response. Can someone point me in the right direction so I can test a variation on what I'm doing? Thank you in advance.
Update: The response headers from the first request:
Cache-Control: private
Date: Wed, 16 Jan 2019 22:04:54 GMT
Content-Length: 164
Content-Type: text/html; charset=utf-8
Location: /default.aspx?err=Expired&dest=%2fhome.aspx
Server: Microsoft-IIS/7.0
Set-Cookie: ASP.NET_SessionId=mo0owzztbul5of0litxox5kx; path=/; secure; HttpOnly
Set-Cookie: NSC_bumbtcsjehf.dpn_TTM_443_MCWT=ffffffffc3a00a1a45525d5f4f58455e445a4a423660;Version=1;Max-Age=2400;path=/;secure;httponly
X-AspNet-Version: 4.0.30319
X-UA-Compatible: IE=edge
X-Powered-By: ASP.NET
I'm working on downloading the response body now.
I'm sending HTML emails via Gmail REST API in VBA and the HTML image is not showing up in the sent message. I've added an img title tag, I've tried an approved "ci3.googleusercontent.com" version of the image as the source, tried png & jpg. Since I'm sending the email information in the POST request's body I don't think I need to use Base64. There aren't any spaces so shouldn't have to worry about %20 and converting to +.
Any other ideas?
Sub SendGmail()
Dim result As String, myURL As String, postData As String
Dim winHttpReq As Object
Dim x As Integer
Set winHttpReq = CreateObject("WinHttp.WinHttpRequest.5.1")
myURL = "https://www.googleapis.com/upload/gmail/v1/users/me/messages/send"
postData = "From: 'Michael F' <mf#example.com>" & vbCr & _
"Subject: Test Message " & Now() & vbCr & _
"Reply-To: support#example.com" & vbCr & _
"To: JoeTest#gmail.com" & vbCr & _
"Content-Type: text/html; charset=utf-8" & vbCr & _
"Content-Transfer-Encoding: quoted-printable" & vbCr & vbCr & _
"<b>Test Message</b><p>" & vbCr & vbCr & _
"<img alt='ExampleLogo' " & _
"title='ExampleLogo' src='http://www.example.com/LogoSignature.png'>"
'*Putting 3D right after src= solved the problem!*
winHttpReq.Open "POST", myURL, False
winHttpReq.SetRequestHeader "Host", "www.googleapis.com"
winHttpReq.SetRequestHeader "Content-Length", Len(postData)
winHttpReq.SetRequestHeader "Content-Type", "message/rfc822"
winHttpReq.SetRequestHeader "Authorization", "Bearer <mycode>"
winHttpReq.Send (postData)
Set winHttpReq = Nothing
End Sub
Here is an excerpt of the received email HTML source. The sent email in my Sent folder doesn't show the image either, but the HTML is there which is also strange...
MIME-Version: 1.0
X-Received: by 10.50.30.9 with SMTP id o9mr838664igh.36.1434063589114; Thu, 11
Jun 2015 15:59:49 -0700 (PDT)
Received: from 4.apps.googleusercontent.com named unknown by
gmailapi.google.com with HTTPREST; Thu, 11 Jun 2015 18:59:48 -0400
From: "'Michael F'" <mf#example.com>
Reply-To: support#example.com
Date: Thu, 11 Jun 2015 18:59:48 -0400
Message-ID: <CAKUypCw#mail.gmail.com>
Subject: Test Message 6/11/2015 17:59:51
To: JoeTest#gmail.com
Content-Type: multipart/alternative; boundary=047d7bd76aead100b6051845f2ef
--047d7
Content-Type: text/plain; charset=UTF-8
*Test Message*
--047d7
Content-Type: text/html; charset=UTF-8
<b>Test Message</b><p>
<img></p>
--047d7--
I found a solution but hoping someone can explain what is going on. I was having issues with an HTML image showing up in emails I sent from Gmail REST. However, I found if I put "3D" in front of the image source ie <img src=3D'http://www.example.com/logo.png'> the image will show up in the email. Some searching shows the 3D has something to do with quote pointable but I don't understand that. What is the purpose of the 3D? Is there any danger using it?
Found this old SO thread which explains:
I am trying to write VBA to post json to an api and parse the results into a worksheet. I can generate the JSON and am confident I can parse the result into what I need.
I know there are online tools to convert json to vba and back and browser add ins to post requests but I am the only one in the office that can do this so if I'm sick or on leave I would like to automate it. To do that I need to send the json and maybe store the response so I can parse it.
I'm new to coding so posting a request like this is over my head.
So far I have the following code to write the json. I would appreciate any help in getting me started. If needed I can post a sample of the json or the api I would like to post it to.
Apologies for the poor code I know I can improve it but want to get the json response as I think it will be the most challenging part.
EDIT Have made some progress. Can now send a JSON string to the URL and get the response. However it is always returning a failure:
"{
""message"": ""An error has occurred.""
}"
If I manually send the json with httpRequestor the result is returned correctly.
This seems to suggest that somewhere in the code the JSON is getting mixed up or modified somehow when it is being posted.
Updated code below. (Have removed any reference to actual data)
EDIT 2 fixed and working.
Removed quotes from
objHTTP.send ("Json")
Private Sub CommandButton21_Click()
Dim h_1 As String
Dim h_2 As String
h_1 = Range("A1")
h_2 = Range("B1")
h_3 = Range("C1")
h_4 = Range("D1")
h_5 = Range("E1")
h_6 = Range("F1")
sv_1 = 2
sv_2 = 2
sv_3 = 2
sv_4 = 2
sv_5 = 2
sv_6 = 2
For f = 15 To 21
v_1 = Range("A" & sv_1)
v_2 = Range("B" & sv_2)
v_3 = Range("C" & sv_3)
v_4 = Range("D" & sv_4)
v_5 = Range("E" & sv_5)
v_6 = Range("F" & sv_6)
y = "[{""" & h_1 & """:""" & v_1 & """,""" & h_2 & """:""" & v_2 & """,""" & h_3 & """:""" & v_3 & """,""" & h_4 & """:""" & v_4 & """,""" & h_5 & """:""" & v_5 & """,""" & h_6 & """:""" & v_6 & """ }]"
Range("A" & f).Value = y
sv_1 = sv_1 + 1
sv_2 = sv_2 + 1
sv_3 = sv_3 + 1
sv_4 = sv_4 + 1
sv_5 = sv_5 + 1
sv_6 = sv_6 + 1
Next f
Dim objHTTP As Object
Dim Json As String
Json = Range("A15")
Dim result As String
'Set objIE = CreateObject("InternetExplorer.Application") ' Don't think this is needed
'objIE.navigate "about:blank" ' Don't think this is needed
'objIE.Visible = False ' Don't think this is needed
Set objHTTP = CreateObject("MSXML2.ServerXMLHTTP")
URl = "http://myApi/iSendJsonTo"
objHTTP.Open "POST", URl, False
'objHTTP.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
objHTTP.setRequestHeader "Content-type", "application/json"
objHTTP.send ("Json")
result = objHTTP.responseText
'objIE.document.Write result ' Don't think this is needed
'Some simple debugging
Range("A25").Value = result
Range("A26").Value = Json
Set objHTTP = Nothing
Here is the code that is sending the JSON, cleaned up a little.
Dim objHTTP As Object
Dim Json As String
Json = Range("A15") 'here I am pulling in an existing json string to test it. String is created in other VBA code
Dim result As String
Set objHTTP = CreateObject("MSXML2.ServerXMLHTTP")
URl = "http://myApi/iSendJsonto/"
objHTTP.Open "POST", URl, False
objHTTP.setRequestHeader "Content-type", "application/json"
objHTTP.send (Json)
result = objHTTP.responseText
'Some simple debugging
Range("A25").Value = result
Range("A26").Value = Json
Set objHTTP = Nothing
I currently have a spreadsheet where a macro creates a JSON string and posts it to a web service using HTTP. On windows this code works fine for this:
Private Sub pvPostString(sUrl As String, sString As String, sFileName As String, Optional ByVal bAsync As Boolean)
Const STR_BOUNDARY As String = "3fbd04f5-b1ed-4060-99b9-fca7ff59c113"
Dim nFile As Integer
Dim baBuffer() As Byte
Dim sPostData As String
Dim connUrl As String
sPostData = sString
'--- prepare body
sPostData = "--" & STR_BOUNDARY & vbCrLf & _
"Content-Disposition: form-data; name=""uploadfile""; filename=""" & Mid$(sFileName, InStrRev(sFileName, "\") + 1) & """" & vbCrLf & _
"Content-Type: application/octet-stream" & vbCrLf & vbCrLf & _
sPostData & vbCrLf & _
"--" & STR_BOUNDARY & "--"
'--- post
With CreateObject("MSXML2.XMLHTTP")
.Open "POST", sUrl, bAsync
.SetRequestHeader "Content-Type", "multipart/form-data; boundary=" & STR_BOUNDARY
.Send pvToByteArray(sPostData)
End With
End Sub
However on the latest Mac Excel I get an error "ActiveX component can't create object". This makes sense as MSXML2.XMLHTTP is a Microsoft solution, however it means I need to find a replacement function.
I've done lots of googling on this matter and from what I have read I may be able to achieve this using query tables. However, I have tried all sorts of configurations but with no joy. For example if I try the following then I get the error "Invalid web query"
With ActiveSheet.QueryTables.Add(Connection:=connUrl, Destination:=Range("C30"))
.PostText = myJSONString
.RefreshStyle = xlOverwriteCells
.SaveData = True
.Refresh
End With
This makes sense as JSON isn't valid post text, though at the same time posting a lengthy JSON file as post text doesn't really seem like the right solution.
Ideally I would like to post the JSON as a file so that it can be referenced on the server by $_FILES[]. Though from what I've read it isn't clear on how to do this (or if it is possible at all).
tldr; Ultimately my objective with this is to have a function that allows me to post a lengthy JSON string via http that will work on both Windows and Mac. I would really appreciate any help on this.
VBA-Web (previously Excel-REST) supports both Windows in Mac in v4.0.0 and allows you to GET, POST, PUT, PATCH, and DELETE from VBA. I haven't tried it with file uploads, so I'm not sure it will work in your case, but I'd give it a try. Here's a sample:
' Replace with the following
' With CreateObject("MSXML2.XMLHTTP")
' .Open "POST", sUrl, bAsync
' .SetRequestHeader "Content-Type", "multipart/form-data; boundary=" & STR_BOUNDARY
' .Send pvToByteArray(sPostData)
' End With
' Client for executing requests
Dim Client As New WebClient
' Generally set Client.BaseUrl here, but it's not required
' Request for setting request details
Dim Request As New WebRequest
Request.Method = WebMethod.HttpPost
Request.Resource = sUrl
Request.ContentType = "multipart/form-data; boundary=" & STR_BOUNDARY
' Execute request and store response
Dim Response As WebResponse
Set Response = Client.Execute(Request)