{"record":{"id":"89f827f7a1c3aa56","repo":"fish2018/pansou","slug":"s-w-89f827","errorCode":null,"errorMessage":"[%s] 解析搜索页面失败: %w","messagePattern":"\\[(.+?)\\] 解析搜索页面失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/nyaa/nyaa.go","lineNumber":133,"sourceCode":"\treq.Header.Set(\"Accept-Language\", \"en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7\")\n\treq.Header.Set(\"Connection\", \"keep-alive\")\n\treq.Header.Set(\"Referer\", SiteURL)\n\t\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\t\n\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"[%s] 搜索请求返回状态码: %d\", p.Name(), resp.StatusCode)\n\t}\n\t\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\t\n\t// 7. 提取搜索结果\n\tvar results []model.SearchResult\n\t\n\t// 查找种子列表表格\n\ttable := doc.Find(\"table.torrent-list tbody\")\n\tif table.Length() == 0 {\n\t\treturn []model.SearchResult{}, nil // 没有搜索结果\n\t}\n\t\n\t// 8. 解析每个搜索结果行\n\ttable.Find(\"tr\").Each(func(i int, s *goquery.Selection) {\n\t\tresult := p.parseSearchRow(s)\n\t\tif result.UniqueID != \"\" {\n\t\t\tresults = append(results, result)\n\t\t}\n\t})","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/nyaa/nyaa.go#L115-L151","documentation":"nyaa's searchImpl fails while goquery parses the (supposedly HTML) response body into a document. This indicates the response body is not the expected search-results HTML — parsing itself rarely fails on well-formed responses, so the usual cause is an empty, truncated, or compressed body (e.g. gzip/brotli not decompressed because Accept-Encoding was set manually without handling it).","triggerScenarios":"goquery.NewDocumentFromReader(resp.Body) returns an error — the reader yields malformed/undecodable content: the site returned a charset goquery can't detect, the body is compressed but the client didn't send Accept-Encoding so no auto-decompression happened, or the body was already consumed/truncated.","commonSituations":"Manually set headers (User-Agent etc.) on a default client plus explicit Accept-Encoding: gzip without decompression; site returns a binary challenge page; TLS interception corrupts the stream; empty body from an interrupted connection.","solutions":["Don't set Accept-Encoding manually — let net/http's transparent gzip handling work, or decompress explicitly with gzip.NewReader.","Dump the first bytes of resp.Body (via io.LimitReader + TeeReader) to see what was actually returned.","Check the Content-Type/Content-Encoding response headers before parsing.","Handle charset explicitly with golang.org/x/net/html/charset if the page is non-UTF-8."],"exampleFix":"// before\nreq.Header.Set(\"Accept-Encoding\", \"gzip, deflate\")\ndoc, err := goquery.NewDocumentFromReader(resp.Body)\n// after\n// omit manual Accept-Encoding; net/http decompresses gzip transparently\ndoc, err := goquery.NewDocumentFromReader(resp.Body)","handlingStrategy":"validation","validationCode":"ct := resp.Header.Get(\"Content-Type\")\nif !strings.Contains(ct, \"text/html\") {\n    return fmt.Errorf(\"expected HTML, got %s\", ct)\n}","typeGuard":"null","tryCatchPattern":"doc, err := goquery.NewDocumentFromReader(resp.Body)\nif err != nil {\n    // log Content-Type/Content-Encoding and a body prefix, then fail fast\n    return nil, fmt.Errorf(\"parse failed (ct=%s): %w\", resp.Header.Get(\"Content-Type\"), err)\n}","preventionTips":["Never set Accept-Encoding manually — let net/http handle gzip transparently.","Check Content-Type before parsing; bail early on non-HTML bodies.","Guard against empty bodies before handing them to goquery.","Set a charset-aware reader (golang.org/x/net/html/charset) for non-UTF-8 pages."],"tags":["html-parsing","goquery","scraping","nyaa"],"backgroundTag":"invalid-json-response","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"}