You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Go语言下载需认证的含子文件夹完整目录的方法咨询

下载带身份认证的完整目录(含子文件夹)方案

一、基于Grab包扩展实现

Grab本身侧重单文件下载,要实现目录批量下载(含子文件夹)+身份认证,需要额外处理目录结构遍历、认证头注入和本地文件夹创建三个核心环节:

1. 核心思路

  • 请求目标目录的索引页(前提是服务器暴露目录列表,比如Apache/Nginx的自动索引功能),解析页面提取所有子文件、子目录链接;
  • 递归处理每个链接:若为目录则继续遍历,若为文件则用Grab注入认证头后下载;
  • 下载前先创建对应本地子目录,保证路径结构与远程一致;
  • 根据实际场景注入身份认证信息(如Basic Auth、Bearer Token、Cookie等)。

2. 代码示例

package main

import (
	"fmt"
	"log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/cavaliergopher/grab/v3"
	"golang.org/x/net/html"
)

// 解析目录索引页,返回所有有效子项链接
func parseDirectoryIndex(resp *http.Response) ([]string, error) {
	var links []string
	doc, err := html.Parse(resp.Body)
	if err != nil {
		return nil, err
	}

	var traverse func(*html.Node)
	traverse = func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "a" {
			for _, attr := range n.Attr {
				if attr.Key == "href" {
					// 跳过上级目录和当前目录的跳转链接
					if !strings.HasPrefix(attr.Val, "../") && attr.Val != "./" {
						links = append(links, attr.Val)
					}
					break
				}
			}
		}
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			traverse(c)
		}
	}
	traverse(doc)
	return links, nil
}

// 递归下载目录
func downloadDirectory(client *grab.Client, baseURL, localDir string) error {
	// 创建本地目录,不存在则自动生成
	if err := os.MkdirAll(localDir, 0755); err != nil {
		return err
	}

	// 构建带认证的目录请求
	req, err := http.NewRequest("GET", baseURL, nil)
	if err != nil {
		return err
	}
	// 示例:Basic Auth认证,可替换为Bearer Token或Cookie
	req.SetBasicAuth("your-username", "your-password")
	// Bearer Token写法:req.Header.Add("Authorization", "Bearer your-token")

	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	// 解析子项链接
	links, err := parseDirectoryIndex(resp)
	if err != nil {
		return err
	}

	for _, link := range links {
		// 拼接完整远程URL
		itemURL, err := url.JoinPath(baseURL, link)
		if err != nil {
			log.Printf("无效链接 %s: %v", link, err)
			continue
		}
		// 拼接本地保存路径
		localPath := filepath.Join(localDir, link)

		// 判断是否为子目录(链接以/结尾)
		if strings.HasSuffix(link, "/") {
			// 递归下载子目录
			if err := downloadDirectory(client, itemURL, localPath); err != nil {
				log.Printf("下载目录 %s 失败: %v", itemURL, err)
			}
		} else {
			// 下载单个文件,复用认证头
			grabReq := grab.NewRequest(localDir, itemURL)
			grabReq.HTTPRequest.Header = req.Header.Clone()

			grabResp := client.Do(grabReq)
			if err := grabResp.Err(); err != nil {
				log.Printf("下载文件 %s 失败: %v", itemURL, err)
			} else {
				fmt.Printf("已完成: %s\n", grabResp.Filename)
			}
		}
	}
	return nil
}

func main() {
	client := grab.NewClient()
	// 替换为目标目录URL和本地保存路径
	targetDirURL := "https://example.com/protected/directory/"
	localSaveDir := "./downloads"

	if err := downloadDirectory(client, targetDirURL, localSaveDir); err != nil {
		log.Fatalf("下载失败: %v", err)
	}
	fmt.Println("目录下载完成")
}

注意事项

  • 若服务器禁用了目录列表(返回403或自定义页面),则无法通过解析索引页获取子项,需提前拿到完整的文件路径列表;
  • 认证方式需根据实际接口要求调整,比如部分场景需要携带Cookie,可直接在请求头添加Cookie字段。

二、替代工具方案

如果不想基于Grab扩展,可选择以下方案:

1. Go标准库实现

核心逻辑与上述一致,只是将Grab的下载逻辑替换为标准库的HTTP请求和文件写入:

import "io"

// 带认证下载单个文件
func downloadFileWithAuth(url, localPath, username, password string) error {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return err
	}
	req.SetBasicAuth(username, password)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	out, err := os.Create(localPath)
	if err != nil {
		return err
	}
	defer out.Close()

	_, err = io.Copy(out, resp.Body)
	return err
}

2. 第三方包与命令行工具

  • github.com/go-resty/resty/v2:简化批量HTTP请求,可全局配置认证信息;
  • github.com/cheggaaa/pb/v3:可添加下载进度条,提升交互体验;
  • 允许调用命令行的话,直接用wget/curl更快捷:
    # wget递归下载带Basic Auth的目录
    wget --user=your-username --password=your-password -r -np -k https://example.com/protected/directory/
    

内容的提问来源于stack exchange,提问作者mev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 23:47:28