{"record":{"id":"2f2b94cc9c9f53f9","repo":"NanmiCoder/MediaCrawler","slug":"response-text","errorCode":null,"errorMessage":"{response.text}","messagePattern":"\\{response\\.text\\}","errorType":"exception","errorClass":"ForbiddenError","httpStatus":403,"severity":"error","filePath":"media_platform/zhihu/client.py","lineNumber":109,"sourceCode":"            url: Request URL\n            **kwargs: Other request parameters such as headers, body, etc.\n\n        Returns:\n\n        \"\"\"\n        # Check if proxy is expired before each request\n        await self._refresh_proxy_if_expired()\n\n        # return response.text\n        return_response = kwargs.pop('return_response', False)\n\n        async with make_async_client(proxy=self.proxy) as client:\n            response = await client.request(method, url, timeout=self.timeout, **kwargs)\n\n        if response.status_code != 200:\n            utils.logger.error(f\"[ZhiHuClient.request] Requset Url: {url}, Request error: {response.text}\")\n            if response.status_code == 403:\n                raise ForbiddenError(response.text)\n            elif response.status_code == 404:  # Content without comments also returns 404\n                return {}\n\n            raise DataFetchError(response.text)\n\n        if return_response:\n            return response.text\n        try:\n            data: Dict = response.json()\n            if data.get(\"error\"):\n                utils.logger.error(f\"[ZhiHuClient.request] Request error: {data}\")\n                raise DataFetchError(data.get(\"error\", {}).get(\"message\"))\n            return data\n        except json.JSONDecodeError:\n            utils.logger.error(f\"[ZhiHuClient.request] Request error: {response.text}\")\n            raise DataFetchError(response.text)\n\n    async def get(self, uri: str, params=None, **kwargs) -> Union[Response, Dict, str]:","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/NanmiCoder/MediaCrawler/blob/d6f7c5bb906b6dac40ddf343ef9e26438a3de092/media_platform/zhihu/client.py#L91-L127","documentation":"ForbiddenError raised by ZhiHuClient.request when a signed request returns HTTP 403. For zhihu this means the signature (x-zse-96) was rejected or the session/IP is forbidden; the exception message carries the raw response body for diagnosis.","triggerScenarios":"Any zhihu API call where the signing algorithm version no longer matches the site (signature rejected with 403), the cookie is expired so the signature is computed over stale credentials, or the IP is blocked by zhihu risk control.","commonSituations":"Zhihu updates their signature algorithm and the local signer becomes outdated; long crawl with expired login; datacenter IP flagged by zhihu.","solutions":["Refresh zhihu cookies (re-login) first - cheapest fix - and retry.","If 403 persists with fresh cookies, update the zhihu signing implementation (x-zse-96 algorithm version) to match the current site build.","Enable/rotate proxies if the IP is the blocked factor.","Catch ForbiddenError at loop level to back off instead of immediate retries."],"exampleFix":"// before\ndata = await zhihu_client.request(\"GET\", url)\n// after\nfrom media_platform.zhihu.exception import ForbiddenError\ntry:\n    data = await zhihu_client.request(\"GET\", url)\nexcept ForbiddenError as e:\n    utils.logger.error(f\"zhihu 403: {e}\")\n    await asyncio.sleep(30)\n    raise","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"from media_platform.zhihu.exception import ForbiddenError\ntry:\n    data = await zhihu_client.request(\"GET\", url)\nexcept ForbiddenError as e:\n    utils.logger.error(f\"zhihu 403 body: {e}\")\n    await asyncio.sleep(60)\n    raise","preventionTips":["Refresh cookies at the first 403 - stale credentials invalidate signatures.","Track zhihu signature-algorithm updates (x-zse-96 version) and update the signer.","Rotate IPs when 403 persists across fresh cookies."],"tags":["zhihu","http","forbidden","signing"],"backgroundTag":null,"analyzedSha":"d6f7c5bb906b6dac40ddf343ef9e26438a3de092","analyzedAt":"2026-08-15T01:39:07.505Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}