fish2018/pansou · error
[ ] 请求返回状态码
Error message
[%s] 请求返回状态码: %d
What it means
Status error in pianku's searchImpl (plugin/pianku/pianku.go:147): the search page responded with a non-200 status after retries. The server was reachable but refused the request, so HTML parsing is skipped.
Solutions
- Log the status code; for 403/503 check whether setRequestHeaders is sending a valid User-Agent and cookies
- Add backoff on 429 and reduce request frequency
- Verify the search URL still exists (404 means the site moved it)
- Use cloudscraper/proxy if the site enabled Cloudflare protection
Example fix
// before
if resp.StatusCode != 200 {
return nil, fmt.Errorf("[%s] 请求返回状态码: %d", p.Name(), resp.StatusCode)
}
// after
if resp.StatusCode != 200 {
if resp.StatusCode == 429 {
time.Sleep(2*time.Second)
return p.searchImpl(client, keyword, ext)
}
return nil, fmt.Errorf("[%s] 请求返回状态码: %d", p.Name(), resp.StatusCode)
} Defensive patterns
Strategy: retry
Validate before calling
if req.Header.Get("User-Agent") == "" {
return fmt.Errorf("missing User-Agent, expect anti-bot 403")
} Try / catch
results, err := plugin.Search(keyword, ext)
if err != nil {
if strings.Contains(err.Error(), "请求返回状态码: 429") {
time.Sleep(backoff) // retry
} else if strings.Contains(err.Error(), "请求返回状态码: 403") {
// refresh cookies/User-Agent or enable proxy
}
} Prevention
- Always send a realistic User-Agent and cookies via setRequestHeaders
- Back off on 429 instead of hammering
- Smoke-test the endpoint when its protection changes
When it happens
Trigger: GET of the pianku search page (after successful transport) returns e.g. 403 (Cloudflare/WAF), 429 (too many requests), 404 (endpoint moved), or 500.
Common situations: 请求头特征被拦截;站点临时不可用。
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/a89f2e0211cee428.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/pianku/pianku.go:147
// 创建请求
req, err := http.NewRequestWithContext(ctx, "GET", searchURL, nil)
if err != nil {
return nil, fmt.Errorf("[%s] 创建请求失败: %w", p.Name(), err)
}
// 设置请求头
p.setRequestHeaders(req)
// 发送HTTP请求(带重试机制)
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 != 200 {
return nil, fmt.Errorf("[%s] 请求返回状态码: %d", p.Name(), resp.StatusCode)
}
// 解析HTML
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] HTML解析失败: %w", p.Name(), err)
}
// 提取搜索结果基本信息
searchResults := p.extractSearchResults(doc)
// 为每个搜索结果获取详情页的下载链接
var finalResults []model.SearchResult
for _, result := range searchResults {
// 获取详情页链接
if len(result.Links) == 0 {
continue
}View on GitHub (pinned to beaa561337)