fish2018/pansou · error
[ ] HTML解析失败
Error message
[%s] HTML解析失败: %w
What it means
goquery.NewDocumentFromReader failed to parse the search response body as HTML. goquery returns an error only when reading the body fails or the document cannot be constructed (e.g. empty/stream-broken input), not for ordinary malformed HTML.
Solutions
- Check body length before parsing; treat empty bodies as an upstream/anti-bot issue
- Retry the request on parse failure
- Log a body snippet to see what the 200 response actually contained
- Verify no middleware closes resp.Body before goquery reads it
Example fix
// before
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, fmt.Errorf("[%s] HTML解析失败: %w", p.Name(), err)
}
// after
bodyBytes, rerr := io.ReadAll(resp.Body)
if rerr != nil || len(bodyBytes) == 0 {
return nil, fmt.Errorf("[%s] 空或不可读的响应体: %v", p.Name(), rerr)
}
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(bodyBytes))
if err != nil {
return nil, fmt.Errorf("[%s] HTML解析失败: %w", p.Name(), err)
} Defensive patterns
Strategy: fallback
Validate before calling
b, _ := io.ReadAll(resp.Body)
if len(b) == 0 || (!bytes.Contains(b, []byte("<html")) && !bytes.Contains(bytes.ToLower(b), []byte("<!doctype"))) {
return fmt.Errorf("response is not HTML")
} Type guard
func isHTMLBody(body []byte) bool {
trimmed := bytes.TrimSpace(body)
return len(trimmed) > 0 && bytes.HasPrefix(trimmed, []byte("<"))
} Try / catch
results, err := plugin.Search(keyword, ext)
if err != nil {
if strings.Contains(err.Error(), "HTML解析失败") {
// empty/truncated body: retry or fall back to other plugins
}
} Prevention
- Buffer the body and check emptiness before goquery parsing
- Retry once on parse failure — bodies are often truncated transiently
- Keep resp.Body open until goquery has consumed it
When it happens
Trigger: The response body could not be read as an HTML document — typically a truncated/empty body, an already-closed reader, or a body interrupted mid-transfer after a 200 status.
Common situations: Anti-bot layer returned an empty 200 body; connection cut mid-response; proxy mangling the body; the site now returns JSON/redirect content where HTML was expected.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/e4aadfad81487118.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/pianku/pianku.go:153
// 设置请求头
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
}
detailURL := result.Links[0].URL
// 请求详情页并解析下载链接
downloadLinks, err := p.fetchDetailPageLinks(client, detailURL)
if err != nil {
// 如果获取详情页失败,仍然保留原始结果View on GitHub (pinned to beaa561337)