fish2018/pansou · error

[ ] HTML解析失败

Error message

[%s] HTML解析失败: %w

What it means

jutoushe searchImpl wraps errors from goquery.NewDocumentFromReader, which parses the response body as HTML. This fails when the body is not valid HTML — empty body, truncated response, JSON error page, or compressed content not decompressed.

Solutions

  1. Read the body first and check it is non-empty before parsing
  2. Verify Content-Encoding handling (set Accept-Encoding or use an auto-decompressing transport)
  3. Log the first bytes of the body to see what the server actually returned
  4. Check that resp.Body was not already consumed by a prior read

Example fix

// before
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil { return nil, fmt.Errorf("[%s] HTML解析失败: %w", p.Name(), err) }
// after
body, rerr := io.ReadAll(resp.Body)
if rerr != nil || len(bytes.TrimSpace(body)) == 0 {
    return nil, fmt.Errorf("[%s] empty or unreadable response body", p.Name())
}
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(body))
Defensive patterns

Strategy: fallback

Validate before calling

body, _ := io.ReadAll(io.LimitReader(resp.Body, 256))
if len(bytes.TrimSpace(body)) == 0 {
    return errors.New("empty response body; skip parsing")
}

Try / catch

results, err := plugin.Search(keyword)
if err != nil {
    if strings.Contains(err.Error(), "HTML解析失败") {
        return useAlternativeSource(keyword) // fall back to another plugin
    }
    return err
}

Prevention

When it happens

Trigger: goquery.NewDocumentFromReader(resp.Body) errors: empty response body, charset/gzip issues, or a non-HTML response (e.g. a JSON error from a CDN).

Common situations: Anti-bot layer returns an empty or challenge page; response gzip-compressed but not handled; connection closed early producing truncated HTML.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


AI-assisted analysis of fish2018/pansou@beaa561337 (2026-09-07). Data as JSON: /api/errors/dede525398695bd6. Report an issue: GitHub.

Appendix: source

Thrown at plugin/jutoushe/jutoushe.go:82

	req.Header.Set("Connection", "keep-alive")
	req.Header.Set("Referer", baseURL+"/")

	// 5. 发送HTTP请求(带重试机制)
	resp, err := p.doRequestWithRetry(req, client)
	if err != nil {
		return nil, fmt.Errorf("[%s] 搜索请求失败: %w", p.Name(), err)
	}
	defer resp.Body.Close()

	// 6. 检查状态码
	if resp.StatusCode != 200 {
		return nil, fmt.Errorf("[%s] 请求返回状态码: %d", p.Name(), resp.StatusCode)
	}

	// 7. 解析搜索结果页面
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("[%s] HTML解析失败: %w", p.Name(), err)
	}

	// 8. 提取搜索结果
	var results []model.SearchResult
	doc.Find("ul.erx-list li.item").Each(func(i int, s *goquery.Selection) {
		// 提取标题和链接
		linkElem := s.Find(".a a.main")
		title := strings.TrimSpace(linkElem.Text())
		detailPath, exists := linkElem.Attr("href")
		
		if !exists || title == "" {
			return // 跳过无效项
		}

		// 构建完整的详情页URL
		detailURL := baseURL + detailPath

		// 提取发布时间

View on GitHub (pinned to beaa561337)