fish2018/pansou · error

[ ] 搜索返回状态码

Error message

[%s] 搜索返回状态码: %d

What it means

Status error in KkMaoPlugin.searchImpl (plugin/kkmao/kkmao.go:129): the search page returned a status other than 200 after retry. The site was reachable but refused the request (rate limiting or anti-bot), so parsing is skipped.

Solutions

  1. Log status plus a body snippet to distinguish blocking vs server error
  2. Update setCommonHeaders to mimic a current browser (fresh User-Agent, cookies)
  3. Throttle request rate to avoid 429; add jitter/backoff
  4. Verify the search endpoint path is still correct in a browser

Example fix

// before
if resp.StatusCode != http.StatusOK {
    return nil, fmt.Errorf("[%s] 搜索返回状态码: %d", p.Name(), resp.StatusCode)
}
// after
if resp.StatusCode == http.StatusTooManyRequests {
    time.Sleep(2 * time.Second)
    return p.searchImpl(ctx, client, keyword) // or propagate retry signal
}
if resp.StatusCode != http.StatusOK {
    return nil, fmt.Errorf("[%s] 搜索返回状态码: %d", p.Name(), resp.StatusCode)
}
Defensive patterns

Strategy: retry

Validate before calling

resp, err := http.Head("https://www.kuakemao.com/?s=test")
if err == nil && resp.StatusCode != http.StatusOK {
    return fmt.Errorf("kuakemao returning %d; fix headers/proxy before scraping", resp.StatusCode)
}

Try / catch

results, err := plugin.Search(keyword)
if err != nil {
    if strings.Contains(err.Error(), "搜索返回状态码") {
        return backoffAndRetry(err) // 429/403 often transient
    }
    return err
}

Prevention

When it happens

Trigger: Any non-200 status: 403 (Cloudflare/WAF block), 404 (search route changed), 429 (too many requests), 5xx (server-side failure).

Common situations: 高频搜索触发限流;站点临时维护。

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/9468416ec6c2a21a. Report an issue: GitHub.

Appendix: source

Thrown at plugin/kkmao/kkmao.go:129

	searchURL := fmt.Sprintf("https://www.kuakemao.com/?s=%s", url.QueryEscape(keyword))
	ctx, cancel := context.WithTimeout(context.Background(), searchTimeout)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)
	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")

View on GitHub (pinned to beaa561337)