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

  1. Unwrap the inner error to see which underlying step failed (request creation, HTTP, status code, body read, HTML parse).
  2. Retry the search after a delay — transient network issues and rate limiting are the most common causes.
  3. If status-code errors recur, check the site in a browser; update headers/cookies in setRequestHeaders to bypass anti-bot changes.
  4. Increase TimeoutSeconds if timeouts occur on a slow endpoint.
  5. 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

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)