fish2018/pansou · error

[ ] 解析HTML失败

Error message

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

What it means

Returned by doSearch in the aikanzy plugin when goquery.NewDocumentFromReader fails to parse the HTTP response body as HTML. This is rare — it occurs only when reading the body fails (I/O error) or the response body is not valid parseable content (e.g. binary data, compressed/garbled encoding).

Solutions

  1. Check that the http.Client Transport isn't forcing an Accept-Encoding the client can't decode; let net/http handle gzip automatically.
  2. Read the body into memory first (io.ReadAll) and inspect it to confirm it is HTML before parsing.
  3. Verify the connection isn't truncated (check for partial results; retry on read errors).
  4. If the site serves non-HTML challenge pages, update headers/cookies to pass anti-bot checks.

Example fix

// before
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
	return nil, fmt.Errorf("[%s] 解析HTML失败: %w", p.Name(), err)
}
// after
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
	return nil, fmt.Errorf("[%s] 读取响应体失败: %w", p.Name(), err)
}
doc, err := goquery.NewDocumentFromReader(bytes.NewReader(bodyBytes))
if err != nil {
	return nil, fmt.Errorf("[%s] 解析HTML失败 (前100字节: %q): %w", p.Name(), bodyBytes[:min(100, len(bodyBytes))], err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

ct := resp.Header.Get("Content-Type")
if !strings.Contains(ct, "text/html") {
	return fmt.Errorf("unexpected content type: %s", ct)
}

Try / catch

doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
	// retry once; if it persists, dump the body for inspection
	raw, rerr := io.ReadAll(resp.Body)
	if rerr == nil {
		log.Printf("unparseable body head: %q", raw[:min(200, len(raw))])
	}
	return err
}

Prevention

When it happens

Trigger: After a 200 response, goquery.NewDocumentFromReader(resp.Body) returns an error because the body stream failed mid-read or the content is not HTML (e.g. a compressed body with mismatched Content-Encoding, or a challenge page served as non-HTML).

Common situations: Server returns gzip/brotli content that http.Client didn't transparently decompress (custom Transport missing Accept-Encoding handling); truncated response due to connection reset mid-body; site serves a CAPTCHA/JS-challenge page with unexpected encoding.

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/155f5273db287466. Report an issue: GitHub.

Appendix: source

Thrown at plugin/aikanzy/aikanzy.go:174

	req.Header.Set("Upgrade-Insecure-Requests", "1")
	req.Header.Set("Cache-Control", "max-age=0")
	
	// 使用带重试的请求方法发送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 != http.StatusOK {
		return nil, fmt.Errorf("[%s] 请求搜索页面失败,状态码: %d", p.Name(), resp.StatusCode)
	}
	
	// 使用goquery解析HTML
	doc, err := goquery.NewDocumentFromReader(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("[%s] 解析HTML失败: %w", p.Name(), err)
	}
	
	// 解析搜索结果列表
	articleItems := p.parseArticleList(doc)
	if len(articleItems) == 0 {
		return []model.SearchResult{}, nil
	}
	
	// 并发抓取详情页获取网盘链接
	results := p.fetchDetailsWithLinks(articleItems, client, keyword)
	
	// 使用过滤功能过滤结果
	filteredResults := plugin.FilterResultsByKeyword(results, keyword)
	
	return filteredResults, nil
}

// ArticleItem 文章基本信息

View on GitHub (pinned to beaa561337)