{"record":{"id":"0e6d76359bfdd807","repo":"fish2018/pansou","slug":"s-d-0e6d76","errorCode":null,"errorMessage":"[%s] 搜索请求返回状态码: %d","messagePattern":"\\[(.+?)\\] 搜索请求返回状态码: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/duoduo/duoduo.go","lineNumber":184,"sourceCode":"\t\n\t// 4. 设置完整的请求头（避免反爬虫）\n\treq.Header.Set(\"User-Agent\", \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36\")\n\treq.Header.Set(\"Accept\", \"text/html,application/xhtml+xml,application/xml;q=0.9,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(\"Connection\", \"keep-alive\")\n\treq.Header.Set(\"Upgrade-Insecure-Requests\", \"1\")\n\treq.Header.Set(\"Cache-Control\", \"max-age=0\")\n\treq.Header.Set(\"Referer\", \"https://tv.yydsys.top/\")\n\t\n\t// 5. 发送请求（带重试机制）\n\tresp, err := p.doRequestWithRetry(req, client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n\t}\n\tdefer resp.Body.Close()\n\t\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求返回状态码: %d\", p.Name(), resp.StatusCode)\n\t}\n\t\n\t// 6. 解析搜索结果页面\n\tdoc, err := goquery.NewDocumentFromReader(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 解析搜索页面失败: %w\", p.Name(), err)\n\t}\n\t\n\t// 7. 提取搜索结果\n\tvar results []model.SearchResult\n\t\n\tdoc.Find(\".module-search-item\").Each(func(i int, s *goquery.Selection) {\n\t\tresult := p.parseSearchItem(s, keyword)\n\t\tif result.UniqueID != \"\" {\n\t\t\tresults = append(results, result)\n\t\t}\n\t})\n\t","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/duoduo/duoduo.go#L166-L202","documentation":"The duoduo search HTTP request succeeded at the transport level but returned a status code other than 200, so searchImpl rejects the response instead of parsing it. The plugin treats any non-200 as fatal because it expects an HTML search results page. This is an upstream site behavior problem, not a bug in the caller's request.","triggerScenarios":"The GET to the search URL returns 403/429/503 etc., typically when anti-bot protection (Cloudflare or similar) blocks the request, the Referer/UA headers are insufficient, or the site is rate-limiting frequent searches.","commonSituations":"Repeated automated searches trigger rate limiting (429); Cloudflare/WAF challenge page returned (403 or 503); site moved and old URL now redirects to an error page; server temporarily overloaded (5xx).","solutions":["Log resp.StatusCode and the response body snippet to identify whether it's a WAF block, rate limit, or server error.","Rotate/randomize User-Agent and consider cookie handling or a real browser-like header set to pass anti-bot checks.","Back off and retry with exponential delay on 429/5xx instead of failing immediately.","If 403 persists, the site likely blocks non-browser clients — switch data source or use a headless-browser fetch."],"exampleFix":"// before\nif resp.StatusCode != 200 {\n    return nil, fmt.Errorf(\"[%s] 搜索请求返回状态码: %d\", p.Name(), resp.StatusCode)\n}\n// after\nif resp.StatusCode == 429 || resp.StatusCode >= 500 {\n    time.Sleep(retryBackoff)\n    // retry once before giving up\n} else if resp.StatusCode != 200 {\n    return nil, fmt.Errorf(\"[%s] 搜索请求返回状态码: %d\", p.Name(), resp.StatusCode)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil {\n    var statusErr interface{ StatusCode() int }\n    // or inspect resp.StatusCode before parsing:\n    if resp.StatusCode == 429 {\n        time.Sleep(backoff)\n        // retry\n    } else if resp.StatusCode >= 500 {\n        // retry with backoff\n    } else {\n        // 403/404: likely blocked; disable source or change headers\n    }\n}","preventionTips":["Send complete browser-like header sets to pass WAF checks.","Throttle request rate to avoid 429s.","Treat 5xx/429 as retryable, 4xx as non-retryable.","Log response bodies on unexpected statuses for diagnosis."],"tags":["http","status-code","anti-bot","scraping"],"backgroundTag":"http-non-200-response","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"}