fish2018/pansou · error

[ ] HTML解析失败

Error message

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

What it means

searchPage wraps the error from goquery.NewDocumentFromReader, which parses the response body as HTML using the goquery/html parser. goquery's HTML parser is extremely lenient, so this error almost always means the body was not parseable at all — e.g. empty body, binary/compressed content, or garbage — rather than merely malformed markup.

Solutions

  1. Log the first bytes / length of body to see what was actually received
  2. Check the Content-Type and Content-Encoding response headers and add gzip handling if needed
  3. Send realistic Accept/Accept-Encoding headers via setRequestHeaders to get proper HTML
  4. Verify the site still serves the expected search HTML (open searchURL in a browser)
  5. If the site's markup changed, update extractSearchResults selectors; the parse error itself usually indicates non-HTML content
Defensive patterns

Strategy: fallback

Validate before calling

// check response looks like HTML before parsing
cType := resp.Header.Get("Content-Type")
if !strings.Contains(cType, "text/html") {
    return fmt.Errorf("unexpected content-type: %s", cType)
}
if len(body) == 0 {
    return fmt.Errorf("empty response body")
}

Type guard

func looksLikeHTML(b []byte) bool {
    s := strings.TrimSpace(string(b))
    return len(s) > 0 && (strings.HasPrefix(s, "<") || strings.Contains(s[:min(200, len(s))], "<html"))
}

Try / catch

results, err := p.Search(keyword, ext)
if err != nil {
    if strings.Contains(err.Error(), "HTML解析失败") {
        // fall back to another search plugin; log body sample for diagnosis
    }
}

Prevention

When it happens

Trigger: goquery.NewDocumentFromReader(strings.NewReader(string(body))) fails: body is nil/garbled, served with an unexpected content encoding that wasn't decompressed, or the site returned binary data with a 200 status.

Common situations: Site changed response format or now serves compressed content without proper Accept-Encoding handling; response body empty because of a silent WAF block; CDN serving an error asset.

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

Appendix: source

Thrown at plugin/wuji/wuji.go:209

		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)
	}
	
	// 读取响应体内容
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("[%s] 读取响应失败: %w", p.Name(), err)
	}
	
	// 解析HTML
	doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(body)))
	if err != nil {
		return nil, fmt.Errorf("[%s] HTML解析失败: %w", p.Name(), err)
	}
	
	// 提取搜索结果
	return p.extractSearchResults(doc), nil
}

// extractSearchResults 提取搜索结果
func (p *WujiPlugin) extractSearchResults(doc *goquery.Document) []model.SearchResult {
	var results []model.SearchResult
	
	// 查找所有搜索结果
	doc.Find("table.file-list tbody tr").Each(func(i int, s *goquery.Selection) {
		result := p.parseSearchResult(s)
		if result.Title != "" {
			results = append(results, result)
		}
	})
	

View on GitHub (pinned to beaa561337)