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

如何使用Golang下载HTTP目录下的全部文件及子目录内容

Go 实现HTTP目录递归下载解决方案

前置说明

要实现从URL下载整个目录,需要目标服务器开启目录索引功能(即访问目录URL时会返回包含当前路径下所有文件、子目录链接的HTML列表页),否则无法枚举待下载资源。

你提供的原有DownloadFile函数存在两个语法问题:contentType变量未提前声明、函数括号匹配错误,先修复该函数,再补充目录递归下载的逻辑。

完整实现代码

package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"path"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func main() {
	// 测试:下载目标目录到本地的./download目录
	baseURL := "http://example.com/target-dir/"
	localRoot := "./download"
	err := DownloadDirectory(localRoot, baseURL)
	if err != nil {
		panic(err)
	}
	fmt.Println("目录全部下载完成:" + baseURL)
}

// DownloadFile 下载单个URL到本地路径
func DownloadFile(filepath string, url string) error {
	// 发送请求
	resp, err := http.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	contentType := resp.Header.Get("Content-Type")
	// 可根据需求调整可下载的内容类型判断逻辑
	if strings.Contains(contentType, "text/html") {
		return fmt.Errorf("当前URL为HTML页面,非可下载文件")
	}

	// 创建本地文件
	out, err := os.Create(filepath)
	if err != nil {
		return err
	}
	defer out.Close()

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

// ParseDirectoryIndex 解析目录索引页,提取当前目录下的文件、子目录链接
func ParseDirectoryIndex(pageURL string) ([]string, error) {
	resp, err := http.Get(pageURL)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	if !strings.Contains(resp.Header.Get("Content-Type"), "text/html") {
		return nil, fmt.Errorf("不是目录索引页")
	}

	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return nil, err
	}

	base, err := url.Parse(pageURL)
	if err != nil {
		return nil, err
	}

	var links []string
	doc.Find("a").Each(func(i int, s *goquery.Selection) {
		href, exists := s.Attr("href")
		if !exists {
			return
		}
		// 解析相对路径为绝对路径
		absURL, err := base.Parse(href)
		if err != nil {
			return
		}
		// 过滤上级目录链接和外部链接
		if strings.HasPrefix(absURL.Path, "/") && !strings.HasPrefix(absURL.Path, base.Path) {
			return
		}
		if href == "../" || href == "." {
			return
		}
		links = append(links, absURL.String())
	})
	return links, nil
}

// DownloadDirectory 递归下载HTTP目录到本地根路径
func DownloadDirectory(localRoot string, dirURL string) error {
	// 先解析目录下的所有资源链接
	links, err := ParseDirectoryIndex(dirURL)
	if err != nil {
		// 如果不是目录,尝试当作单个文件下载
		return DownloadFile(localRoot, dirURL)
	}

	// 创建本地目录
	err = os.MkdirAll(localRoot, 0755)
	if err != nil {
		return err
	}

	for _, link := range links {
		// 提取资源的相对路径
		parsedDirURL, _ := url.Parse(dirURL)
		parsedLink, _ := url.Parse(link)
		relPath := strings.TrimPrefix(parsedLink.Path, parsedDirURL.Path)
		localPath := path.Join(localRoot, relPath)

		if strings.HasSuffix(link, "/") {
			// 子目录,递归下载
			err = DownloadDirectory(localPath, link)
			if err != nil {
				fmt.Printf("下载子目录失败 %s: %v\n", link, err)
				continue
			}
		} else {
			// 单个文件下载
			err = DownloadFile(localPath, link)
			if err != nil {
				fmt.Printf("下载文件失败 %s: %v\n", link, err)
				continue
			}
			fmt.Println("已下载:" + link)
		}
	}
	return nil
}

使用说明

  • 依赖安装:代码中使用了goquery库解析HTML,执行go get github.com/PuerkitoBio/goquery安装依赖即可运行。
  • 适配调整:如果目标服务器的目录索引页结构特殊,只需要调整ParseDirectoryIndex函数中提取a标签的逻辑即可适配。
  • 功能扩展:可根据需求添加请求头(如User-Agent、Cookie)、并发下载控制、断点续传等功能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 17:54:10