{"record":{"id":"baa4b2abeed32cc5","repo":"fish2018/pansou","slug":"s-w-baa4b2","errorCode":null,"errorMessage":"[%s] 解析详情页失败: %w","messagePattern":"\\[(.+?)\\] 解析详情页失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"plugin/qiwei/qiwei.go","lineNumber":420,"sourceCode":"\tif isVerifyPage(string(responseBody)) {\n\t\treturn fmt.Errorf(\"站点未接受验证参数\")\n\t}\n\treturn nil\n}\n\nfunc md5StringToHex(value string) string {\n\tvar builder strings.Builder\n\tfor _, r := range value {\n\t\tbuilder.WriteString(fmt.Sprintf(\"%d\", r+1))\n\t}\n\tsum := md5.Sum([]byte(builder.String()))\n\treturn hex.EncodeToString(sum[:])\n}\n\nfunc (p *QiweiPlugin) parseDetail(detailURL, body, fallbackTitle, fallbackPic string) (detailInfo, error) {\n\tdoc, err := goquery.NewDocumentFromReader(strings.NewReader(body))\n\tif err != nil {\n\t\treturn detailInfo{}, fmt.Errorf(\"[%s] 解析详情页失败: %w\", p.Name(), err)\n\t}\n\n\ttitle := cleanText(doc.Find(\".main-ui-meta h1\").First().Text())\n\ttitle = yearSuffixRegex.ReplaceAllString(title, \"\")\n\tif title == \"\" {\n\t\ttitle = fallbackTitle\n\t}\n\n\tcover := normalizeURL(detailURL, attrOrEmpty(doc.Find(`meta[property=\"og:image\"]`).First(), \"content\"))\n\tif cover == \"\" {\n\t\tcover = normalizeURL(detailURL, attrOrEmpty(doc.Find(\".main-left .img img\").First(), \"src\"))\n\t}\n\tif cover == \"\" {\n\t\tcover = fallbackPic\n\t}\n\n\tcontentParts := make([]string, 0, 3)\n\tif meta := cleanText(doc.Find(\".main-ui-meta .otherbox\").First().Text()); meta != \"\" {","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/qiwei/qiwei.go#L402-L438","documentation":"parseDetail hands the fetched HTML body to goquery.NewDocumentFromReader. goquery only errors when the underlying XML/HTML parser fails, which is rare; this error wraps that parser failure with the plugin name prefix. It means the document could not be constructed at all.","triggerScenarios":"goquery.NewDocumentFromReader(strings.NewReader(body)) returns a non-nil error inside parseDetail, called from getDetailInfo after a successful fetch of a detail candidate URL.","commonSituations":"Practically triggered by an empty or nil reader state rather than truly invalid HTML (goquery's parser is lenient); a body containing extremely malformed content in strict parsing configurations.","solutions":["Verify the body passed to parseDetail is non-empty and is actually HTML (log a snippet on error)","Since goquery tolerates most malformed HTML, check for a goquery/x-net-html version issue and update dependencies","Rely on getDetailInfo's fallback: it continues to the next candidate URL, so ensure candidate list covers alternates"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"info, err := plugin.GetDetailInfo(ctx, url)\nif err != nil && strings.Contains(err.Error(), \"解析详情页失败\") {\n    log.Printf(\"goquery parse failed for %s: %v\", url, err)\n    return detailInfo{} // degrade gracefully; getDetailInfo already tries alternate URLs\n}","preventionTips":["Keep goquery and golang.org/x/net updated","getDetailInfo already falls back to other candidate URLs — ensure candidate lists are populated","Log body snippets when parsing fails to detect non-HTML responses"],"tags":["html","parsing","goquery","scraping"],"backgroundTag":"unexpected-response-shape","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"}