fish2018/pansou · error

[ ] 第 页HTML解析失败

Error message

[%s] 第%d页HTML解析失败: %w

What it means

This error is thrown by Dy4kPlugin.searchPage when goquery.NewDocumentFromReader cannot parse the fetched HTML. It means the response body, although readable, is not valid/parseable HTML (e.g., a truncated document, an anti-bot challenge page, or binary/encoded content instead of HTML). The underlying goquery/xml parse error is wrapped with the plugin name and page number.

Solutions

  1. Log/save htmlContent (debug mode already can dump it) and inspect what the server actually returned
  2. Check for anti-bot interstitials and rotate User-Agent / add cookies
  3. Retry the request — truncation is often transient
  4. Verify the response Content-Encoding is being handled (disable manual gzip handling conflicts in the transport)

Example fix

// before
doc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlContent))
if err != nil {
    return nil, 0, fmt.Errorf("[%s] 第%d页HTML解析失败: %w", p.Name(), page, err)
}
// after
doc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlContent))
if err != nil {
    return nil, 0, fmt.Errorf("[%s] 第%d页HTML解析失败 (长度=%d, 前100字节=%.100q): %w", p.Name(), page, len(htmlContent), htmlContent, err)
}
Defensive patterns

Strategy: validation

Validate before calling

if len(htmlContent) == 0 { return errors.New("empty HTML response") }
if !strings.Contains(htmlContent, "<html") && !strings.Contains(htmlContent, "<!DOCTYPE") {
    return fmt.Errorf("non-HTML response: %.200q", htmlContent)
}

Try / catch

doc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlContent))
if err != nil {
    return fmt.Errorf("parse failed: %w (head=%.200q)", err, htmlContent) // inspect before retrying
}

Prevention

When it happens

Trigger: Calling Search when the HTML fetched for a search page fails goquery parsing — typically a truncated or malformed response, a WAF/captcha interstitial, or non-HTML content returned with 200.

Common situations: Site serves a Cloudflare/security challenge page; response truncated by an unstable connection; site changed markup or returned compressed content without correct Content-Encoding handling.

Related errors


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

Appendix: source

Thrown at plugin/dy4k/dy4k.go:446

	if DebugMode {
		htmlDir := "./html"
		os.MkdirAll(htmlDir, 0755)

		filename := fmt.Sprintf("dy4k_page_%d_%s.html", page, strings.ReplaceAll(encodedKeyword, "%", "_"))
		filepath := filepath.Join(htmlDir, filename)

		err = os.WriteFile(filepath, htmlBytes, 0644)
		if err != nil {
			debugPrintf("❌ [Dy4k DEBUG] 保存HTML文件失败: %v\n", err)
		} else {
			debugPrintf("✅ [Dy4k DEBUG] HTML已保存到: %s\n", filepath)
		}
	}

	// 解析HTML响应
	doc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlContent))
	if err != nil {
		return nil, 0, fmt.Errorf("[%s] 第%d页HTML解析失败: %w", p.Name(), page, err)
	}

	// 8. 解析分页信息
	totalPages := p.parseTotalPages(doc)

	// 9. 提取搜索结果。旧版使用 .hl-list-item,新版 4KDY 使用 /4K-detail/ 链接。
	results := make([]model.SearchResult, 0)
	if legacyItems := doc.Find(".hl-list-item"); legacyItems.Length() > 0 {
		legacyItems.Each(func(_ int, s *goquery.Selection) {
			if result := p.parseSearchResultItem(s); result != nil {
				results = append(results, *result)
			}
		})
	} else {
		p.extractNewSearchResults(doc, &results)
	}

	return results, totalPages, nil

View on GitHub (pinned to beaa561337)