<

Automatically download files from the web - AutoHotkey Script

Published on
4,468 Points
368 Views
1 Endorsement
Last Modified:
Editors:
Joe Winograd
CERTIFIED EXPERT
50+ years in computer industry
Development•Sales
CIO•Document Imaging
EE — FELLOW 2017
MVE 2015,2016,2018
RENOWNED 2018,2019
GOLD 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%
  Return
}
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
  {
    NumBad:=NumBad+1
    WriteLogfile("BadItem: " . A_LoopField)
    Continue
  }
  FileLocal:=FileListArray[1] ; full path to file on computer
  URLweb:=FileListArray[2] ; link to file on web
  TrayTip:=ProgramName . " Version " . Version . "`nDownloading: " . URLweb
  Menu,Tray,Tip,%TrayTip%
  UrlDownloadToFile,%URLweb%,%FileLocal% ; download file
  If (ErrorLevel=0)
  {
    NumSuccess:=NumSuccess+1
    Result:="Success: "
  }
  Else
  {
    NumFailure:=NumFailure+1
    Result:="Failure: "
  }
  WriteLogfile(Result . A_LoopField)
}
EndTimeStd:=A_Now
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%
    ExitApp
  }
  Else ; logfile assigned
  {
    MsgBox,4164,%ProgramName% Done,Succeeded: %NumSuccess%`nFailed: %NumFailure%`nBad: %NumBad%`n`nDo you want to open logfile now?"
    IfMsgBox,No
      ExitApp
    If (!FileExist(Logfile))
      MsgBox,4112,Fatal Error,Unable to create logfile:`n%Logfile%
    Else
      Run,%Logfile%
  }
}
ExitApp

InitializeVars:
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
Return

ConfigureInitialTray:
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,Tip,%TrayTip%
Menu,Tray,Icon,%TrayIconFile%,%TrayIconNum%
Menu,Tray,Default,&About ; default (double-click) is About
Return

ContextMenu:
; check which context menu selected
If (A_ThisMenuItem="&About")
{
  MsgBox,4160,About %ProgramName%,%ProgramName% Version: %Version%
  Return
}
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
  IfMsgBox,No
    Return ; user does not really want to quit - stay running
}
ExitApp ; user wants to quit - terminate app

WriteLogfile(Record)
{
  global Logfile
  If (Logfile="")
    Return
  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%
    ExitApp
  }
  Return
}


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


AutoDown.ahk

AutoDown.txt

AutoDown_2020-01-17_14.38.42.468.log


1
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