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

