fish2018/pansou · error

[ ] 搜索返回状态码

Error message

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

What it means

searchImpl returns "[%s] 搜索返回状态码" when the search page responds with a status other than 200. The plugin scrapes HTML with goquery and only handles a 200 body, so any other status is reported with its numeric code.

Solutions

  1. Log the status code; treat 403/429 as blocking and add cookies, referer, or realistic headers via setCommonHeaders.
  2. Back off and retry later for 429/5xx; reduce search request frequency.
  3. If 404, verify the search URL format against the live site and update searchImpl.
  4. Capture the response body on non-200 to identify WAF challenge pages.

Example fix

// before
if resp.StatusCode != http.StatusOK {
    return nil, fmt.Errorf("[%s] 搜索返回状态码: %d", p.Name(), resp.StatusCode)
}
// after
if resp.StatusCode != http.StatusOK {
    return nil, fmt.Errorf("[%s] 搜索返回状态码: %d (blocked=%v)",
        p.Name(), resp.StatusCode, resp.StatusCode == 403 || resp.StatusCode == 429)
}
Defensive patterns

Strategy: try-catch

Try / catch

results, err := plugin.Search(ctx, keyword)
if err != nil && strings.Contains(err.Error(), "搜索返回状态码") {
    var sc int
    fmt.Sscanf(err.Error(), "搜索返回状态码: %d", &sc)
    if sc == 429 || sc == 403 {
        // back off significantly before the next attempt
    }
    return nil, err
}

Prevention

When it happens

Trigger: The search GET completes but resp.StatusCode != http.StatusOK: 404 for a moved search route, 403/429 from WAF or rate limiting, or 5xx server errors.

Common situations: Site added Cloudflare/anti-bot protection returning 403, aggressive search requests trigger 429, the WordPress-style ?s= search route changed, or the origin returns 502/504 under load.

Related errors


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

Appendix: source

Thrown at plugin/daishudj/daishudj.go:142

	searchURL := fmt.Sprintf("https://www.daishuduanju.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.daishuduanju.com/")

	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 != 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(".item-jx.item-blog").Each(func(_ int, item *goquery.Selection) {
		titleSel := item.Find(".subtitle h5 a")
		title := strings.TrimSpace(titleSel.Text())
		detailURL, ok := titleSel.Attr("href")

View on GitHub (pinned to beaa561337)