{"record":{"id":"9d1144de8887db9c","repo":"fish2018/pansou","slug":"s-html-w-9d1144","errorCode":null,"errorMessage":"[%s] 解析搜索结果HTML失败: %w","messagePattern":"\\[(.+?)\\] 解析搜索结果HTML失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/dyyj/dyyj.go","lineNumber":364,"sourceCode":"\t\t}\n\n\t\t// 查找所有包含/d/的链接（使用预编译的正则）\n\t\tmatches := linkHrefRegex.FindAllStringSubmatch(bodyString, -1)\n\t\tlog.Printf(\"[DYYJ] 使用正则表达式找到 %d 个包含'/d/'的链接\", len(matches))\n\t\tfor i, match := range matches {\n\t\t\tif i < 10 {\n\t\t\t\tlog.Printf(\"[DYYJ]   链接 %d: %s\", i+1, match[1])\n\t\t\t}\n\t\t}\n\t}\n\n\t// 解析HTML提取搜索结果\n\tdoc, err := goquery.NewDocumentFromReader(strings.NewReader(bodyString))\n\tif err != nil {\n\t\tif p.debugMode {\n\t\t\tlog.Printf(\"[DYYJ] 解析搜索结果HTML失败: %v\", err)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"[%s] 解析搜索结果HTML失败: %w\", p.Name(), err)\n\t}\n\n\tresults, err := p.parseSearchResults(doc, bodyString)\n\tif p.debugMode {\n\t\tlog.Printf(\"[DYYJ] 解析搜索结果完成，获取到 %d 个结果\", len(results))\n\t}\n\n\treturn results, err\n}\n\ntype dyyjAPIResponse struct {\n\tData     []dyyjDiscussion `json:\"data\"`\n\tIncluded []dyyjIncluded   `json:\"included\"`\n}\n\ntype dyyjDiscussion struct {\n\tID         string `json:\"id\"`\n\tAttributes struct {","sourceCodeStart":346,"sourceCodeEnd":382,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/dyyj/dyyj.go#L346-L382","documentation":"dyyj.executeSearchHTML could not parse the fetched search page HTML into a goquery document (goquery.NewDocumentFromReader failed). Indicates the body was not valid parseable HTML — empty, binary, or severely malformed content.","triggerScenarios":"goquery.NewDocumentFromReader(strings.NewReader(bodyString)) returned err — typically an empty body, gzip/brotli bytes not decompressed (Content-Encoding mishandled), or binary garbage from a WAF.","commonSituations":"Response was compressed but the client lacks automatic decompression; site returned an empty 200; anti-bot served raw challenge bytes the parser chokes on.","solutions":["Log bodyString length and first bytes to see what was actually received","Ensure the transport handles Content-Encoding (EnableFullDuplex/default Go transport handles gzip; brotli needs manual handling)","Guard against empty bodyString before parsing","Verify the site still returns HTML and not a JSON API or challenge page"],"exampleFix":"// before\ndoc, err := goquery.NewDocumentFromReader(strings.NewReader(bodyString))\nif err != nil {\n\treturn nil, fmt.Errorf(\"[%s] 解析搜索结果HTML失败: %w\", p.Name(), err)\n}\n// after\nif len(bodyString) == 0 {\n\treturn nil, fmt.Errorf(\"[%s] 响应体为空\", p.Name())\n}\ndoc, err := goquery.NewDocumentFromReader(strings.NewReader(bodyString))\nif err != nil {\n\treturn nil, fmt.Errorf(\"[%s] 解析搜索结果HTML失败: %w (head=%q)\", p.Name(), err, bodyString[:min(64, len(bodyString))])\n}","handlingStrategy":"validation","validationCode":"if len(bodyString) == 0 { return errors.New(\"empty search response\") }\nif !strings.Contains(strings.ToLower(resp.Header.Get(\"Content-Type\")), \"html\") { return fmt.Errorf(\"unexpected content-type: %s\", resp.Header.Get(\"Content-Type\")) }","typeGuard":"func looksLikeHTML(s string) bool {\n\ts = strings.TrimSpace(s)\n\treturn strings.HasPrefix(s, \"<\") || strings.HasPrefix(s, \"\\xef\\xbb\\xbf<\") || strings.Contains(s[:min(512, len(s))], \"<html\")\n}","tryCatchPattern":"doc, err := goquery.NewDocumentFromReader(strings.NewReader(bodyString))\nif err != nil {\n\tlog.Printf(\"html parse failed: %v, head=%q\", err, bodyString[:min(64, len(bodyString))])\n\treturn nil, err\n}","preventionTips":["Verify Content-Encoding handling (gzip/brotli) in the transport","Reject empty bodies before parsing","Check for WAF challenge pages before parsing","Snapshot a body prefix on every parse failure"],"tags":["html-parsing","go","scraper"],"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"}