fish2018/pansou · error

[ ] 第 页搜索请求失败

Error message

[%s] 第%d页搜索请求失败: %w

What it means

This error wraps a failed per-page HTTP search request in the yunsou plugin's fetchPage. doRequestWithRetry exhausted all retry attempts (network error or non-200 status) and the underlying failure is chained with %w so the root cause (e.g. the '重试 %d 次后仍然失败' error) is preserved. It indicates the plugin could not retrieve the HTML for that search page at all.

Solutions

  1. Inspect the wrapped cause (%w chain) to see if it is a timeout, connection error, or bad status code.
  2. Verify network connectivity and that wpys.cc is reachable (curl -I https://wpys.cc/).
  3. Update/rotate User-Agent, Referer, and other headers if the site added anti-bot protection.
  4. Increase maxRetries or retry backoff in doRequestWithRetry for flaky networks.
  5. Reduce requested pages so one bad page does not fail the whole search.

Example fix

// before
return nil, fmt.Errorf("[%s] 第%d页搜索请求失败: %w", p.Name(), page, err)
// after
var resp *http.Response
resp, err = p.doRequestWithRetry(req, client)
if err != nil {
    log.Printf("[%s] 第%d页搜索请求失败(跳过): %v", p.Name(), page, err)
    return nil, nil // degrade gracefully instead of aborting search
}
Defensive patterns

Strategy: retry

Validate before calling

func checkReachable(url string) error {
    resp, err := http.Head(url)
    if err != nil { return err }
    defer resp.Body.Close()
    if resp.StatusCode != 200 { return fmt.Errorf("站点状态码 %d", resp.StatusCode) }
    return nil
}

Try / catch

doc, err := p.fetchPage(client, keyword, page)
if err != nil {
    log.Printf("跳过第%d页: %v", page, err)
    return resultsSoFar, nil // partial results instead of abort
}

Prevention

When it happens

Trigger: doRequestWithRetry returns an error after maxRetries failures in fetchPage — all attempts timed out, connection was refused/reset, or every retry returned a non-200 status code.

Common situations: Site wpys.cc is down or blocked, the User-Agent/Referer anti-scrape headers are no longer sufficient and the site returns 403/503, DNS failure, or the machine has no internet/proxy access.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at plugin/yunsou/yunsou.go:129

func (p *YunsouAsyncPlugin) fetchPage(ctx context.Context, client *http.Client, keyword string, page int) (*goquery.Document, error) {
	pathKeyword := url.PathEscape(keyword)
	path := pathKeyword
	if page > 1 {
		path = fmt.Sprintf("%s-%d", pathKeyword, page)
	}
	requestURL := fmt.Sprintf(searchURLTemplate, path)
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)
	if err != nil {
		return nil, fmt.Errorf("[%s] 创建第%d页请求失败: %w", p.Name(), page, err)
	}
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36")
	req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
	req.Header.Set("Referer", "https://wpys.cc/")
	resp, err := p.doRequestWithRetry(req, client)
	if err != nil {
		return nil, fmt.Errorf("[%s] 第%d页搜索请求失败: %w", p.Name(), page, err)
	}
	defer resp.Body.Close()
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("[%s] 解析第%d页失败: %w", p.Name(), page, err)
	}
	return doc, nil
}

func (p *YunsouAsyncPlugin) doRequestWithRetry(req *http.Request, client *http.Client) (*http.Response, error) {
	var lastErr error
	for attempt := 0; attempt < maxRetries; attempt++ {
		if attempt > 0 {
			time.Sleep(time.Duration(1<<(attempt-1)) * 200 * time.Millisecond)
		}
		resp, err := client.Do(req.Clone(req.Context()))
		if err == nil && resp.StatusCode == http.StatusOK {
			return resp, nil

View on GitHub (pinned to beaa561337)