fish2018/pansou · error
[ ] API 失败且网页搜索返回状态码 (API: )
Error message
[%s] API 失败且网页搜索返回状态码 %d (API: %v)
What it means
In searchWeb, after the fallback HTML page loads, a non-200 status is reported with this message, which also embeds the original API failure (apiErr) since the web path only runs after the API path failed. It means the site answered but refused the scraping request.
Solutions
- Log the status code and check for HTML challenge pages in the body
- Update User-Agent/Accept/Referer headers to match a current browser and the live domain
- Add rate limiting or backoff between scraping requests
- Update SearchWebURL when the site rotates domains
Example fix
// before
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[%s] API 失败且网页搜索返回状态码 %d (API: %v)", p.Name(), resp.StatusCode, apiErr)
}
// after
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[%s] API 失败且网页搜索返回状态码 %d (API: %v)", p.Name(), resp.StatusCode, apiErr)
}
// plus: refresh headers per live site, e.g.
req.Header.Set("Referer", "https://feikuai.in/") // verify current domain Defensive patterns
Strategy: retry
Validate before calling
// slow the scrape rate to stay under throttling thresholds rateLimiter := rate.NewLimiter(rate.Every(500*time.Millisecond), 1) _ = rateLimiter.Wait(ctx) // before each search call
Try / catch
results, err := plugin.Search(keyword)
if err != nil && strings.Contains(err.Error(), "网页搜索返回状态码") {
if strings.Contains(err.Error(), "429") {
time.Sleep(10 * time.Second)
results, err = plugin.Search(keyword) // backoff retry
} else if strings.Contains(err.Error(), "403") {
log.Printf("feikuai WAF block; refresh headers or rotate proxy")
}
} Prevention
- Mirror the live site's browser headers including current Referer domain
- Add per-request jitter and a global rate limit for scraping
- Detect 403/429 early and back off instead of hammering
- Track upstream domain rotations and update constants promptly
When it happens
Trigger: resp.StatusCode != http.StatusOK in searchWeb, typically 403 (anti-bot/WAF), 429 (rate limit), or 404/301 after a domain change, while the API path had already errored.
Common situations: Cloudflare or WAF challenge page for scraping requests, outdated Referer (https://feikuai.in/) after domain rotation, too-frequent scraping triggering throttling.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/9a52cf1b15d2b70d.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/feikuai/feikuai.go:189
func (p *FeikuaiPlugin) searchWeb(client *http.Client, keyword string, apiErr error) ([]model.SearchResult, error) {
ctx, cancel := context.WithTimeout(context.Background(), DefaultTimeout)
defer cancel()
searchURL := SearchWebURL + "?wd=" + url.QueryEscape(keyword) + "&ext=1"
req, err := http.NewRequestWithContext(ctx, http.MethodGet, searchURL, nil)
if err != nil {
return nil, fmt.Errorf("[%s] 创建网页搜索请求失败: %w", p.Name(), err)
}
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/136.0.0.0 Safari/537.36")
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8")
req.Header.Set("Referer", "https://feikuai.in/")
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("[%s] API 失败且网页搜索请求失败: %v (API: %v)", p.Name(), err, apiErr)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("[%s] API 失败且网页搜索返回状态码 %d (API: %v)", p.Name(), resp.StatusCode, apiErr)
}
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] 网页搜索 HTML 解析失败: %w", p.Name(), err)
}
results := make([]model.SearchResult, 0, 64)
seen := make(map[string]struct{})
add := func(linkURL, title, content string, datetime time.Time) {
linkURL = strings.TrimSpace(linkURL)
if linkURL == "" {
return
}
linkType := util.GetLinkType(linkURL)
if linkType == "" || linkType == "others" {
return
}
if _, ok := seen[linkURL]; ok {View on GitHub (pinned to beaa561337)