fish2018/pansou · error
站点触发 Cloudflare 浏览器验证
Error message
站点触发 Cloudflare 浏览器验证
What it means
This plugin-level heuristic detects Cloudflare's interstitial challenge page: if no search results were extracted and the page <title> is exactly 'Just a moment...', the site is serving a browser-verification challenge that server-side HTTP clients cannot pass, so a dedicated descriptive error is returned.
Solutions
- Treat the site as migrated and stop server-side scraping (see the plugin's own detection at doRequestWithRetry via cf-mitigated header)
- Use a headless browser (chromedp/rod) to pass the challenge
- Route requests through a residential proxy or retry later
- Check the cf-mitigated: challenge header proactively and surface a user-facing message
Defensive patterns
Strategy: fallback
Validate before calling
if doc.Find("title").First().Text() == "Just a moment..." {
// challenge detected before extracting results
return errChallenge
} Try / catch
results, err := plugin.Search(ctx, kw)
if err != nil && strings.Contains(err.Error(), "Cloudflare") {
return useHeadlessBrowserFallback(ctx, kw)
} Prevention
- Watch for Cloudflare 'Just a moment...' pages
- Prefer headless browsers for protected sites
- Use residential egress IPs
- Disable scraping when cf-mitigated: challenge appears
When it happens
Trigger: Cloudflare bot management serves the JS challenge page with status 200; extractSearchResults finds zero results and the title matches 'Just a moment...'.
Common situations: Target site recently enabled Cloudflare under-attack mode or bot fight mode; datacenter IP or non-browser User-Agent flagged; scraping from a cloud provider IP range.
Related errors
- [ ] 搜索请求返回 HTTP
- [ ] 搜索请求返回状态码
- [ ] 请求搜索页面失败,状态码
- 期望302重定向,但得到状态码
- [ ] 触发 Cloudflare Managed Challenge (HTTP )
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/24c648a6723afcb6.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/xdpan/xdpan.go:130
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
return nil, fmt.Errorf("GET请求失败: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("请求返回状态码: %d", resp.StatusCode)
}
// 解析HTML
doc, err := goquery.NewDocumentFromReader(io.LimitReader(resp.Body, maxPageSize))
if err != nil {
return nil, fmt.Errorf("解析HTML失败: %w", err)
}
results := p.extractSearchResults(doc)
if len(results) == 0 && doc.Find("title").First().Text() == "Just a moment..." {
return nil, fmt.Errorf("站点触发 Cloudflare 浏览器验证")
}
return results, nil
}
// extractSearchResults 从搜索页面提取结果
func (p *XdpanPlugin) extractSearchResults(doc *goquery.Document) []model.SearchResult {
var results []model.SearchResult
// 查找所有包含详情页链接的van-row元素
doc.Find("van-row").Each(func(i int, s *goquery.Selection) {
// 检查是否包含详情页链接
detailLink := s.Find("a[href^='/s/']")
if detailLink.Length() == 0 {
return
}
result := p.parseSearchResult(s)
if result.Title != "" {View on GitHub (pinned to beaa561337)