最稳方式是用goquery解析HTML并提取所有img的src属性:先用strings.NewReader转字符串为io.Reader,再调用NewDocumentFromReader;遍历doc.Find("img"),通过s.Attr("src")安全获取非空src值。

用 goquery 解析 HTML 并提取所有 <img> 的 src 属性
最稳的方式是用 goquery(基于 net/html 的 jQuery 风格库),它能正确处理嵌套、属性引号、自闭合等真实 HTML 边界情况,比正则靠谱得多。
先安装:go get github.com/PuerkitoBio/goquery
关键点:必须用 strings.NewReader() 把 HTML 字符串转成 io.Reader 才能喂给 goquery.NewDocumentFromReader(),直接传字符串会 panic。
示例代码片段:
立即学习“go语言免费学习笔记(深入)”;
doc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlStr))
if err != nil {
// 处理解析错误,比如 malformed HTML
}
var srcs []string
doc.Find("img").Each(func(i int, s *goquery.Selection) {
if src, exists := s.Attr("src"); exists && src != "" {
srcs = append(srcs, src)
}
})
注意:s.Attr("src") 返回两个值 —— 属性值和是否存在的布尔值,漏掉 exists 判断会导致空 src 被加入结果。
手动用 net/html 词法解析时如何避免跳过嵌套或注释里的 <img>
net/html 是 Go 标准库,轻量但需要自己遍历节点树。容易出错的地方在于:误把注释、CDATA 或 script 标签里的文本当成标签处理。
必须在进入 html.CommentToken 或 html.ScriptToken 时跳过其子内容,否则可能把 <!-- <img src="x"> --> 里的 src 提取出来。
实操建议:
- 用
z := html.NewTokenizer(strings.NewReader(htmlStr))初始化解析器 - 只在
z.Token().Type == html.StartTagToken且标签名是"img"时检查属性 - 调用
token.Attr遍历属性,找到key == "src"的那个值 - 遇到
html.CommentToken或html.ScriptToken时,用z.Next()跳过内部内容,直到对应结束标记
regexp 提取 src 的适用边界和致命缺陷
正则只适合已知格式高度可控的场景,比如模板生成的静态 HTML,且不含换行、属性顺序固定、引号统一。
常见错误正则:`<img[^>]+src=[\"']([^\"']+)[\"'][^>]*>` —— 它会在以下情况失效:
-
<img src='a.jpg' alt="b>c">:双引号出现在 alt 里,导致正则提前截断 -
<img src="y">:匹配到的是data-src,不是src -
<IMG SRC="a.png">:标签名大小写不敏感,但正则没加i标志 -
<img src="a.jpg">:HTML 实体编码,正则无法识别
如果非要用正则,至少加上 (?i) 和更宽松的引号匹配逻辑,但依然不推荐用于生产环境。
相对路径怎么转成绝对 URL?url.Join() 是唯一可靠方式
提取出来的 src 常是相对路径(如 /images/a.jpg 或 ./b.png),直接使用会 404。不能靠字符串拼接,必须用标准库 url.Join(baseURL, src)。
要点:
-
baseURL必须是完整 URL(含 scheme,如"https://example.com/"),不能是域名或路径 -
url.Join()会自动处理../、./、重复斜杠等,手写逻辑极易出错 - 如果原始 HTML 来自本地文件(无 base URL),需明确约定一个 base,比如
"file:///path/to/"
示例:final, _ := url.Join("https://site.com/blog/", "../img/x.png") → "https://site.com/img/x.png"
别忽略 url.Join() 的 error 返回值 —— 当 src 是 javascript: 或 data: 协议时,它可能返回 error,这时应保留原值而非 panic。



















