fish2018/pansou · error
[ ] 搜索第一页失败
Error message
[%s] 搜索第一页失败: %w
What it means
ClmaoPlugin.searchImpl wraps any failure from fetching the first page of results (p.searchPage(client, keyword, 1)) with the plugin name for context. It means the very first page request — request creation, HTTP round trip, status check, body read, HTML parse, or nested retry exhaustion — failed, so the multi-page aggregation aborts before appending any results.
Solutions
- Unwrap the inner error to see which underlying step failed (request creation, HTTP, status code, body read, HTML parse).
- Retry the search after a delay — transient network issues and rate limiting are the most common causes.
- If status-code errors recur, check the site in a browser; update headers/cookies in setRequestHeaders to bypass anti-bot changes.
- Increase TimeoutSeconds if timeouts occur on a slow endpoint.
- Handle partial results gracefully if business logic allows instead of failing the entire search.
Example fix
// before
firstPageResults, err := p.searchPage(client, keyword, 1)
if err != nil {
return nil, fmt.Errorf("[%s] 搜索第一页失败: %w", p.Name(), err)
}
// after
firstPageResults, err := p.searchPage(client, keyword, 1)
if err != nil {
if isTransient(err) { time.Sleep(backoff); return p.searchPage(client, keyword, 1) }
return nil, fmt.Errorf("[%s] 搜索第一页失败: %w", p.Name(), err)
} Defensive patterns
Strategy: try-catch
Validate before calling
// verify keyword non-empty before calling search
if strings.TrimSpace(keyword) == "" { return nil, errors.New("keyword required") } Try / catch
results, err := p.searchImpl(client, keyword, ext)
if err != nil {
log.Printf("clmao first-page search failed: %v", err)
return nil, err // or degraded results
} Prevention
- Always unwrap and log the inner error; this is a wrapper around several failure modes.
- Watch for site redesigns — first-page parse failures usually mean markup changed.
- Throttle request frequency to avoid triggering anti-bot responses.
- Keep plugin timeout (TimeoutSeconds) generous enough for slow responses.
When it happens
Trigger: Calling the clmao plugin's Search entry point when p.searchPage(client, keyword, 1) returns an error: http.NewRequestWithContext fails, doRequestWithRetry exhausts retries, response status != 200, io.ReadAll fails, goquery parse fails — all get re-wrapped here as "[clmao] 搜索第一页失败: %w".
Common situations: The site is temporarily unreachable or rate-limiting the client; a site redesign makes the response a non-200 or unparseable page (CAPTCHA/anti-bot interstitial); the request context (TimeoutSeconds) expires before the response arrives.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/9d3fd3b834b415f0.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/clmao/clmao.go:104
func (p *ClmaoPlugin) Search(keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
result, err := p.SearchWithResult(keyword, ext)
if err != nil {
return nil, err
}
return result.Results, nil
}
// SearchWithResult 执行搜索并返回包含IsFinal标记的结果
func (p *ClmaoPlugin) SearchWithResult(keyword string, ext map[string]interface{}) (model.PluginSearchResult, error) {
return p.AsyncSearchWithResult(keyword, p.searchImpl, p.MainCacheKey, ext)
}
// searchImpl 实际的搜索实现
func (p *ClmaoPlugin) searchImpl(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {
// 1. 首先搜索第一页
firstPageResults, err := p.searchPage(client, keyword, 1)
if err != nil {
return nil, fmt.Errorf("[%s] 搜索第一页失败: %w", p.Name(), err)
}
// 存储所有结果
var allResults []model.SearchResult
allResults = append(allResults, firstPageResults...)
// 2. 并发搜索其他页面(第2页到第5页)
if MaxPages > 1 {
var wg sync.WaitGroup
var mu sync.Mutex
// 使用信号量控制并发数
semaphore := make(chan struct{}, MaxConcurrency)
// 存储每页结果
pageResults := make(map[int][]model.SearchResult)
for page := 2; page <= MaxPages; page++ {View on GitHub (pinned to beaa561337)