fish2018/pansou · error
详情页HTML解析失败
Error message
详情页HTML解析失败: %w
What it means
The downloaded detail-page HTML is parsed with goquery.NewDocumentFromReader. goquery's HTML parser (go.net/html) almost never errors on real input, so this error indicates malformed input such as a nil reader, or an empty/invalid body stream failing to parse. When it fires, the wrapped error comes from the underlying html parser.
Solutions
- Verify body is fully read before parsing (io.ReadAll succeeded) and non-empty; skip empty bodies earlier.
- If streaming resp.Body into goquery directly, close/replace that path — read fully first so parse errors are separated from network errors.
- Check the wrapped parse error via %w unwrap; go.net/html parse errors usually mean the input reader failed, not the HTML content.
- Add a guard: if len(body) == 0 return a clearer 'empty detail page' error before parsing.
Example fix
// before
doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(body)))
if err != nil {
return "", fmt.Errorf("详情页HTML解析失败: %w", err)
}
// after
if len(bytes.TrimSpace(body)) == 0 {
return "", fmt.Errorf("详情页响应为空: %s", detailURL)
}
doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(body)))
if err != nil {
return "", fmt.Errorf("详情页HTML解析失败: %w", err)
} Defensive patterns
Strategy: validation
Validate before calling
if len(bytes.TrimSpace(body)) == 0 {
return fmt.Errorf("empty detail page body")
}
// safe to parse
doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(body))) Try / catch
doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(body)))
if err != nil {
return fmt.Errorf("parse failed: %w", err)
} Prevention
- Read the body fully with io.ReadAll before parsing
- Reject empty bodies before handing them to the parser
- Never stream a live network body straight into goquery
When it happens
Trigger: goquery.NewDocumentFromReader(strings.NewReader(string(body))) returns an error — practically only when body is produced by a failing/nil reader or the parse hits a fatal reader error. With an in-memory strings.Reader over already-read bytes this is an edge case.
Common situations: A code path change passing a nil or already-closed body reader; extremely truncated responses reused downstream; custom modifications to the function that stream the body directly into goquery while the network stream errors.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/7881309a39040dc6.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/wuji/wuji.go:335
return "", fmt.Errorf("详情页请求失败: %w", err)
}
defer resp.Body.Close()
// 检查状态码
if resp.StatusCode != 200 {
return "", fmt.Errorf("详情页返回状态码: %d", resp.StatusCode)
}
// 读取响应体内容
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("读取详情页响应失败: %w", err)
}
// 解析HTML
doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(body)))
if err != nil {
return "", fmt.Errorf("详情页HTML解析失败: %w", err)
}
// 提取磁力链接
magnetInput := doc.Find("input#input-magnet")
if magnetInput.Length() == 0 {
return "", fmt.Errorf("未找到磁力链接输入框")
}
magnetLink, exists := magnetInput.Attr("value")
if !exists || magnetLink == "" {
return "", fmt.Errorf("磁力链接为空")
}
// 存入缓存
magnetCache.Store(detailURL, magnetCacheEntry{
MagnetLink: magnetLink,
Timestamp: time.Now(),
})View on GitHub (pinned to beaa561337)