{"record":{"id":"04db135c3e7e51e9","repo":"fish2018/pansou","slug":"s-w-04db13","errorCode":null,"errorMessage":"[%s] 解析搜索页面失败: %w","messagePattern":"\\[(.+?)\\] 解析搜索页面失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/muou/muou.go","lineNumber":230,"sourceCode":"\treq.Header.Set(\"Upgrade-Insecure-Requests\", \"1\")\n\treq.Header.Set(\"Cache-Control\", \"max-age=0\")\n\treq.Header.Set(\"Referer\", strings.TrimRight(baseURL, \"/\")+\"/\")\n\n\t// 5. 发送请求（带重试机制）\n\tresp, err := p.doRequestWithRetry(req, client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求失败: %w\", p.Name(), err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求返回状态码: %d\", p.Name(), resp.StatusCode)\n\t}\n\n\t// 6. 解析搜索结果页面\n\tdoc, err := goquery.NewDocumentFromReader(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 解析搜索页面失败: %w\", p.Name(), err)\n\t}\n\n\t// 7. 提取搜索结果\n\tvar results []model.SearchResult\n\n\tdoc.Find(\".module-search-item\").Each(func(i int, s *goquery.Selection) {\n\t\tresult := p.parseSearchItem(s, keyword)\n\t\tif result.UniqueID != \"\" {\n\t\t\tresults = append(results, result)\n\t\t}\n\t})\n\n\treturn results, nil\n}\n\n// parseSearchItem 解析单个搜索结果项\nfunc (p *MuouAsyncPlugin) parseSearchItem(s *goquery.Selection, keyword string) model.SearchResult {\n\tresult := model.SearchResult{}","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/muou/muou.go#L212-L248","documentation":"Raised in Muou's searchAtBase when goquery.NewDocumentFromReader fails to parse the search response body as HTML. The body was empty, truncated, or not HTML — often an anti-bot challenge page or an encoding problem.","triggerScenarios":"Triggered when the search page body cannot be parsed: empty response body, connection closed mid-download, gzip/deflate body not decoded, or a JS challenge page that is still invalid HTML.","commonSituations":"CDN serves a challenge/interstitial; response body already consumed elsewhere; server closes connection early under load; charset/encoding issues breaking the tokenizer.","solutions":["Read the body with io.ReadAll first and log a prefix on parse failure to see actual content","Confirm resp.Body was not previously read (single consumption)","Verify Content-Type of the response is text/html before parsing","Let http.Client handle compression automatically (don't set raw Accept-Encoding unless decoding manually)","Add a length check to skip/record empty bodies distinctly from parse errors"],"exampleFix":"// before\ndoc, err := goquery.NewDocumentFromReader(resp.Body)\nif err != nil {\n    return nil, fmt.Errorf(\"[%s] 解析搜索页面失败: %w\", p.Name(), err)\n}\n// after\nbody, rerr := io.ReadAll(resp.Body)\nif rerr != nil {\n    return nil, fmt.Errorf(\"[%s] 读取搜索页面失败: %w\", p.Name(), rerr)\n}\nif len(bytes.TrimSpace(body)) == 0 {\n    return nil, fmt.Errorf(\"[%s] 搜索页面响应为空\", p.Name())\n}\ndoc, err := goquery.NewDocumentFromReader(bytes.NewReader(body))\nif err != nil {\n    return nil, fmt.Errorf(\"[%s] 解析搜索页面失败: %w\", p.Name(), err)\n}","handlingStrategy":"validation","validationCode":"body, err := io.ReadAll(resp.Body)\nif err != nil { return err }\nif len(bytes.TrimSpace(body)) == 0 {\n    return errEmptyBody\n}\nif !strings.Contains(resp.Header.Get(\"Content-Type\"), \"text/html\") {\n    return fmt.Errorf(\"non-html response: %s\", resp.Header.Get(\"Content-Type\"))\n}\ndoc, err := goquery.NewDocumentFromReader(bytes.NewReader(body))","typeGuard":null,"tryCatchPattern":"doc, err := goquery.NewDocumentFromReader(resp.Body)\nif err != nil {\n    log.Printf(\"search page parse failed: %v\", err)\n    return nil, errParse // let caller try next mirror\n}","preventionTips":["Validate Content-Type and body length before goquery parsing","Read the body exactly once","Log body prefixes to detect anti-bot challenge pages","Handle compression via http.Client defaults"],"tags":["html-parsing","goquery","scraping","go"],"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"}