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
- Log status plus a body snippet to distinguish blocking vs server error
- Update setCommonHeaders to mimic a current browser (fresh User-Agent, cookies)
- Throttle request rate to avoid 429; add jitter/backoff
- 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
- Rotate/refresh browser-like headers regularly
- Throttle request rate; respect Retry-After on 429
- Alert when status codes indicate permanent blocking
- Verify search route still exists after site updates
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)