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

  1. Check body length before parsing; treat empty bodies as an upstream/anti-bot issue
  2. Retry the request on parse failure
  3. Log a body snippet to see what the 200 response actually contained
  4. 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

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)