简介
批量文件下载器 PowerShell 版,类似于迅雷批量下载功能,且可以破解 Referer 防盗链
源代码
git: https://gitee.com/codefelix/spany-down-ps.git
## =============================================================================== Write-Output "---------------------------------------------" Write-Output "批量文件下载器 PowerShell版" Write-Output "@product spany-down-ps" Write-Output "@author felix" Write-Output "@date 2019-04-19" Write-Output "---------------------------------------------" Write-Output "" ## =============================================================================== # 接收是否输入 function ReadInput_YesOrNo([string]$message, [switch]$defaultValue) { while($true) { $input = Read-Host $message if(![String]::IsNullOrWhiteSpace($input)) { if($input -eq 'y' -or $input -eq 'n') { return $input -eq 'y' } } if($defaultValue) { return $args -eq $true } } } # 接收文本输入 function ReadInput_Text([string]$message, [string]$defaultValue) { while($true) { $input = Read-Host $message if(![String]::IsNullOrWhiteSpace($input)) { return $input.Trim() } if($defaultValue) { return $defaultValue } } } # 接收整数输入 function ReadInput_Integer([string]$message, [int]$minValue=[Int32]::MinValue, [int]$maxValue=[Int32]::MaxValue) { $defaultValue = $message while($true) { $input = Read-Host $message if([String]::IsNullOrWhiteSpace($input)) { $message = $defaultValue continue } $input = $input.Trim() [int]$result = 0 if(![Int32]::TryParse($input, [ref]$result)) { $message = "必须输入一个整数" continue } elseif($result -lt $minValue -or $result -gt $maxValue) { $message = "整数范围必须是 $minValue-$maxValue,请重新输入" continue } return $result } } # 接收URL输入 function ReadInput_Url([string]$message, [string]$defaultValue) { $defaultMessage = $message while($true) { $input = Read-Host $message if([String]::IsNullOrWhiteSpace($input)) { if($defaultValue){ return $defaultValue } $message = $defaultMessage continue } $input = $input.Trim() if($input.Length -lt 18 -or !($input -clike 'http://*' -or $input -clike 'https://*')) { $message = "URL 格式不正确,请重新输入" continue } return $input } } # 接收目录输入 function ReadInput_Path([string]$message, [string]$defaultValue, [bool]$createIfNotExist = $true) { $path = "" while($true) { $input = Read-Host $message if(![String]::IsNullOrWhiteSpace($input)) { $path = $input.Trim() } elseif($defaultValue) { $path = $defaultValue } else { continue } if($createIfNotExist -and ![System.IO.Directory]::Exists($path)) { # 或者 Test-Path -Path $path 但无法识别路径中的括号 New-Item -Path $path -ItemType Directory | Out-Null } return $path } } # 构建URL列表 function BuildUrlList([string]$urlFormat, [int]$start, [int]$end, [int]$len) { if(!$urlFormat.Contains("(*)")) { return ,$urlFormat } $list = @() $last = $end + 1 for($i = $start; $i -lt $last; $i++) { $tmp_url = $urlFormat -replace "\(\*\)",("{0:D$len}" -f $i) ## 或者 $i.ToString("D$len") $list += $tmp_url } return $list } [int]$script:completed = 0 # 下载完成数量 [int]$script:succeed = 0 # 下载成功数量 # 开始下载(普通方法) function StartDownload([array]$urlList, [string]$path, [string]$referer) { $last = $urlList.Count $watch = Measure-Command { for($i = 0; $i -lt $last; $i++) { DownloadItem -url $urlList[$i] -path $path -referer $referer Start-Sleep -Milliseconds 200 # 延迟0.2秒 } } $failed = $script:completed - $succeed $elapsed = [Math]::Round($watch.TotalMilliseconds/1000, 2) # 总计耗时(秒) Write-Output "" Write-Host "总共下载 $script:completed,成功 $script:succeed,失败 $failed,耗时 $elapsed s" -ForegroundColor Red -BackgroundColor Yellow $script:completed = 0 $script:succeed = 0 } # 下载单个文件 function DownloadItem([string]$url, [string]$path, [string]$referer) { $url_file = $url.Substring($url.LastIndexOf('/') + 1); if($referer.Contains("(*)")) { $referer = $referer -replace "\(\*\)", $url } try{ $tmpFileName = [System.IO.Path]::GetTempFileName() $destFileName = [System.IO.Path]::Combine($path, $url_file) $watch = Measure-Command { # 下载文件到临时文件夹 Invoke-WebRequest -Uri $url -Method Get -Headers @{"Referer"=$referer} -UserAgent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36" -TimeoutSec 120 -OutFile $tmpFileName # 将临时文件移动到目标文件夹 Move-Item -Path $tmpFileName -Destination $destFileName -Force } $script:succeed += 1 $fileLength =[Math]::Ceiling((Get-Item -LiteralPath $destFileName).Length / 1024.0) $elapsed = [Math]::Round($watch.TotalMilliseconds) # 下载成功!12.jpg - 115KB/2356ms Write-Host "下载成功!$url_file - $fileLength KB/$elapsed ms" -ForegroundColor Green } catch { Write-Error $PSItem.ToString() } finally { $script:completed += 1 } } # 主函数 运行 AppStart 即可启动 function AppStart { $urlFormat = ReadInput_Url -message "输入URL(含通配符,例如 http://www.spany.com/2019/(*).jpg)" $start = ReadInput_Integer -message "通配符数字开始(0~200)" -minValue 0 -maxValue 200 $end = $start + 200 $end = ReadInput_Integer -message "通配符数字结束($start~$end)" -minValue: $start -maxValue $end $len = ReadInput_Integer -message "通配符数字长度(1~5)" -minValue: 1 -maxValue 5 $referer = ReadInput_Url -message "输入Referer为破解防盗链(如果Referer中含有通配符(*),则将被当前URL替换,如无须Referer则直接回车)" -defaultValue "https://www.baidu.com/visit" Write-Output "" $urlList = BuildUrlList -urlFormat $urlFormat -start $start -end $end -len $len if($urlList.Count -gt 0) { Write-Output "URL列表如下:" foreach($url in $urlList) { Write-Output "`t$url" } Write-Output "" if(ReadInput_YesOrNo -message "是否开始下载?(y/n)") { $path = ReadInput_Path -message "输入文件存储目录" Write-Output "" StartDownload -urlList $urlList -path $path -referer $referer } } else { Write-Warning "不能创建URL列表,请核对参数!" } Write-Output "" } AppStartspany-down-ps.ps1
如何使用
以管理员方式打开 PowerShell 命令终端,定位到文件目录,运行 ./spany-down-ps.ps1 即可,如提示此系统上禁止运行脚本,可执行命令 Set-ExecutionPolicy -ExecutionPolicy Unrestricted 更改执行策略
然后按照屏幕提示,输入必要参数,启动下载进程,截图演示下载美图录的美女写真集(宅男福利啊!)
如果你直接打开图片或者用迅雷批量下载,都将被 403 Forbidden,因为网站启用了 Referer 防盗链
不过 PowerShell 版还是单线程顺序下载,如果不嫌麻烦,想提高下载效率,可以用另一个 C#/.NET Core 版 https://gitee.com/codefelix/spany-down-sharp