{"record":{"id":"f8de89eea779e818","repo":"fish2018/pansou","slug":"s-d-html-w","errorCode":null,"errorMessage":"[%s] 第%d页HTML解析失败: %w","messagePattern":"\\[(.+?)\\] 第(.+?)页HTML解析失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/dy4k/dy4k.go","lineNumber":446,"sourceCode":"\tif DebugMode {\n\t\thtmlDir := \"./html\"\n\t\tos.MkdirAll(htmlDir, 0755)\n\n\t\tfilename := fmt.Sprintf(\"dy4k_page_%d_%s.html\", page, strings.ReplaceAll(encodedKeyword, \"%\", \"_\"))\n\t\tfilepath := filepath.Join(htmlDir, filename)\n\n\t\terr = os.WriteFile(filepath, htmlBytes, 0644)\n\t\tif err != nil {\n\t\t\tdebugPrintf(\"❌ [Dy4k DEBUG] 保存HTML文件失败: %v\\n\", err)\n\t\t} else {\n\t\t\tdebugPrintf(\"✅ [Dy4k DEBUG] HTML已保存到: %s\\n\", filepath)\n\t\t}\n\t}\n\n\t// 解析HTML响应\n\tdoc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlContent))\n\tif err != nil {\n\t\treturn nil, 0, fmt.Errorf(\"[%s] 第%d页HTML解析失败: %w\", p.Name(), page, err)\n\t}\n\n\t// 8. 解析分页信息\n\ttotalPages := p.parseTotalPages(doc)\n\n\t// 9. 提取搜索结果。旧版使用 .hl-list-item，新版 4KDY 使用 /4K-detail/ 链接。\n\tresults := make([]model.SearchResult, 0)\n\tif legacyItems := doc.Find(\".hl-list-item\"); legacyItems.Length() > 0 {\n\t\tlegacyItems.Each(func(_ int, s *goquery.Selection) {\n\t\t\tif result := p.parseSearchResultItem(s); result != nil {\n\t\t\t\tresults = append(results, *result)\n\t\t\t}\n\t\t})\n\t} else {\n\t\tp.extractNewSearchResults(doc, &results)\n\t}\n\n\treturn results, totalPages, nil","sourceCodeStart":428,"sourceCodeEnd":464,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/dy4k/dy4k.go#L428-L464","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Log/save htmlContent (debug mode already can dump it) and inspect what the server actually returned","Check for anti-bot interstitials and rotate User-Agent / add cookies","Retry the request — truncation is often transient","Verify the response Content-Encoding is being handled (disable manual gzip handling conflicts in the transport)"],"exampleFix":"// before\ndoc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlContent))\nif err != nil {\n    return nil, 0, fmt.Errorf(\"[%s] 第%d页HTML解析失败: %w\", p.Name(), page, err)\n}\n// after\ndoc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlContent))\nif err != nil {\n    return nil, 0, fmt.Errorf(\"[%s] 第%d页HTML解析失败 (长度=%d, 前100字节=%.100q): %w\", p.Name(), page, len(htmlContent), htmlContent, err)\n}","handlingStrategy":"validation","validationCode":"if len(htmlContent) == 0 { return errors.New(\"empty HTML response\") }\nif !strings.Contains(htmlContent, \"<html\") && !strings.Contains(htmlContent, \"<!DOCTYPE\") {\n    return fmt.Errorf(\"non-HTML response: %.200q\", htmlContent)\n}","typeGuard":null,"tryCatchPattern":"doc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlContent))\nif err != nil {\n    return fmt.Errorf(\"parse failed: %w (head=%.200q)\", err, htmlContent) // inspect before retrying\n}","preventionTips":["Verify response Content-Type is text/html before parsing","Detect anti-bot/captcha interstitials by signature strings and rotate UA/cookies","Log a body preview on parse failure to diagnose what the server returned","Handle Content-Encoding correctly so decompressed text is parsed"],"tags":["html","parsing","goquery","go"],"backgroundTag":"html-parse-failed","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}