fish2018/pansou · error
[ ] 解析搜索页面失败
Error message
[%s] 解析搜索页面失败: %w
What it means
Wrapped parse error in KkMaoPlugin.searchImpl (plugin/kkmao/kkmao.go:134): the 200 response body could not be turned into a goquery document — usually an HTML challenge or non-HTML error page instead of search results.
Solutions
- Read and size-check the body before parsing; log the first bytes on failure
- Ensure the transport handles gzip/deflate (http.DefaultTransport does; custom ones may not)
- Confirm no earlier code consumed resp.Body
- Handle encoding indicated by the Content-Type charset
Example fix
// before
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil { return nil, fmt.Errorf("[%s] 解析搜索页面失败: %w", p.Name(), err) }
// after
body, rerr := io.ReadAll(resp.Body)
if rerr != nil || len(bytes.TrimSpace(body)) == 0 {
return nil, fmt.Errorf("[%s] empty response body (status %d)", p.Name(), resp.StatusCode)
}
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(body)) Defensive patterns
Strategy: fallback
Validate before calling
body, _ := io.ReadAll(io.LimitReader(resp.Body, 256))
if len(bytes.TrimSpace(body)) == 0 || !utf8.Valid(body) {
return errors.New("response body empty or invalid; skip parsing")
} Try / catch
results, err := plugin.Search(keyword)
if err != nil {
if strings.Contains(err.Error(), "解析搜索页面失败") {
return useFallbackSource(keyword)
}
return err
} Prevention
- Verify body non-empty before goquery parsing
- Use a transport with automatic gzip decoding
- Never read resp.Body twice
- Log response Content-Type on parse failures
When it happens
Trigger: goquery.NewDocumentFromReader(resp.Body) errors: empty body from a blocked request, truncated transfer, charset/compression mismatch, or a JSON/challenge page instead of HTML.
Common situations: 站点改版返回 JSON 或错误页。
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/7714d748e6e74ea4.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/kkmao/kkmao.go:134
if err != nil {
return nil, fmt.Errorf("[%s] 创建请求失败: %w", p.Name(), err)
}
setCommonHeaders(req, "https://www.kuakemao.com/")
resp, err := p.doRequestWithRetry(req, client, searchMaxRetries, retryBaseDelay)
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)
}
var (
results []model.SearchResult
wg sync.WaitGroup
mu sync.Mutex
sem = make(chan struct{}, maxConcurrency)
)
doc.Find("article.excerpt").Each(func(_ int, item *goquery.Selection) {
titleSel := item.Find("header h2 a")
title := strings.TrimSpace(titleSel.Text())
detailURL, ok := titleSel.Attr("href")
if !ok || title == "" || detailURL == "" {
return
}
articleID := extractArticleID(detailURL)View on GitHub (pinned to beaa561337)