fish2018/pansou · error
[ ] 解析搜索结果失败
Error message
[%s] 解析搜索结果失败: %w
What it means
The duanjuw plugin wraps goquery.NewDocumentFromReader failures as '[plugin] failed to parse search results'. The body could not be parsed as an HTML document, usually because it is empty or not HTML despite a 200 status.
Solutions
- Read and log the first bytes of resp.Body on failure to see the actual content
- Avoid manually setting Accept-Encoding unless the Transport decompresses
- Retry — empty 200 bodies are often transient
- If the site changed its page structure/content type, update the parser
Example fix
// before
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil { return nil, err }
// after
body, rerr := io.ReadAll(resp.Body)
if rerr != nil || len(bytes.TrimSpace(body)) == 0 {
return nil, fmt.Errorf("empty search body")
}
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(body)) Defensive patterns
Strategy: validation
Validate before calling
body, _ := io.ReadAll(resp.Body)
if len(bytes.TrimSpace(body)) == 0 {
return fmt.Errorf("empty body; skip goquery parse")
}
if !utf8.Valid(body) {
return fmt.Errorf("non-utf8 body")
} Try / catch
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(body))
if err != nil {
log.Printf("parse failed, body head: %q", body[:min(200,len(body))])
return []model.SearchResult{}, nil
} Prevention
- Buffer the body first so it can be inspected and re-read
- Never set Accept-Encoding without transport decompression
- Retry empty/truncated 200 responses
- Test the parser against saved snapshots when the site updates
When it happens
Trigger: goquery.NewDocumentFromReader(resp.Body) returns err in searchImpl — empty body, truncated stream, or non-HTML content (binary, badly encoded).
Common situations: Server returns 200 with an empty or challenge body; compression mismatch when Accept-Encoding is set manually; connection cut mid-body causing malformed HTML.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/d9500b220f171cae.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/duanjuw/duanjuw.go:126
req, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)
if err != nil {
return nil, fmt.Errorf("[%s] 创建搜索请求失败: %w", p.Name(), err)
}
setDuanjuwHeaders(req, duanjuwBaseURL+"/")
resp, err := doDuanjuwRequestWithRetry(req, client)
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] 搜索返回状态码: %d", p.Name(), resp.StatusCode)
}
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] 解析搜索结果失败: %w", p.Name(), err)
}
items := p.parseSearchResults(doc)
if len(items) == 0 {
return []model.SearchResult{}, nil
}
// The current site renders search results as numbered chat entries with
// direct pan links. Older pages still use result cards and need detail fetches.
for _, item := range items {
if len(item.Links) > 0 {
return plugin.FilterResultsByKeyword(items, keyword), nil
}
}
results := p.enrichResults(client, items)
return plugin.FilterResultsByKeyword(results, keyword), nil
}
View on GitHub (pinned to beaa561337)