概况
golang写个小程序把unpkg网站上的包下载下来,文章后面有现成exe程序。拿来就用,不要浪费时间。
目标
从unpkg.com中下载文件
原理分析
F12,启动!
发现网站文件目录信息全部存放在一个window.__DATA__的变量里。
可以发现他的数据也是有规则的,列表信息存放在target.details里面。里面甚至有type字段用来区分文件还是目录。
这下就好办啦。
实现思路
技术选型
golang
原因是方便编译成exe供后人使用
代码实现
package main
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"regexp"
)
type PageData struct {
FileName string `json:"filename"`
PackageName string `json:"packageName"`
PackageVersion string `json:"packageVersion"`
Target Target `json:"target"`
}
type Target struct {
Path string `json:"path"`
Type string `json:"type"`
Details map[string]AItem `json:"details"`
}
type AItem struct {
Path string `json:"path"`
Type string `json:"type"`
ContentType string `json:"contentType"`
Integrity string `json:"integrity"`
Size int `json:"size"`
}
func GetHtml(url string) string {
//获取html
resp, err := http.Get(url)
resp.Header.Set("Accept-Language", "zh-CN,zh;q=0.8")
resp.Header.Set("Content-Type", "text/html;Charset=utf-8")
resp.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36")
if err != nil {
fmt.Println("请求失败:", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("读取响应失败:", err)
}
return string(body)
}
func DownloadFile(downloadUrl, dest, fileName string) error {
//创建文件
out, err := os.Create(dest + fileName)
if err != nil {
fmt.Println("创建文件失败", dest+fileName)
return err
}
defer out.Close()
//下载文件
resp, err := http.Get(downloadUrl)
if err != nil {
fmt.Println("网络异常~!")
return err
}
defer resp.Body.Close()
//拷贝
_, err = io.Copy(out, resp.Body)
if err != nil {
fmt.Println("网络异常~!")
return err
}
return nil
}
func GetPageDataByUrl(url string, fileDir string) {
str := GetHtml(url)
ret := regexp.MustCompile(`window.__DATA__ =(.+?)</script>`)
//只查找前 n 个匹配项,如果 n = -1,则查找所有匹配项
//FindAllStringSubmatch 匹配结果:string1: 表示带有匹配参考项的全部字串。string2: 表示去除匹配参考项后的字串。
res := ret.FindAllStringSubmatch(str, 1)
pageData := PageData{}
if len(res) != 1 || len(res[0]) != 2 {
fmt.Println("数据获取失败", url)
return
}
//解析json
err := json.Unmarshal([]byte(res[0][1]), &pageData)
if err != nil {
fmt.Println("json解析失败")
return
}
//无内容,进入到空目录
if pageData.Target.Details == nil {
return
}
//创建文件夹
fmt.Println(fileDir + pageData.FileName)
ferr := os.MkdirAll(fileDir+pageData.FileName, 0755)
if ferr != nil {
fmt.Println("文件夹创建失败", err)
return
}
//递归
for _, v := range pageData.Target.Details {
var fileType = v.Type
var fileName = v.Path
if fileType == "file" {
//文件 下载
df := "https://unpkg.com/" + pageData.PackageName + "@" + pageData.PackageVersion + fileName
fmt.Println(fileDir + fileName)
derr := DownloadFile(df, fileDir, fileName)
for derr != nil {
derr = DownloadFile(df, fileDir, fileName)
}
} else {
//目录 继续往下递归
dd := "https://unpkg.com/browse/" + pageData.PackageName + "@" + pageData.PackageVersion + fileName + "/"
GetPageDataByUrl(dd, fileDir)
}
}
}
func main() {
var url string
// url := "https://unpkg.com/browse/element-ui@2.15.14/"
fmt.Println("请输入地址(eg:https://unpkg.com/browse/element-ui@2.15.14/)")
fmt.Print("=>")
fmt.Scan(&url)
fmt.Println("=>准备执行...")
var fileDir = "./keke_file"
GetPageDataByUrl(url, fileDir)
fmt.Println("=>执行完毕,文件已下载至" + fileDir)
}
运行
等个十来分钟(时间有点久,留给后人优化)
完成!!芜湖
附上源码地址,含exe可执行文件
https://gitee.com/cyme/go-unpkg-tool
链接: 网站unpkg.com,文件下载工具,实现语言:golang,有现成exe直接运行