fish2018/pansou · error
详情页HTML解析失败
Error message
详情页HTML解析失败: %w
What it means
goquery.NewDocumentFromReader failed while parsing the detail-page response body into an HTML document. goquery returns this error when reading the body stream fails (goquery itself does not validate HTML; malformed HTML still parses leniently).
Solutions
- Retry the request — a truncated body is usually transient network corruption.
- Ensure automatic decompression: set Transport.DisableCompression=false or use httputil to handle gzip; don't set Accept-Encoding manually without decoding.
- Check that resp.Body wasn't read before this call (e.g. by a debug logger).
- Capture and log the underlying read error (errors.Unwrap) to confirm I/O vs decompression.
Example fix
// before
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, fmt.Errorf("详情页HTML解析失败: %w", err)
}
// after
body, rerr := io.ReadAll(resp.Body)
if rerr != nil {
return nil, fmt.Errorf("读取详情页响应体失败: %w", rerr)
}
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(body))
if err != nil {
return nil, fmt.Errorf("详情页HTML解析失败: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
body, err := io.ReadAll(resp.Body)
if err != nil || len(body) == 0 {
return // truncated/empty body, retry the request
} Type guard
func isBodyReadError(err error) bool {
return err != nil && (errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF))
} Try / catch
results, err := plugin.Search(keyword)
if err != nil && strings.Contains(err.Error(), "详情页HTML解析失败") {
// transient I/O on the body: retry once
results, err = plugin.Search(keyword)
} Prevention
- Let the http.Transport handle gzip/deflate; don't set Accept-Encoding manually.
- Buffer the response body before parsing so failures are diagnosable.
- Avoid reading resp.Body anywhere before goquery.
- Retry body-read failures; they are usually transient network truncation.
When it happens
Trigger: Reading resp.Body returned an I/O error: connection dropped mid-body, gzip/deflate decompression failure due to a corrupted or truncated response, or the body was already partially consumed.
Common situations: Unstable network cutting the response short; server advertises Content-Encoding: gzip but sends invalid data; a proxy mangling the response; very large pages hitting an underlying read limit.
Related errors
AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07).
Data as JSON: /api/errors/d00be829e87785cb.
Report an issue: GitHub.
Appendix: source
Thrown at plugin/pianku/pianku.go:405
// 设置请求头
p.setRequestHeaders(req)
// 发送HTTP请求
resp, err := p.doRequestWithRetry(req, client)
if err != nil {
return nil, fmt.Errorf("详情页请求失败: %w", err)
}
defer resp.Body.Close()
// 检查状态码
if resp.StatusCode != 200 {
return nil, fmt.Errorf("详情页请求返回状态码: %d", resp.StatusCode)
}
// 解析HTML
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
return nil, fmt.Errorf("详情页HTML解析失败: %w", err)
}
// 提取下载链接
return p.extractDownloadLinks(doc), nil
}
// extractDownloadLinks 提取详情页中的下载链接
func (p *PiankuPlugin) extractDownloadLinks(doc *goquery.Document) []model.Link {
var links []model.Link
seenURLs := make(map[string]bool) // 用于去重
// 查找下载链接区域
doc.Find("#donLink .down-list2").Each(func(i int, s *goquery.Selection) {
linkURL, exists := s.Find(".down-list3 a").Attr("href")
if !exists || linkURL == "" {
return
}
View on GitHub (pinned to beaa561337)