{"record":{"id":"07d20460d9614a36","repo":"fish2018/pansou","slug":"s-d-w-07d204","errorCode":null,"errorMessage":"[%s] 第%d页搜索请求失败: %w","messagePattern":"\\[(.+?)\\] 第(.+?)页搜索请求失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/yunsou/yunsou.go","lineNumber":129,"sourceCode":"\nfunc (p *YunsouAsyncPlugin) fetchPage(ctx context.Context, client *http.Client, keyword string, page int) (*goquery.Document, error) {\n\tpathKeyword := url.PathEscape(keyword)\n\tpath := pathKeyword\n\tif page > 1 {\n\t\tpath = fmt.Sprintf(\"%s-%d\", pathKeyword, page)\n\t}\n\trequestURL := fmt.Sprintf(searchURLTemplate, path)\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 创建第%d页请求失败: %w\", p.Name(), page, err)\n\t}\n\treq.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\")\n\treq.Header.Set(\"Accept\", \"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\")\n\treq.Header.Set(\"Accept-Language\", \"zh-CN,zh;q=0.9,en;q=0.8\")\n\treq.Header.Set(\"Referer\", \"https://wpys.cc/\")\n\tresp, err := p.doRequestWithRetry(req, client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 第%d页搜索请求失败: %w\", p.Name(), page, err)\n\t}\n\tdefer resp.Body.Close()\n\tdoc, err := goquery.NewDocumentFromReader(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 解析第%d页失败: %w\", p.Name(), page, err)\n\t}\n\treturn doc, nil\n}\n\nfunc (p *YunsouAsyncPlugin) doRequestWithRetry(req *http.Request, client *http.Client) (*http.Response, error) {\n\tvar lastErr error\n\tfor attempt := 0; attempt < maxRetries; attempt++ {\n\t\tif attempt > 0 {\n\t\t\ttime.Sleep(time.Duration(1<<(attempt-1)) * 200 * time.Millisecond)\n\t\t}\n\t\tresp, err := client.Do(req.Clone(req.Context()))\n\t\tif err == nil && resp.StatusCode == http.StatusOK {\n\t\t\treturn resp, nil","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/yunsou/yunsou.go#L111-L147","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the wrapped cause (%w chain) to see if it is a timeout, connection error, or bad status code.","Verify network connectivity and that wpys.cc is reachable (curl -I https://wpys.cc/).","Update/rotate User-Agent, Referer, and other headers if the site added anti-bot protection.","Increase maxRetries or retry backoff in doRequestWithRetry for flaky networks.","Reduce requested pages so one bad page does not fail the whole search."],"exampleFix":"// before\nreturn nil, fmt.Errorf(\"[%s] 第%d页搜索请求失败: %w\", p.Name(), page, err)\n// after\nvar resp *http.Response\nresp, err = p.doRequestWithRetry(req, client)\nif err != nil {\n    log.Printf(\"[%s] 第%d页搜索请求失败(跳过): %v\", p.Name(), page, err)\n    return nil, nil // degrade gracefully instead of aborting search\n}","handlingStrategy":"retry","validationCode":"func checkReachable(url string) error {\n    resp, err := http.Head(url)\n    if err != nil { return err }\n    defer resp.Body.Close()\n    if resp.StatusCode != 200 { return fmt.Errorf(\"站点状态码 %d\", resp.StatusCode) }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"doc, err := p.fetchPage(client, keyword, page)\nif err != nil {\n    log.Printf(\"跳过第%d页: %v\", page, err)\n    return resultsSoFar, nil // partial results instead of abort\n}","preventionTips":["Pre-flight check site reachability with a HEAD request","Keep User-Agent/Referer headers current","Add exponential backoff between retries","Cap concurrent requests to avoid rate limiting"],"tags":["network","http","scraping","retry-exhausted"],"backgroundTag":"http-request-failed","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}