Download Files (PDF) from Web - vba

I am fresh-starter at VBA.
How do I download PDF file using UrlDownloadToFile from http://cetatenie.just.ro/wp-content/uploads/?
Can anybody help with this? The code is searching the PDF files udner hyperlinks and matches them under some criteria, i.e. the current year under their name.
Function UrlDownloadToFile(lNum As Long, sUrl As String, sPath As String, _
lNum1 As Long, lNum2 As Long) As Long
UrlDownloadToFile = 0
End Function
Sub DownPDF()
' This macro downloads the pdf file from webpage
' Need to download MSXML2 and MSHTML parsers and install
Dim sUrl As String
Dim xHttp As MSXML2.XMLHTTP
Dim hDoc As MSHTML.HTMLDocument
Dim hAnchor As MSHTML.HTMLAnchorElement
Dim Ret As Long
Dim sPath As String
Dim i As Long
sPath = "C:\Documents and Settings\ee28118\Desktop\"
sUrl = "http://cetatenie.just.ro/wp-content/uploads/"
'Get the directory listing
Set xHttp = New MSXML2.XMLHTTP
xHttp.Open "GET", sUrl
xHttp.send
'Wait for the page to load
Do Until xHttp.readyState = 4
DoEvents
Loop
'Put the page in an HTML document
Set hDoc = New MSHTML.HTMLDocument
hDoc.body.innerHTML = xHttp.responseText
'Loop through the hyperlinks on the directory listing
For i = 0 To hDoc.getElementsByTagName("a").Length - 1
Set hAnchor = hDoc.getElementsByTagName("a").Item(i)
'test the pathname to see if it matches your pattern
If hAnchor.pathname Like "Ordin-*.2013.pdf" Then
Ret = UrlDownloadToFile(0, sUrl & hAnchor.pathname, sPath, 0, 0)
If Ret = 0 Then
Debug.Print sUrl & hAnchor.pathname & " downloaded to " & sPath
Else
Debug.Print sUrl & hAnchor.pathname & " not downloaded"
End If
End If
Next i
End Sub

Sorry - I should have guessed that URLDownloadToFile was an API call and could have answered the whole question at SQL "%" equivalent in VBA.
Remove the function named URLDownloadToFile completely. Paste this at the top of the module where your Sample procedure is
Private Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
(ByVal pCaller As Long, _
ByVal szURL As String, _
ByVal szFileName As String, _
ByVal dwReserved As Long, _
ByVal lpfnCB As Long) As Long
Now change that one line in Sample to look like this
Ret = URLDownloadToFile(0, sUrl & hAnchor.pathname, sPath & hAnchor.pathname, 0, 0)
Then you should be good to go. If you want some different file name, then you'll have to code some logic to change it at each iteration.

Related

Why does my Access database object variable lose connection to its source file midway through reading its Modules container?

We use a VBA tool to extract modules, forms and reports from our Access applications and create an executable for users. This tool has been working without any problems until very recently. However, when I use it to extract from a couple of applications, I keep on encountering an "Automation Error (The remote procedure call failed)" error. However, my colleague (running the same code on a virtually identical build) is able to run it ok.
This is running on Win10 Pro (v2004 - 19041.685), Office 2016 Pro Plus (16.0.4266.1001). I believe my colleague's machine should be the same, as we have only just moved across to these laptops.
This is the core code:
Public Sub ExportAll()
On Error GoTo ErrorProc
Dim oAccessApp As Access.Application
Dim oDoc As Document
Dim sFilePath As String
Dim oDb As Database
Dim fso As FileSystemObject
Dim strFile As String
Dim strFolder As String
strFile = "accdb path"
strFolder = oApp.GetFolder(strFile)
Set oAccessApp = oApp.OpenDatabase(strFile)
Set oDb = oAccessApp.CurrentDb
Set fso = New FileSystemObject
If Not fso.FolderExists((strFolder) & "\SCC") Then
fso.CreateFolder strFolder & "\SCC"
End If
If Not fso.FolderExists(strFolder & "\SCC\Modules") Then
fso.CreateFolder strFolder & "\SCC\Modules"
End If
If Not fso.FolderExists(strFolder & "\SCC\Forms") Then
fso.CreateFolder strFolder & "\SCC\Forms"
End If
If Not fso.FolderExists(strFolder & "\SCC\Reports") Then
fso.CreateFolder strFolder & "\SCC\Reports"
End If
For Each oDoc In oDb.Containers("Modules").Documents
DoEvents
sFilePath = strFolder & "\SCC\Modules\" & oDoc.Name & ".bas.txt"
oAccessApp.SaveAsText acModule, oDoc.Name, sFilePath
Next
For Each oDoc In oDb.Containers("Forms").Documents
DoEvents
sFilePath = strFolder & "\SCC\Forms\" & oDoc.Name & ".frm.txt"
oAccessApp.SaveAsText acForm, oDoc.Name, sFilePath
Next
For Each oDoc In oDb.Containers("Reports").Documents
DoEvents
sFilePath = strFolder & "\SCC\Reports\" & oDoc.Name & ".rpt.txt"
oAccessApp.SaveAsText acReport, oDoc.Name, sFilePath
Next
oDb.Close
Set oDb = Nothing
oAccessApp.Quit
Set oAccessApp = Nothing
Exit Sub
ErrorProc:
If Not (oAccessApp Is Nothing) Then
oAccessApp.Quit
End If
Set oAccessApp = Nothing
MsgBox Err.Description, vbExclamation, "Error " & Err.Number
End Sub
As the extraction takes place, the database being extracted should remain open throughout. Each failure occurs in the For Each oDoc In oDb.Containers("Modules").Documents loop, and happens when a particular module is referenced by the oDoc variable. When I step through and reach the offending module, all is fine until the line with oDoc.Name is hit, at which point the database closes and all the messages for the object oDb reads "".
The module causing the problem is below:
Option Compare Database
Option Explicit
'
' Opens file using default program
' (.xls files open in Excel, .doc files open in Word, etc)
'
'Code Courtesy of
'Dev Ashish
#If Win64 Then
Private Declare PtrSafe Function apiShellExecute Lib "shell32.dll" Alias "ShellExecuteA" ( _
ByVal hWnd As LongPtr, ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As LongPtr
#Else
Private Declare Function apiShellExecute Lib "shell32.dll" _
Alias "ShellExecuteA" _
(ByVal hwnd As Long, _
ByVal lpOperation As String, _
ByVal lpFile As String, _
ByVal lpParameters As String, _
ByVal lpDirectory As String, _
ByVal nShowCmd As Long) _
As Long
#End If
Public Enum ShellExecuteWinStyle
WIN_NORMAL = 1 'Open Normal
WIN_MAX = 2 'Open Maximized
WIN_MIN = 3 'Open Minimized
End Enum
Private Const ERROR_SUCCESS = 32&
Private Const ERROR_NO_ASSOC = 31&
Private Const ERROR_OUT_OF_MEM = 0&
Private Const ERROR_FILE_NOT_FOUND = 2&
Private Const ERROR_PATH_NOT_FOUND = 3&
Private Const ERROR_BAD_FORMAT = 11&
'
' Opens file using default program
' (.xls files open in Excel, .doc files open in Word, etc)
'
Function ShellExecute(strFile As Variant, lShowHow As ShellExecuteWinStyle)
#If Win64 Then
Dim lRet As LongPtr
#Else
Dim lRet As Long
#End If
Dim varTaskID As Variant
Dim stRet As String
Dim stFile As String
If IsNull(strFile) Or strFile = "" Then Exit Function
stFile = strFile
'First try ShellExecute
lRet = apiShellExecute(hWndAccessApp, vbNullString, _
stFile, vbNullString, vbNullString, lShowHow)
If lRet > ERROR_SUCCESS Then
stRet = vbNullString
lRet = -1
Else
Select Case lRet
Case ERROR_NO_ASSOC:
'Try the OpenWith dialog
varTaskID = Shell("rundll32.exe shell32.dll,OpenAs_RunDLL " _
& stFile, WIN_NORMAL)
lRet = (varTaskID <> 0)
Case ERROR_OUT_OF_MEM:
stRet = "Error: Out of Memory/Resources. Couldn't Execute!"
Case ERROR_FILE_NOT_FOUND:
stRet = "Error: File not found. Couldn't Execute!"
Case ERROR_PATH_NOT_FOUND:
stRet = "Error: Path not found. Couldn't Execute!"
Case ERROR_BAD_FORMAT:
stRet = "Error: Bad File Format. Couldn't Execute!"
Case Else:
End Select
End If
ShellExecute = lRet & _
IIf(stRet = "", vbNullString, ", " & stRet)
End Function
I have tried the following:
removing the problem module (process completes successfully)
renaming the module
removing pro-compile conditional statements
moving extraction code to a new database
extracting from database with only problem module plus module with comments
repair MS Office
reinstall MS Office
downgrade Windows updates
Does anyone have any idea why this might be failing? Any suggestions on how to rectify would be really appreciated.

Downloading all files with the prefix from the website in VBA

I have a website where there are 100 links to csv files that are automatically downloaded after clicking. Each of the files has a prefix in the form aaa_.
The following standard code allows you to save a file based on the URL to the selected location on the disk:
Sub Download_from_website()
Dim myURL As String
myURL = "https://mysite/2500/csv/aaa_1.csv"
Dim WinHttpReq As Object
Set WinHttpReq = CreateObject("Microsoft.XMLHTTP")
WinHttpReq.Open "GET", myURL, False
WinHttpReq.Send
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\tkp\Desktop\download_from_website\aaa_1.csv")
oStream.Close
End If
End Sub
How can you transform the above code so that you can automatically search the web page to find all links in which the string aaa_ appears and automatically save in the selected location? I will be very grateful for any tips.
The above code was a simplified example of what I would like to get. However, in fact I would like to save all the files that have the SEB_ prefix from the site
https://sebgroup.lu/private/luxembourg-based-funds/download-of-portfolio-holdings
This should manage them
Option Explicit
#If VBA7 And Win64 Then
Private Declare PtrSafe Function URLDownloadToFile Lib "urlmon" _
Alias "URLDownloadToFileA" ( _
ByVal pCaller As LongPtr, _
ByVal szURL As String, _
ByVal szFileName As String, _
ByVal dwReserved As LongPtr, _
ByVal lpfnCB As LongPtr _
) As Long
#Else
Private Declare Function URLDownloadToFile Lib "urlmon" _
Alias "URLDownloadToFileA" ( _
ByVal pCaller As Long, _
ByVal szURL As String, _
ByVal szFileName As String, _
ByVal dwReserved As Long, _
ByVal lpfnCB As Long _
) As Long
#End If
Public Const BINDF_GETNEWESTVERSION As Long = &H10
Public Sub GetLinks()
Dim sResponse As String, html As New HTMLDocument
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", "https://sebgroup.lu/private/luxembourg-based-funds/download-of-portfolio-holdings", False
.send
sResponse = StrConv(.responseBody, vbUnicode)
End With
sResponse = Mid$(sResponse, InStr(1, sResponse, "<!DOCTYPE "))
With html
.body.innerHTML = sResponse
Dim list As Object, i As Long
Set list = html.getElementsByClassName("linklist")(0).getElementsByTagName("a")
For i = 0 To list.Length - 1
If instr(list(i).getAttribute("href"),"SEB_") > 0 Then
downloadfile list(i).getAttribute("href")
End If
Next i
End With
End Sub
Public Sub downloadfile(ByVal url As String)
Dim fileName As String, fileNames() As String, folderName As String
fileNames = Split(url, "/")
fileName = fileNames(UBound(fileNames))
folderName = "C:\Users\User\Desktop\CurrentDownloads\" & fileName '<==change as required
Dim ret As Long
ret = URLDownloadToFile(0, url, folderName, BINDF_GETNEWESTVERSION, 0)
End Sub
Give the following script a go. I suppose it will fix the issues you are having now. I've written this script considering the fact that you want all the csv files which have seb in their links.
Here you go:
Sub DownloadFilesFromWeb()
Const URL As String = "https://sebgroup.lu/private/luxembourg-based-funds/download-of-portfolio-holdings"
Dim Http As New WinHttp.WinHttpRequest, Html As New HTMLDocument, I&, tempArr As Variant
With Http
.Open "GET", URL, False
.send
Html.body.innerHTML = .responseText
End With
With Html.querySelectorAll(".linklist a[href*='seb']")
For I = 0 To .Length - 1
tempArr = Split(.item(I).getAttribute("href"), "/")
tempArr = tempArr(UBound(tempArr))
Http.Open "GET", .item(I).getAttribute("href"), False
Http.send
With CreateObject("ADODB.Stream")
.Open
.Type = 1
.write Http.responseBody
''notice the following line how the "tempArr" should be appended to the folder you have
.SaveToFile "C:\Users\WCS\Desktop\downloadfile\" & tempArr
.Close
End With
Next I
End With
End Sub
Reference to add to the library:
Microsoft HTML Object Library
Microsoft WinHTTP Services, version 5.1

Downloading a PDF

I am trying to download a .pdf file which opens up in an IE Web browser. Here is my code:
Private Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" _
(ByVal pCaller As Long, _
ByVal szURL As String, _
ByVal szFileName As String, _
ByVal dwReserved As Long, _
ByVal lpfnCB As Long) As Long
Sub DownPDF()
Dim sUrl As String
Dim sPath As String
sPath = "C:\Users\adhil\Documents"
sUrl = "http://analytics.ncsu.edu/sesug/2010/HOW01.Waller.pdf"
Ret = URLDownloadToFile(0, sUrl, sPath, 0, 0)
If Ret = 0 Then
Debug.Print sUrl & " downloaded to " & sPath
Else
Debug.Print sUrl & " not downloaded"
End If
End Sub
However, I am unable to get the file downloaded although response says so.
Can anyone assist me?
The function expects the parameter szFileName to be a fullpath name of a file, not a folder.
Try with this:
sPath = "C:\Users\adhil\Documents\HOW01.Waller.pdf"
I worked with me, while it did not work when the destination file name was omitted.

File download in IE10

I'm working on an internet explorer automation project. The code downloads and saves a file from a website. Its possible to download and save file using 'SendKeys' but its not a reliable method as I cannot detect the download notification:
Is there a way to download and save the file without 'SendKeys'? or at least is there a way to detect the presence of this notification?
Ps - I have referred to these links, which are helpful for IE8 downloads:
http://www.siddharthrout.com/2011/10/23/vbavb-netvb6click-opensavecancel-button-on-ie-download-window/
http://www.siddharthrout.com/2012/02/02/vbavb-netvb6click-opensavecancel-button-on-ie-download-window-part-ii/
Any help?
Why to use SendKeys method to download a file? Sorry, this is wrong approach.
Use API!
Solution 1:
Private Declare Function URLDownloadToFile Lib "urlmon" Alias _
"URLDownloadToFileA" (ByVal pCaller As Long, ByVal szURL As String, ByVal _
szFileName As String, ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
Sub DownloadFilefromWeb()
Dim strSavePath As String
Dim URL As String, ext As String
Dim buf, ret As Long
URL = Worksheets("References & Resources").Range("URLMSL").Value
buf = Split(URL, ".")
ext = buf(UBound(buf))
strSavePath = ThisWorkbook.Path & "\" & "DownloadedFile." & ext
ret = URLDownloadToFile(0, URL, strSavePath, 0, 0)
If ret = 0 Then
MsgBox "Download has been succeed!"
Else
MsgBox "Error"
End If
End Sub
Source: VBA - Save a file from a Website
Solution 2:
Option Explicit
Sub DownloadXLFileFromURL()
Dim myURL As String, sFilename As String
myURL = "http://img.chandoo.org/hw/max-change-problem.xlsx"
sFilename = Environ("SystemDrive") & Environ("HomePath") & _
Application.PathSeparator & "Desktop" & Application.PathSeparator & _
"file.xlsx"
Dim WinHttpReq As Object, oStream As Object
Set WinHttpReq = CreateObject("Microsoft.XMLHTTP")
WinHttpReq.Open "GET", myURL, False ', "username", "password"
WinHttpReq.Send
myURL = WinHttpReq.ResponseBody
If WinHttpReq.Status = 200 Then
Set oStream = CreateObject("ADODB.Stream")
oStream.Open
oStream.Type = 1
oStream.Write WinHttpReq.ResponseBody
oStream.SaveToFile sFilename, 2 ' 1 = no overwrite, 2 = overwrite
oStream.Close
End If
End Sub
Source: Download file from URL using VBA
Solution 3:
Finally, you can create custom class, which can create an instance of MS IE. Now, you are able to control/manage of IE object via using its properties and events, such as DownloadBegin, DownloadComplete, FileDownload
Please, see: Using the WebBrowser Control from Visual Basic
Note: Never before i tried it...

How to download a images from url with authentication

I have a code by which i can download a images from non authentication websites URL. It work fine with those websites, but when i try to download a image by url, website like dropbox. It gives me an error.
Now what i want is this, i want a code by which i can download a images from authenticated and non authenticated website url.
Below is my code:
Option Explicit
Private Declare Function URLDownloadToFile Lib "urlmon" _
Alias "URLDownloadToFileA" (ByVal pCaller As Long, _
ByVal szURL As String, ByVal szFileName As String, _
ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
Dim Ret As Long
'~~> This is where the images will be saved. Change as applicable
Const FolderName As String = "C:\Users\INTEL\Desktop\Hari\Images\"
Sub Sample()
Dim ws As Worksheet
Dim LastRow As Long, i As Long
Dim strPath As String
'~~> Name of the sheet which has the list
Set ws = Sheets("Sheet1")
LastRow = ws.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To LastRow '<~~ 2 because row 1 has headers
strPath = FolderName & ws.Range("A" & i).Value & ".jpg"
Ret = URLDownloadToFile(0, ws.Range("B" & i).Value, strPath, 0, 0)
If Ret = 0 Then
ws.Range("C" & i).Value = "File successfully downloaded"
Else
ws.Range("C" & i).Value = "Unable to download the file"
End If
Next i
End Sub
If your url's are highlighted in blue click on the first one. Excel should open a window where you can authenticate the connection. Enter your username and password for the server and tick checkbox below to save credentials.
If your url's are not highlighted add column next to it with =url(a1) and then click on it.
Once excel remebers your credentials you can execute your script.