My Excel VBA macro sends a POST multipart/form-data request to an API and receives a application/pdf file as a response.
This is the relevant part:
Set xhr = CreateObject("MSXML2.XMLHTTP")
xhr.Open "POST", Uri, False
xhr.setRequestHeader "Content-Type", "multipart/form-data; boundary=" & strBoundary
xhr.setRequestHeader "X-Api-Key", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
xhr.send (strBody)
If xhr.Status Then
Set oStream = CreateObject("ADODB.Stream")
oStream.Open
oStream.Type = 1
oStream.Write xhr.responseBody
oStream.SaveToFile outputFileName, 2
oStream.Close
End If
Set xhr = Nothing
The downloaded PDF document is unreadable by any PDF reader. I checked its contents and it is almost the same as the downloaded document from other clients (eg Postman, cURL), which are valid PDF documents (ie can be open in PDF readers) [Edited].
For example, when opening the PDF documents in VS Code:
The VBA macro downloaded file:
Compare it to the PDF downloaded with Postman (Check the last line in the picture):
If it was a text file, it would seem as an encoding problem, but as I am using the ADODB.Stream with Type = 1 that should handle binary files well.
What am I missing?
Related
I want to download a zip file from OneDrive using VBA.(UserData folder zipped as UserData.zip and uploaded to the OneDrive location; size: 200KB) For that, I used the following VBA script.(sensitive data altered in the code)
Sub DownloadFile()
'Declare the Object and URL
Dim myURL As String
Dim WinHttpReq As Object
'Assign the URL and Object to Variables
myURL = "https://MYCOMPANYNAME-my.sharepoint.com/personal/MYUSERNAME_MYCOMPANYNAME_com/Documents/FOLDERNAME/UsersData.zip"
Set WinHttpReq = CreateObject("Microsoft.XMLHTTP")
'Provide Access Token and PWD to the URL for getting the service from API
WinHttpReq.Open "GET", myURL, False, "abcdef", "12345"
WinHttpReq.send
Debug.Print WinHttpReq.Status
myURL = WinHttpReq.responseBody
If WinHttpReq.Status = 200 Then
Set oStream = CreateObject("ADODB.Stream")
oStream.Open
oStream.Type = 1
oStream.Write WinHttpReq.responseBody
oStream.SaveToFile "C:\Users\MYUSERNAME\Downloads\UsersData.zip", 2
oStream.Close
MsgBox "File downloaded"
Else
MsgBox "Download failed"
End If
End Sub
When I run it, it downloads the zip file and gives me the "File downloaded" message as well. But when I try to open the downloaded file, unzipping application fails to do that and it seems like the file is corrupted.
This works fine for pdf, jpg, txt and other similar files. Why this happens only in zip files?
What is the issue in my code and is there any other effective ways in VBA to download zip files from OneDrive?
I am trying to download a file from sharepoint via VBScript.
Unfortunately i get the following errormessage after downloading the Excel- File:
"Excel cannot open the file ' xxxxx.xlsx' because the file format or file extension is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file"
My code snipped is the following:
dim bStrm: Set bStrm = createobject("Adodb.Stream")
xHttp.Open "GET", "https://company.sharepoint.com/:x:/r/teams/xxxxx/_layouts/15/Doc.aspx?sourcedoc=%7B5AA396CB-4711-4E73-AEC5-3CB8B6E174D3%7D&file=xxxx%20Automation%xxxx.xlsx&wdOrigin=OFFICECOM-WEB.START.REC&action=default&mobileredirect=true", False
xHttp.Send
with bStrm
.type = 1 '//binary
.open
.write xHttp.responseBody
.savetofile "c:\temp\TestNow.xlsx", 2 '//overwrite
end with
The approach isn't wrong but when dealing with downloads from a URL you should always check the Response Status Code to see if it is valid before continuing.
After calling Send() always surround the response in a conditional statement like this;
If xHttp.Status = 200 Then 'Expecting a HTTP 200 OK response
With bStrm
.Type = 1 '//binary
.Open
.Write xHttp.responseBody
.SaveToFile "c:\temp\TestNow.xlsx", 2 '//overwrite
End With
Else
'Check the response body for details of the error.
MsgBox("Unexpected response: " & xHttp.Status & " - " & xHttp.StatusText, 48, "Error")
End If
Because you are trying to download from a SharePoint site the likelihood is the request is failing and returning an HTTP 403 Forbidden for not providing any authentication.
I have the following code that download xml file with the subtitle of a video from YouTube
Sub Test()
Dim http As Object
Dim oStream As Object
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET", "http://video.google.com/timedtext?lang=en&v=qANA6POtuFo", False
http.send
Set oStream = CreateObject("ADODB.Stream")
oStream.Open
oStream.Type = 1
oStream.Write http.responseBody
oStream.SaveToFile ThisWorkbook.Path & "\Sample.xml", 2
oStream.Close
End Sub
But it doesn't work for other videos
for example I tried this link
v=4Z3EJrh7_5k
Any idea how to do the download with any video with a subtitle?
As far as I researched, you cannot download from 4Z3EJrh7_5k because it's subtitle is not a file someone uploaded, but it is generated automatically.
To see if a video has any subtitle file, you can use http://video.google.com/timedtext?type=list&v=qANA6POtuFo, and it will list every file with languages inserted in the video. You can note that it shows only one, even if you go to the video and click, there are two (English and English (Automatically generated))
So I have a VBA code that is currently successfully logging into a website and further navigating to other pages of the website and scraping data that I need.
I now need to navigate to a page (no problem), fill a textbox with a query (no problem) and click on a 'download' button (no problem). This then prompts a popup to download a file (open/save/cancel). My requirement is to save this file without user interaction - the macro should save the file in a predetermined directory.
Any ideas on how to achieve this? I couldn't get SendKeys to work at all.
Set appIE = New InternetExplorerMedium
sURL2 = "http://somewebsite.com/query.asp?"
With appIE
.Navigate sURL2
.Visible = True
End With
Do While appIE.Busy Or appIE.ReadyState <> 4
DoEvents
Loop
'code to enter the query in textbox and click on download file button
appIE.Document.getElementsByTagName("textarea")(0).Value = Sheets("UserEntry").Range("L37")
appIE.Document.getElementsByName("btnSubmit")(203).Click
Application.SendKeys "%{s}"
Set appIE = Nothing
Edit: Even if I could get SendKeys to work, I need to 'save as' the file automatically, not just 'save' it in the Downloads folder.
Ok, got it working, thanks to the approach suggested by #BrownishMonster
I used WinHTTP.WinHTTPRequest.5.1
I also used Fiddler to investigate what the browser was sending in the POST requests and then made VBA do the same
Set WHTTP = CreateObject("WinHTTP.WinHTTPrequest.5.1")
'This is to POST the login info and login to the site
WHTTP.Open "POST", mainUrl, False
WHTTP.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
WHTTP.send loginString
'This is to POST the download info and download the file
WHTTP.Open "POST", fileUrl_XLSResult, False
WHTTP.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
WHTTP.send downloadString
FileData = WHTTP.responseBody
'This is to save the file in the location MyFilePath
If WHTTP.Status = 200 Then
Set oStream = CreateObject("ADODB.Stream")
oStream.Open
oStream.Type = 1
oStream.Write WHTTP.responseBody
oStream.SaveToFile MyFilePath, 1
oStream.Close
End If
i have tried the following code to download a single Excel file from Sharepoint 2013.
Option Explicit
Sub TxtStream()
Dim myURL As String, DestFile As String, myHeader As String
Dim Usr as string, Pwd as string
Dim oStream As Object
Usr="": Pwd=""
myURL = "https://Server.Name/teams/Forms/AllItems.aspx/MasterFile.xlsx"
DestFile = "C:\Test.xlsx"
Dim WinHttpReq As Object
Set WinHttpReq = CreateObject("MSXML2.XMLHTTP")
'WinHttpReq.Open "HEAD", myURL, False, Usr, Pwd
'WinHttpReq.Send
'myHeader = WinHttpReq.getAllResponseHeaders()
'Debug.Print myHeader
'myHeader = WinHttpReq.getResponseHeader("Content-Disposition")
'Debug.Print myHeader
'myHeader = WinHttpReq.getResponseHeader("Content-Type")
'Debug.Print myHeader
WinHttpReq.Open "GET", myURL, False, Usr, Pwd
WinHttpReq.setRequestHeader "content-type", "application/octet-stream"
WinHttpReq.Send
myURL = WinHttpReq.responsebody
If WinHttpReq.Status = 200 Then
Set oStream = CreateObject("ADODB.Stream")
oStream.Type = 1
oStream.Open
oStream.Position = 0
oStream.Write WinHttpReq.responsebody
oStream.SaveToFile DestFile, 2
oStream.Close
End If
End Sub
It downloads ok, but when i try to open it in Excel 2010, it shoots an error:
Excel cannot open the file Test.xlsx because the file format or file extension is not valid. Verify the file has not been corrupted and the file extension matches the format of the file.
I have checked the Content-Type and it shows as Text/Html;UTF-8. It doesn't show Content-Disposition.
Can someone help as to why the file is not opening?
This is not a full fledged answer, but more like a comment / suggestion as I do not have enough reputation to post comments.
Setting a content-type header in your GET query does not seems to make any difference. We need to check the WinHttpReq.getResponseHeader("Content-Type") sent by the server which in this case seems to be Text/Html;UTF-8.
If you copy paste the URL used in myURL variable to your browser, do you get the "file save as" dialog box?
Better analysis of your requests and responses can be done if you use Fiddler Web Debugger where you can create requests in teh composer and check the responses to finetune your requirements and to see whether any other headers (like cookies, authentications etc) are also required for the file to be downloaded. In this case, you might be getting back a login page (html) because of some authentication issues and not the excel file.
Open the DestFile saved with Notepad.exe to see whether it is actualy an XLSX file (starting with characters PK) or an HTML or other text file.