fish2018/pansou · error
[ ] 解析搜索结果失败
Error message
[%s] 解析搜索结果失败: %w
What it means
The dygang plugin failed to build a goquery document from the decoded GB18030 HTML of the search page. This is thrown when goquery.NewDocumentFromReader cannot parse the response body, typically malformed or truncated HTML. The plugin wraps the parse error with its plugin name for context.
Solutions
- Log the first bytes of `decoded` to check whether it is actually HTML
- Verify the site's real charset and that decodeGB18030 matches it (GBK vs UTF-8)
- Check whether the site is serving an anti-bot/challenge page and add proper headers or cookies
- Add a guard for empty decoded body before calling goquery
- Retry the request — transient truncation often resolves
Example fix
// before
doc, err := goquery.NewDocumentFromReader(strings.NewReader(decoded))
if err != nil {
return nil, fmt.Errorf("[%s] 解析搜索结果失败: %w", p.Name(), err)
}
// after
if strings.TrimSpace(decoded) == "" {
return nil, fmt.Errorf("[%s] 搜索结果为空", p.Name())
}
doc, err := goquery.NewDocumentFromReader(strings.NewReader(decoded))
if err != nil {
return nil, fmt.Errorf("[%s] 解析搜索结果失败: %w (前64字节: %q)", p.Name(), err, decoded[:min(64, len(decoded))])
} Defensive patterns
Strategy: try-catch
Validate before calling
if body == nil || len(body) == 0 { return errors.New("empty response body") } Type guard
func isHTMLBody(contentType string, head []byte) bool {
ct := strings.ToLower(contentType)
if !strings.Contains(ct, "text/html") && !strings.Contains(ct, "application/xhtml") { return false }
s := strings.TrimSpace(string(head))
return strings.HasPrefix(s, "<") || strings.HasPrefix(s, "\xef\xbb\xbf<")
} Try / catch
doc, err := goquery.NewDocumentFromReader(strings.NewReader(decoded))
if err != nil {
log.Printf("html parse failed, head=%q", decoded[:min(64, len(decoded))])
return fallbackEmptyResults() // degrade gracefully instead of aborting
} Prevention
- Check Content-Type header before parsing
- Guard against empty bodies before goquery
- Verify charset handling matches the site's real encoding
- Log a body prefix on parse failure for diagnosis
When it happens
Trigger: fetchSearch received a 200 response whose body decoded via decodeGB18030 but goquery could not parse it — e.g. empty body, binary/garbage content misidentified as GB18030, or a CDN error page with invalid markup.
Common situations: Site deploys a WAF/anti-bot interstitial serving non-HTML bytes; the site changes character encoding so decodeGB18030 corrupts the stream; response body truncated by proxy; site temporarily down returning empty body.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/30c13898b8da1211.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/dygang/dygang.go:197
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[%s] 搜索请求返回 HTTP %d", p.Name(), resp.StatusCode)
}
body, err := io.ReadAll(io.LimitReader(resp.Body, 4<<20))
if err != nil {
return nil, fmt.Errorf("[%s] 读取搜索结果失败: %w", p.Name(), err)
}
decoded, err := decodeGB18030(body)
if err != nil {
return nil, fmt.Errorf("[%s] 解码搜索结果失败: %w", p.Name(), err)
}
doc, err := goquery.NewDocumentFromReader(strings.NewReader(decoded))
if err != nil {
return nil, fmt.Errorf("[%s] 解析搜索结果失败: %w", p.Name(), err)
}
return doc, nil
}
func (p *Plugin) fetchDetail(client *http.Client, detailURL string) ([]magnetItem, string, string) {
ctx, cancel := context.WithTimeout(context.Background(), requestTimeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, http.MethodGet, detailURL, nil)
if err != nil {
return nil, "", ""
}
setHeaders(req, baseURL+"/")
resp, err := client.Do(req)
if err != nil {
return nil, "", ""
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {View on GitHub (pinned to beaa561337)