Automatically download files from the web - AutoHotkey Script

Published on
4,342 Points
1 Endorsement
Last Modified:
Joe Winograd
50+ years in computer industry•Development•Sales•CIO•Document Imaging
•EE — FELLOW 2017•MVE 2015,2016,2018•RENOWNED EXPERT 2018,2019,2020
In a recent question here at Experts Exchange about Windows 10 automation, a member asked for a solution "to download one by one automatically" 10 specific files from the Internet. This article presents an AutoHotkey script with the solution, enhanced to allow any number of files to be downloaded.

In an interesting question here at Experts Exchange with a subject of "Windows 10 Automation...", a member asked for a solution "to download one by one automatically" ten (10) specific files from the web. I posted a quick-and-dirty script with the solution at the question, then decided to develop a more robust script, which I'm presenting in this article.

I wrote the script in the AutoHotkey language. If you are not familiar with AutoHotkey and this article piques your interest in it, one of my other EE articles will get you started on it:

AutoHotkey - Getting Started

The script presented in this article works as follows:

• Supports the specification of a plain text input file that contains two or three fields on each line. The first field (required) is the full path of the local file on the PC to store the downloaded file. The second field (required) is the web address (URL) of the file to download. The third field (optional) is a comment, providing you with a place to enter any text that you want about the file.

• Allows any number of lines in the input file, with each line representing a file to download.

• Expects the two (or three) fields to be separated from each other with a vertical bar (the "pipe" character) followed by a space. I chose this two-character separator because the vertical bar is invalid in a file name and the space is invalid in a URL. So, the two characters together provide a perfect way to separate the fields. You may change this if you want via the assignment statement that puts a value in the FieldSeparator variable, but keep in mind that you don't want the StrSplit (string split) function to find the separator in the local file name or in the web address. Here's a sample input line:

c:\temp\EE home page.txt| https://www.experts-exchange.com| Experts Exchange home page

Attached is a sample (working) input file — AutoDown.txt.

• Ignores blank (empty/null) lines in the input file (helpful for improving readability).

• Ignores lines in the input file with a semi-colon (;) in the first column. In other words, they're comments (helpful for documenting the input file).

• Creates a logfile (optional) that makes an entry showing the result of processing each line in the input file. There are three possible entries:

Success — means the download succeeded (but see Two Important Caveats below)

Failure — means the download failed

BadItem — means the input line was badly formed, i.e., has fewer than two fields or more than three fields

The first line of the logfile contains the script's Version, the date and time that the run began, and the full path/name of the input file. The last line of the logfile contains the date and time that the run ended, along with summary statistics. Each logfile entry begins with the local time in YYYYMMDDhhmmss format. Here's a screenshot of a sample logfile:

The posted code creates a file name for the logfile that has the date and time in it (including milliseconds) and stores it in the Windows %temp% folder (the AutoHotkey built-in variable A_Temp). As with anything in the script, feel free to change it to suit your needs. In particular, there are numerous variables in the ***begin variables to change*** section of the InitializeVars subroutine that you may want to change — and one that you definitely need to change, namely, the location of the input file (FileListInput).

The sample (plain text) logfile shown in the screenshot above is attached (AutoDown_2020-01-17_14.38.42.468.log).

Two Important Caveats

(1) An existing file will be overwritten by the downloaded file with no warning.

(2) The download may seem successful (ErrorLevel=0) even when the file on the web does not exist. This is because some web servers send an error page when the file is missing, and the downloaded error page will look like a success when it has been successfully downloaded.

• Provides a QuietMode option that allows unattended runs, meaning that it does not display any dialog boxes. The results of the run are available in the logfile (if, of course, the logfile was specified).

• Checks the return code (ErrorLevel) on each download and counts the number of successes and failures (but see Two Important Caveats above). These counts are shown in a closing dialog (along with the number of bad items in the input file), unless it's a QuietMode run. Here's a sample closing dialog:

Clicking Yes opens the logfile in the program that owns the LOG file extension on your system, such as Notepad, and then the script exits. The script exits immediately if you click No.

• Displays a system tray (notification area) icon when it is running that looks like this:

Hovering over the icon produces a tooltip:

This allows you to see easily what file is currently downloading.

Right-clicking on the icon produces this context menu:

Note that the context menu does not appear until it is finished the download that is in progress — be patient — the context menu will eventually appear.

Selecting the About menu choice displays this dialog:

Selecting the Exit menu choice exits (terminates/quits) the script, thereby stopping any remaining downloads. To make sure that this wasn't selected by accident, it displays the dialog below, where No is the default button (so that an accidental Enter key won't cause an unwanted exit):

Here is the script in a code block (it is also attached as a file — AutoDown.ahk — at the end of the article for easy downloading):

; Joe Winograd 17-Jan-2020
#Warn,UseUnsetLocal ; warning on uninitialized variables
#NoEnv ; avoid checking empty variables to see if they are environment variables
#SingleInstance Force ; replace old instance immediately
SetBatchLines,-1 ; run at maximum speed

Gosub,InitializeVars ; initialize all variables
Gosub,ConfigureInitialTray ; configure initial system tray (notification area)

FileRead,FileList,%FileListInput% ; read list of files to download
If (ErrorLevel!=0)
  MsgBox,4112,Error,Error Level %ErrorLevel% trying to read file list:`n`n%FileListInput%
Loop,Parse,FileList,`n,`r ; loop through all files in list
  If (A_LoopField="")
    Continue ; ignore blank lines
  If (SubStr(A_LoopField,1,1)=";") ; semi-colon in column 1 is a comment
    Continue ; ignore comments
  FileListArray:=StrSplit(A_LoopField,FieldSeparator) ; split input line at vertical bar (pipe)
  NumFields:=FileListArray.MaxIndex() ; get number of fields on line
  If ((NumFields<2) or (NumFields>3)) ; number of fields must be 2 or 3
    WriteLogfile("BadItem: " . A_LoopField)
  FileLocal:=FileListArray[1] ; full path to file on computer
  URLweb:=FileListArray[2] ; link to file on web
  TrayTip:=ProgramName . " Version " . Version . "`nDownloading: " . URLweb
  UrlDownloadToFile,%URLweb%,%FileLocal% ; download file
  If (ErrorLevel=0)
    Result:="Success: "
    Result:="Failure: "
  WriteLogfile(Result . A_LoopField)
FormatTime,EndTime,%EndTimeStd%,yyyy-MM-dd_HH.mm.ss ; end time nicely formatted
WriteLogfile("Ending date and time: " . EndTime . "  Succeeded: " . NumSuccess . "  Failed: " . NumFailure . "  Bad: " . NumBad)
If (!QuietMode) ; do not display closing dialog box in quiet mode run
  If (Logfile="") ; no logfile - just display closing dialog and exit
    MsgBox,4160,%ProgramName% Done,Succeeded: %NumSuccess%`nFailed: %NumFailure%`nBad: %NumBad%
  Else ; logfile assigned
    MsgBox,4164,%ProgramName% Done,Succeeded: %NumSuccess%`nFailed: %NumFailure%`nBad: %NumBad%`n`nDo you want to open logfile now?"
    If (!FileExist(Logfile))
      MsgBox,4112,Fatal Error,Unable to create logfile:`n%Logfile%

BeginTimeStd:=A_Now ; begin time in standard time format
FormatTime,BeginTime,%BeginTimeStd%,yyyy-MM-dd_HH.mm.ss ; begin time nicely formatted and valid in file name
SplitPath,A_ScriptName,,,,ProgramName ; get name of script without path or extension

; *** begin variables to change ***
Version:="1.1" ; version number to put in logfile, "About" dialog box, system tray tip
FileListInput:="c:\MyFiles\AutoDown.txt" ; full path to plain text file with a URL and file name on each line (and an optional comment)
Logfile:=A_Temp . "\" . ProgramName . "_" . BeginTime . "." . A_Msec . ".log" ; logfile full path - set to null [Logfile:=""] for no logfile
TrayIconFile:=A_WinDir . "\System32\wpdshext.dll" ; icon from built-in wpdshext.dll file
TrayIconNum:="-751" ; blue down arrow
FieldSeparator:="| " ; pipe (vertical bar) and space - pipe invalid in file name - space invalid in URL
QuietMode:=False ; True ==> suppress all dialogs - for unattended runs
; *** end variables to change ***

NumSuccess:=NumFailure:=NumBad:=0 ; set Success, Failure, and Bad counters to zero
WriteLogfile(ProgramName . " Version " . Version . "   Beginning date and time: " . BeginTime . "   Input File: " . FileListInput) ; write opening logfile record

Menu,Tray,NoStandard ; do not use standard AutoHotkey context menu
Menu,Tray,Add,&About,ContextMenu ; first item is About
Menu,Tray,Add,E&xit,ContextMenu ; last item is Exit
TrayTip:=ProgramName . " Version " . Version
Menu,Tray,Default,&About ; default (double-click) is About

; check which context menu selected
If (A_ThisMenuItem="&About")
  MsgBox,4160,About %ProgramName%,%ProgramName% Version: %Version%
If (A_ThisMenuItem="E&xit") ; true means Exit selected, but make sure it was not accidental
  MsgBox,4388,Terminate %ProgramName%?,Are you sure you want to quit? ; 4388 means No is default button, in case of accidental Enter key
    Return ; user does not really want to quit - stay running
ExitApp ; user wants to quit - terminate app

  global Logfile
  If (Logfile="")
  FileAppend,%A_Now% %Record%`n,%Logfile%
  If (ErrorLevel!=0)
    MsgBox,4112,Fatal Error,Error Level %ErrorLevel% occurred while trying to write record:`n%Record%`nto logfile:`n%Logfile%

I hope that the descriptive variable names and the comments in the script provide enough documentation for readers to understand and modify it, but if you have any questions, please post them here and I'll try to help.

The script should work in all versions of Windows from XP through W10, 32-bit and 64-bit. I tested it on W7/64-bit and W10/64-bit — both worked perfectly.

If you find this article to be helpful, please click the thumbs-up icon below. This lets me know what is valuable for EE members and provides direction for future articles. Thanks very much! Regards, Joe




Ask questions about what you read
If you have a question about something within an article, you can receive help directly from the article author. Experts Exchange article authors are available to answer questions and further the discussion.
Get 7 days free