fish2018/pansou · error
[ ] 解析搜索页面失败
Error message
[%s] 解析搜索页面失败: %w
What it means
Wrapped parse error in huban's searchAtBase (plugin/huban/huban.go:275): the search page returned 200 but goquery could not parse it into a document, typically because the body was an anti-bot or error page rather than search HTML. Content-shape failure, not network.
Solutions
- Retry the request — the body read failure is often transient network corruption
- Verify the response Content-Encoding/Content-Type matches what goquery expects (HTML)
- Check whether the site is returning a challenge/blocked page instead of search results
- Log the underlying wrapped error (err) for the root cause
- Ensure resp.Body is fully consumed only once and not already closed
Example fix
// before
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] 解析搜索页面失败: %w", p.Name(), err)
}
// after
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] 解析搜索页面失败: %w", p.Name(), err)
}
if doc.Find(".module-search-item").Length() == 0 {
return nil, fmt.Errorf("[%s] 页面无搜索结果,可能被拦截", p.Name())
} Defensive patterns
Strategy: try-catch
Type guard
func isParseError(err error) bool {
return err != nil && strings.Contains(err.Error(), "解析搜索页面失败")
} Try / catch
results, err := plugin.Search(keyword)
if isParseError(err) {
log.Printf("search page unparseable, retrying once: %v", err)
results, err = plugin.Search(keyword)
}
if err != nil { return nil, err } Prevention
- Retry parse failures once — body truncation is often transient
- Ensure gzip/decompression is handled before goquery parses the body
- Log response Content-Type to detect non-HTML challenge pages
- Treat zero parsed results as a signal of a blocked/changed page layout
When it happens
Trigger: goquery.NewDocumentFromReader(resp.Body) returns a non-nil error during searchAtBase — typically truncated/gzip-corrupted body or an I/O error while reading the response stream.
Common situations: 镜像站返回压缩/二进制内容;站点改版输出格式变化。
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/efc66846c1bbce1e.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/huban/huban.go:275
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Referer", strings.TrimRight(baseURL, "/")+"/")
// 5. 发送请求
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("[%s] 搜索请求返回状态码: %d", p.Name(), resp.StatusCode)
}
// 6. 解析搜索结果页面
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] 解析搜索页面失败: %w", p.Name(), err)
}
// 7. 提取搜索结果
var results []model.SearchResult
doc.Find(".module-search-item").Each(func(i int, s *goquery.Selection) {
result := p.parseSearchItem(s, keyword)
if result.UniqueID != "" {
results = append(results, result)
}
})
return results, nil
}
// parseSearchItem 解析单个搜索结果项
func (p *HubanAsyncPlugin) parseSearchItem(s *goquery.Selection, keyword string) model.SearchResult {
result := model.SearchResult{}View on GitHub (pinned to beaa561337)