fish2018/pansou · error
[ ] 解析搜索结果HTML失败
Error message
[%s] 解析搜索结果HTML失败: %w
What it means
executeSearchWithRateLimit returns '[javdb] 解析搜索结果HTML失败: %w' (failed to parse search results HTML) when goquery.NewDocumentFromReader fails to parse the fetched body as HTML. With goquery this is rare and almost always means the reader itself errored, but it signals the response could not be turned into a parseable document.
Solutions
- Log the first bytes/Content-Type of bodyBytes when this fires to see what was actually returned
- Verify automatic gzip/deflate decompression (check Content-Encoding handling in the transport)
- Check for soft-block pages (challenge/JS) that are not real search HTML
- Guard against empty bodies before parsing and return a clearer 'empty response' error
- Update selectors/endpoint if the site changed its HTML contract
Example fix
// before
doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(bodyBytes)))
// after
if len(bodyBytes) == 0 {
return nil, fmt.Errorf("[%s] empty response body", p.Name()), false
}
doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(bodyBytes))) Defensive patterns
Strategy: validation
Validate before calling
// Go: sanity-check the body before HTML parsing
ct := resp.Header.Get("Content-Type")
if !strings.Contains(ct, "text/html") {
return fmt.Errorf("unexpected content-type %q", ct)
}
if len(bodyBytes) == 0 {
return errors.New("empty response body")
} Type guard
func looksLikeHTML(b []byte) bool {
s := strings.TrimSpace(string(b))
return len(s) > 0 && (strings.HasPrefix(s, "<") || strings.Contains(s[:min(200, len(s))], "<html"))
} Try / catch
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(bodyBytes))
if err != nil {
log.Printf("javdb html parse failed, body head=%q", bodyBytes[:min(200, len(bodyBytes))])
return nil, err, false
} Prevention
- Verify Content-Encoding/decompression is handled (garbled bodies break parsers)
- Check Content-Type before parsing
- Log a body snippet on parse failure to detect soft-block pages
- Update selectors when the site changes markup
When it happens
Trigger: goquery.NewDocumentFromReader returns an error on the bodyBytes reader — typically because the body is empty/corrupt or the underlying reader fails, after a successful (but wrong) response was fetched.
Common situations: Site returns a non-HTML body (JSON error, compressed/garbled bytes when Content-Encoding handling is broken, empty body from a soft block) that the HTML parser chokes on.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/9332d0c2610e59b4.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/javdb/javdb.go:237
if err != nil {
return nil, fmt.Errorf("[%s] 读取搜索结果失败: %w", p.Name(), err), false
}
if p.debugMode {
bodyStr := string(bodyBytes)
log.Printf("[JAVDB] 响应体长度: %d", len(bodyStr))
// 输出前500个字符用于调试
if len(bodyStr) > 500 {
log.Printf("[JAVDB] 响应体前500字符: %s", bodyStr[:500])
} else {
log.Printf("[JAVDB] 完整响应体: %s", bodyStr)
}
}
// 解析HTML提取搜索结果
doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(bodyBytes)))
if err != nil {
return nil, fmt.Errorf("[%s] 解析搜索结果HTML失败: %w", p.Name(), err), false
}
results, err := p.parseSearchResults(doc)
return results, err, false
}
// doRequestWithRetry 带重试机制的HTTP请求
func (p *JavdbPlugin) doRequestWithRetry(req *http.Request, client *http.Client) (*http.Response, error) {
maxRetries := 3
var lastErr error
for i := 0; i < maxRetries; i++ {
if i > 0 {
// 指数退避重试
backoff := time.Duration(1<<uint(i-1)) * 200 * time.Millisecond
time.Sleep(backoff)
}View on GitHub (pinned to beaa561337)