使用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
相关产品推荐
相关产品推荐

