{"record":{"id":"63d6657836130696","repo":"fish2018/pansou","slug":"api-key","errorCode":null,"errorMessage":"无法提取api_key","messagePattern":"无法提取api_key","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/weibo/weibo.go","lineNumber":1811,"sourceCode":"\tinfoResp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\tdefer infoResp.Body.Close()\n\t\n\tinfoBody, err := io.ReadAll(infoResp.Body)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\t\n\t// 响应是JSONP格式，提取JSON部分\n\tinfoText := string(infoBody)\n\t\n\t// 提取api_key: 正则 api_key=(.*)\"\n\tapiKeyRegex := regexp.MustCompile(`api_key=([^\"]+)`)\n\tapiKeyMatch := apiKeyRegex.FindStringSubmatch(infoText)\n\tif len(apiKeyMatch) < 2 {\n\t\treturn nil, \"\", fmt.Errorf(\"无法提取api_key\")\n\t}\n\tapiKey := apiKeyMatch[1]\n\t\n\t// 提取qrid: 正则 \"qrid\":\"(.*?)\"\n\tqridRegex := regexp.MustCompile(`\"qrid\":\"([^\"]+)\"`)\n\tqridMatch := qridRegex.FindStringSubmatch(infoText)\n\tif len(qridMatch) < 2 {\n\t\treturn nil, \"\", fmt.Errorf(\"无法提取qrid\")\n\t}\n\tqrid := qridMatch[1]\n\t\n\t// 第二步：使用api_key获取二维码图片\n\tqrImageURL := fmt.Sprintf(\"https://v2.qr.weibo.cn/inf/gen?api_key=%s\", apiKey)\n\t\n\tqrReq, err := http.NewRequest(\"GET\", qrImageURL, nil)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}","sourceCodeStart":1793,"sourceCodeEnd":1829,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/weibo/weibo.go#L1793-L1829","documentation":"Raised by generateQRCodeWithSig when the regex api_key=([^\"]+) fails to find an api_key value in the HTML/text body fetched from the Weibo QR info endpoint. The plugin scrapes api_key and qrid out of the response to build the QR generation URL; if the page doesn't contain the expected pattern, this error stops QR-code generation. It indicates the response body didn't match the scraped format.","triggerScenarios":"generateQRCodeWithSig (called by handleGetStatus and handleRefreshQRCode) fetches the info page and FindStringSubmatch returns fewer than 2 groups because the body contains no api_key=... sequence.","commonSituations":"Weibo changed the QR info page layout or moved api_key into a JSON/JS payload; the request returned an error page, captcha, or login wall instead of the expected content; rate limiting or geo-blocking returning an interstitial; empty response due to network issues.","solutions":["Log the raw infoText on failure to see what the endpoint actually returned.","Re-fetch — transient blocks/captchas often clear; add proper headers (User-Agent, Referer) so the endpoint serves the real page.","Check whether Weibo changed the page and update the api_key regex to match the new format (e.g. JSON key \"api_key\":\"...\").","Verify the info request itself succeeded (check HTTP status/body length before regex matching) and fail earlier with a clearer message if not."],"exampleFix":"// before\napiKeyMatch := apiKeyRegex.FindStringSubmatch(infoText)\nif len(apiKeyMatch) < 2 {\n    return nil, \"\", fmt.Errorf(\"无法提取api_key\")\n}\n// after: include a response snippet for diagnosis\napiKeyMatch := apiKeyRegex.FindStringSubmatch(infoText)\nif len(apiKeyMatch) < 2 {\n    snippet := infoText\n    if len(snippet) > 200 {\n        snippet = snippet[:200]\n    }\n    return nil, \"\", fmt.Errorf(\"无法提取api_key, 响应片段: %q\", snippet)\n}","handlingStrategy":"validation","validationCode":"// Go: validate the info page body looks scrapable before regex extraction\nif len(infoText) < 50 || strings.Contains(infoText, \"<title>403\") || strings.Contains(infoText, \"captcha\") {\n    return fmt.Errorf(\"info page unusable (len=%d), not attempting api_key extraction\", len(infoText))\n}","typeGuard":"func extractableAPIKey(infoText string) bool {\n    return regexp.MustCompile(`api_key=([^\"]+)`).MatchString(infoText)\n}","tryCatchPattern":"qr, _, err := plugin.GenerateQRCodeWithSig(...)\nif err != nil {\n    if strings.Contains(err.Error(), \"无法提取api_key\") {\n        // endpoint format changed or blocked; retry once, then surface for manual update\n        return retryOrFail(err)\n    }\n    return err\n}","preventionTips":["Send realistic User-Agent/Referer headers so the info endpoint serves the real page, not a block page.","Log a response snippet whenever regex extraction fails to detect format drift early.","Check HTTP status and body length before regex matching.","Keep the scraping regexes in one place with tests against a saved real response."],"tags":["weibo","qr-code","regex-scraping","unexpected-response"],"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"}