• powershell 配合aria2实现简单的图片爬取


    powershell 配合aria2实现简单的图片爬取

    01 前言

    现如今,提到爬虫,令人不得不提到Python,确实简单,也强大,到处都可以找到教程。故而今天换换口味,用powershell来实现,配合aria2的强大下载功能,也很nice

    02 正文

    测试环境:Windows 11

    1. 确定目标网站

    这一步通过搜索引擎,很容易就可以找到感兴趣的网站,此处略。

    2. 确定有订阅源地址

    假设目标网站为:https://abc.com,然后在地址栏后面加:/feed,回车访问(即完整的路径为:https://abc.com/feed)。
    如果能够正常访问,且有内容(XML格式),那可以,比如大概长这样:
    xml

    3. 开始处理

    为了方便使用,分为两个部分:powershell脚本bat脚本,那么通过修改bat脚本参数,可以双击直接运行。

    (1)首先应该有aria2,【下载】好并解压。如果本机已经有,就不必下载了。

    (2)powershell脚本代码

    
    
    <#
        xml解析图片地址,调用aria2下载
    
        by hokis
    
        2024-05-29 19:36
    
    #>
    
    [CmdletBinding()]
    Param
    (
        # 域名,一般以/结尾,如:https://abc.com/
        [Parameter(Mandatory=$true,
                    ValueFromPipelineByPropertyName=$true,
                    Position=0)]
        [string]
        $server,
    
        #保存路径,如果为空,则放在 我的/图片 下
        [string]
        $savePath = '',
    
        #aria2.exe所在目录
        [Parameter(Mandatory=$true)]
        [string]
        $aria2Path
    )
    
    
    function Invoke-DownWithAria2
    {
        [CmdletBinding()]
        Param
        (
            # 文件列表,格式:ArrayList 里面放一个2个元素的数组,第一个是URL,第二个是文件名
            [Parameter(Mandatory=$true,
                       ValueFromPipelineByPropertyName=$true,
                       Position=0)]
            [System.Collections.ArrayList]
            $fileList,
    
            #referer
            [string]
            $refer,
    
            [string]
            $newSavePath,
    
            #aria2路径
            [string]
            $aria2Path = ''
        )
    
        Begin
        {
    
        }
        Process
        {
                    #配置模板
            $conf = @'
    
    ## 日志
    log-level=error
    #log=/PATH/.aria2/aria2.log
    
    #控制台日志
    console-log-level=error
    
    ## 文件保存相关 ##
     
    # 文件保存目录
    #dir=
    {0}
    # 启用磁盘缓存, 0为禁用缓存, 需1.16以上版本, 默认:16M
    disk-cache=32M
    # 断点续传
    continue=true
     
    # 文件预分配方式, 能有效降低磁盘碎片, 默认:prealloc
    # 预分配所需时间: none < falloc ? trunc < prealloc
    # falloc和trunc则需要文件系统和内核支持
    # NTFS建议使用falloc, EXT3/4建议trunc, MAC 下需要注释此项
    file-allocation=falloc
     
    ## 下载连接相关 ##
    
    # 最大同时下载任务数, 运行时可修改, 默认:5
    max-concurrent-downloads=10
    # 整体下载速度限制, 运行时可修改, 默认:0(不限制)
    max-overall-download-limit=0
    # 单个任务下载速度限制, 默认:0(不限制)
    #max-download-limit=0
    # 整体上传速度限制, 运行时可修改, 默认:0(不限制)
    #max-overall-upload-limit=0
    # 单个任务上传速度限制, 默认:0(不限制)
    #max-upload-limit=0
    # 禁用IPv6, 默认:false
    disable-ipv6=true
    
    # 客户端伪装
    user-agent=Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36
    #referer=
    {1}
    
    # 最小文件分片大小, 添加时可指定, 取值范围1M -1024M, 默认:20M
    # 假定size=10M, 文件为20MiB 则使用两个来源下载; 文件为15MiB 则使用一个来源下载
    min-split-size=10M
    # 单个任务最大线程数, 添加时可指定, 默认:5
    # 建议同max-connection-per-server设置为相同值
    split=20
     
    # 读取下载任务
    #input-file=
    {2}
    
    '@
            
            if(-not $fileList -or $fileList.Count -lt 1){
                Write-Warning 'file should not be null'
                return
            }
    
            $tempFName = [System.IO.Path]::GetRandomFileName()
            $tempDownFile = Join-Path -Path $env:TEMP -ChildPath $tempFName
    
            Write-Verbose ('down file :' + $tempDownFile)
    
            $sb = [System.Text.StringBuilder]::new()
    
            foreach($f in $fileList){
                #如果不是标准的http或https开头,则不处理
                if(-not $f[0].StartsWith('http://') -and -not $f[0].StartsWith('https://')){
                    continue
                }
                [void]$sb.AppendLine($f[0]).AppendLine(' dir='+($f[1] -replace '\\','/')).AppendLine(' out='+$f[2])
            }
    
            [System.IO.File]::WriteAllText($tempDownFile,$sb.ToString(),[System.Text.UTF8Encoding]::new($false))
    
    
            $referStr = ''
            if(-not [string]::IsNullOrEmpty($refer)){
                $referStr = ('referer={0}' -f $refer)
            }
    
            $inputStr = ('input-file={0}' -f ($tempDownFile -replace '\\','/'))
            
            $pathStr = ('dir={0}' -f ($newSavePath -replace '\\','/'))
    
            $newConf = ($conf -f $pathStr,$referStr,$inputStr)
    
            $tempFName = ([System.IO.Path]::GetRandomFileName() -split '\.')[0]
            $tempConfFile = Join-Path -Path $env:TEMP -ChildPath ($tempFName+'.conf')
    
            Write-Verbose ('down conf :' + $tempConfFile)
    
            [System.IO.File]::WriteAllText($tempConfFile,$newConf,[System.Text.UTF8Encoding]::new($false))
            
            $aria2File = Join-Path -Path $aria2Path -ChildPath 'aria2c.exe'
            if((Test-Path -Path $aria2File -PathType Leaf)){
                $cmdStr = ('"{0}" --conf-path="{1}" --quiet' -f $aria2File,($tempConfFile -replace '\\','/'))
                Write-Verbose ("cmd:" + $cmdStr)
                &cmd.exe /c $cmdStr
            }
    
            #移除文件
            Remove-Item -Path $tempConfFile -Force | Out-Null
            Remove-Item -Path $tempDownFile -Force | Out-Null
        }
        End
        {
        }
    }
    
    
    #验证参数
    if([string]::IsNullOrEmpty($server)){
        Write-Host 'Invalid server...'
        exit
    }
    
    
    if([string]::IsNullOrEmpty($aria2Path)){
        Write-Host 'Invalid aria2Path...'
        exit
    }
    
    
    if(-not (Test-Path -Path $aria2Path -PathType Container)){
        Write-Host 'Not exists aria2Path...'
        exit
    }
    
    
    #保存路径
    if([string]::IsNullOrEmpty($savePath)){
        #保存在 图片 下
        $savePath = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::MyPictures)
    }
    
    
    #域名
    if(-not $server.EndsWith('/')){
        $server += '/'
    }
    
    #xml网址,默认是 /feed
    $xmlUrl = $server+'feed'
    
    #图片正则,根据情况进行修改
    $reg = [System.Text.RegularExpressions.Regex]::new('<\/figure>')
    
    #日期
    $ts = Get-Date -Format 'yyyy-MM-dd'
    
    #以日期命名的目录
    $newSavePath = Join-Path -Path $savePath -ChildPath $ts
    
    #创建目录
    if(-not (Test-Path -Path $newSavePath -PathType Container)){
        mkdir -Path $newSavePath -Force | Out-Null
    }
    
    $resp = Invoke-RestMethod -Uri $xmlUrl
    
    if(-not $resp){
        Write-Host 'Get page error...'
        exit
    }
    
    
    #数据
    $list = [System.Collections.ArrayList]::new()
    
    Write-Host 'Parsing data...'
    
    #文件名中的非法字符
    $chs = [System.IO.Path]::GetInvalidFileNameChars()
    
    #遍历
    foreach($item in $resp){
        #标题
        $title = $item.title
        #内容
        $str = $item.encoded.'#cdata-section'
        #匹配
        $ms = $reg.Matches($str)
    
        if($ms -and $ms.Count -gt 0){
                
            #每个item有自己的名称
    
            #去掉非法字符
            foreach($c in $chs){
                $title = $title.Replace($c,[char]32)
            }
    
            #以标题创建文件夹
            $curPath = Join-Path $newSavePath -ChildPath $title
    
            #序号
            $idx = 0
            #[System.Text.RegularExpressions.Match]$m = $null
            foreach($m in $ms){
                #生成一个guid
                $gid = ([guid]::NewGuid().ToString() -replace '\-','')
    
                #捕获分组
                $url = $m.Groups[1].ToString().Trim()
    
                #后缀名
                $ext = ($url -split '\.')[-1]
    
                #文件名
                $baseName =('{0}_{1}.{2}' -f $idx,$gid,$ext)
                
                [void]$list.Add(@($url,$curPath,$baseName))
    
                $idx++
            }
        }else{
            Write-Host ('【{0}】No matches...' -f $title)
        }
    
    }
    
    if($list.Count -gt 0){
        Write-Host 'Start to download...'
        #开始下载
        Invoke-DownWithAria2 -fileList $list -refer $server -newSavePath $newSavePath -aria2Path $aria2Path
    
    }else{
        Write-Host 'No match data...'
    }
    
    
    Write-Host ('Done at:' + (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'))
    
    

    注意:

    • 代码另存为 parse-xml.ps1,假设全路径为:C:\script\parse-xml.ps1,需注意修改bat脚本中的对应路径
    • 匹配图片路径是通过正则来的,需要根据不同的实际情况进行修改,应确保图片路径在第1个分组的位置:
      $reg = [System.Text.RegularExpressions.Regex]::new(‘<\/figure>’)
    • aria2是临时生成的配置,下载完成后会自动删除,不会影响原来的配置。

    (3)bat脚本部分

    @echo off
    chcp 65001
    title 图片下载
    REM cls
    REM 目标网址
    set server=https://abc.com/
    REM aria2所在路径
    set aria2Path=C:\aria2
    REM 图片保存路径(可以为空,空则保存到 我的/图片 下)
    REM set savePath=
    set savePath=C:\Down
    echo.
    REM 注意修改.ps1 文件全路径
    powershell.exe -file "C:\script\parse-xml.ps1" -server "%server%" -aria2Path "%aria2Path%" -savePath "%savePath%"
    echo.
    echo.
    
    pause
    

    使用脚本注意:

    • 需修改目标网站aria2所在路径图片保存路径
    • 代码另存为 run.bat,双击运行即可
    • 运行成功后,会在图片保存路径下,新增一个以当前日期命名的文件夹,所有下载的东西放在里面

    运行成功:
    成功

    上班累了,洗把脸精神一下吧。

    03 后记

    仅供参考学习使用,爬虫技术慎用也。

    欢迎留言交流~
    ------END------

  • 相关阅读:
    公众号选题方向有哪些?
    UE学习日记14(枪口出现火焰)
    R语言剔除时间序列数据中存在的趋势(trend):使用lm函数拟合线性回归模型、使用原始时间序列值减去线性回归线剔除趋势分量
    Vue3 + Quasar系列-代码配置以及报错汇总记录(不断更新中)
    多线程的初识
    Microsoft Fabric 是什么?
    基于PCA主成分分析的BP神经网络回归预测研究(Matlab代码实现)
    最新Java面试八股文考题答案梳理,不可多得的Java面试真题解析资料,秋招临时抱佛脚?那也得抱对才行
    Go tutorial 笔记
    【电商】电商后台系统整体介绍
  • 原文地址:https://blog.csdn.net/HoKis/article/details/139303935