社区,它的网页和 App 都有大量的数据,比如问题、回答、文章、用户信息等,使用 requests 可以模拟浏览器发送 HTTP 请求,从而获取这些数据。

核心挑战:知乎的登录机制
直接访问知乎的公共页面(如问题列表)是很容易的,但一旦你想访问登录后才能看到的内容(如你的关注者的动态、你的收藏夹、私信等),就会立刻遇到一个巨大的障碍:知乎的反爬虫机制和登录验证。
知乎现在主要使用两种登录方式:
- 扫码登录:这是最主流的方式,用户需要在手机 App 或网页上扫描二维码来确认登录。
- 账号密码登录:这种方式非常少见,且通常需要配合验证码,成功率极低。
对于 requests 模拟扫码登录是技术上最可行、最稳定的方式,直接破解密码或绕过验证码几乎是不可能的。
下面,我将分步讲解从简单到复杂的操作。

第一步:环境准备
确保你已经安装了 requests 库,如果没安装,打开终端或命令行工具运行:
pip install requests
第二步:获取公开数据(无需登录)
对于任何用户都能看到的数据,我们可以直接发送 GET 请求来获取。
示例:获取某个问题的标题和部分回答
我们可以使用 Chrome 浏览器的开发者工具(F12)来分析知乎的网络请求。

- 打开 Chrome 浏览器,访问一个知乎问题页面,如何用 Python 爬取知乎?
- 按 F12 打开“开发者工具”,切换到“网络”(Network)选项卡。
- 刷新页面,你会看到很多请求,我们关注那些返回 HTML 或 JSON 的请求,一个问题的 API 请求 URL 类似于:
https://www.zhihu.com/api/v4/questions/20798354?include=... - 复制这个 URL,我们就可以在 Python 中使用
requests来获取它。
Python 代码示例:
import requests
import json
# 目标问题的 URL
url = "https://www.zhihu.com/api/v4/questions/20798354"
# 设置请求头,模拟浏览器访问
# User-Agent 可以从你的浏览器开发者工具的 Network 请求中复制
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"Host": "www.zhihu.com"
}
try:
# 发送 GET 请求
response = requests.get(url, headers=headers)
# 检查请求是否成功 (状态码 200)
response.raise_for_status()
# 将 JSON 字符串解析为 Python 字典
data = response.json()
# 打印问题标题和回答总数
print(f"问题标题: {data['title']}")
print(f"回答总数: {data['answer_count']}")
# 获取前几个回答的片段
# 注意:获取回答列表需要另一个 API 请求
answers_url = f"https://www.zhihu.com/api/v4/questions/20798354/answers?include=content,voteup_count&limit=5"
answers_response = requests.get(answers_url, headers=headers)
answers_data = answers_response.json()
print("\n--- 前 5 个回答的片段 ---")
for answer in answers_data['data']:
# 为了简洁,只截取回答内容的前 50 个字符
content_snippet = answer['content'][:50] + "..."
print(f"赞同数: {answer['voteup_count']}, 内容: {content_snippet}")
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
代码解释:
headers:非常重要!它告诉服务器我们是一个什么样的客户端,如果不设置User-Agent,知乎很容易识别出这是一个爬虫程序,可能会拒绝你的请求。response.raise_for_status():如果请求失败(404 Not Found, 500 Server Error),这行代码会抛出异常。response.json():requests库非常贴心,它会自动将服务器返回的 JSON 格式数据解析成 Python 的字典和列表。
第三步:获取私有数据(需要登录)
这是最核心也是最困难的部分,我们需要先登录,然后才能访问那些需要身份验证的 API。
手动获取 cookies(简单但低效)
对于一些简单的需求,你可以先手动登录知乎,然后从浏览器中复制 cookies,在代码中使用。
操作步骤:
- 在 Chrome 浏览器中登录你的知乎账号。
- 打开开发者工具 (F12),切换到 "应用" (Application) 选项卡(旧版是 "资源" -> "Cookies")。
- 在左侧找到
https://www.zhihu.com->Cookies->__ac_nonce或z_c0等关键字段。 - 复制所有
Cookies的值,格式如name1=value1; name2=value2; ...。
Python 代码示例:
import requests
# 手动从浏览器复制的 cookies
# !!! 注意:这些 cookies 是会过期的,通常几个小时或一天后就会失效,需要重新获取 !!!
cookies_str = "_xsrf=...; z_c0=...; other_cookies=...;"
cookies_dict = {cookie.split('=')[0]: cookie.split('=')[1] for cookie in cookies_str.split('; ')}
# 访问一个需要登录才能看到的页面,例如你的个人主页
url = "https://www.zhihu.com/people/your-user-name" # 替换成你的用户名
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
"Host": "www.zhihu.com",
# 有些请求可能还需要 Referer
"Referer": "https://www.zhihu.com/"
}
try:
response = requests.get(url, headers=headers, cookies=cookies_dict)
response.raise_for_status()
# 检查页面内容是否包含你的用户名,以判断是否登录成功
if "你的用户名" in response.text:
print("登录成功!可以获取私有数据了。")
# 在这里可以继续请求其他需要登录的 API
else:
print("登录失败,可能 cookies 已过期。")
except requests.exceptions.RequestException as e:
print(f"请求失败: {e}")
缺点:
- Cookies 易失效:知乎会定期更新 cookies,这种方法需要频繁手动复制。
- 无法自动化:完全无法实现无人值守的自动化脚本。
模拟扫码登录(推荐,技术实现)
这是最稳定、最接近真实用户行为的方式,原理是:
- 用
requests访问知乎的登录页面,获取一个用于扫码的xsrftoken。 - 生成一个二维码 URL,并用
qrcode库将其展示出来。 - 模拟手机 App 扫描二维码的过程,向知乎的服务器轮询扫码状态。
- 用户在手机上确认登录后,服务器会返回登录成功的
cookies。 - 将获取到的
cookies保存下来,后续所有请求都带上它即可。
完整代码示例:
import requests
import time
import json
import qrcode
from io import BytesIO
# 1. 定义请求头和基础 URL
HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
'Host': 'www.zhihu.com',
'Referer': 'https://www.zhihu.com/signin'
}
BASE_URL = 'https://www.zhihu.com'
# 2. 获取 XSRF Token
def get_xsrf_token():
"""获取登录所需的 xsrf token"""
url = f'{BASE_URL}/api/v3/oauth/sign_in'
response = requests.get(url, headers=HEADERS)
# xsrf token 通常在 cookie 中
return response.cookies.get('_xsrf')
# 3. 生成二维码并展示
def generate_qrcode():
"""生成二维码并打印到控制台"""
xsrf = get_xsrf_token()
if not xsrf:
print("无法获取 XSRF token!")
return None
# 请求二维码
qr_url = f'{BASE_URL}/api/v3/oauth/sign_in/qrcode?source=com.zhihu.web&ref=www.zhihu.com&lang=zh'
params = {'client_id': 'c3cef7c66a1843f8b3a9e6a1e3160e20', 'grant_type': 'password'}
response = requests.get(qr_url, headers=HEADERS, params=params)
data = response.json()
# 二维码的 UUID
qr_uuid = data['qr_code']
print(f"二维码 UUID: {qr_uuid}")
# 生成二维码图片
qr_img = qrcode.make(qr_uuid)
buf = BytesIO()
qr_img.save(buf, format='PNG')
qr_img_bytes = buf.getvalue()
# 在控制台打印二维码(简单实现,实际项目中可以用 PIL 显示)
print("\n请使用知乎 App 扫描以下二维码:")
# 这是一个简化的打印方式,实际开发中建议使用 PIL 库的 Image.show() 来显示
# 这里我们只打印 UUID,用户可以手动去网页扫码
# 或者,你可以将二维码图片保存到本地
with open("qrcode.png", "wb") as f:
f.write(qr_img_bytes)
print("二维码已保存为 qrcode.png,请用手机知乎 App 扫描。")
return qr_uuid
# 4. 轮询扫码状态
def poll_qrcode_status(qr_uuid):
"""轮询二维码扫码状态,直到用户确认登录"""
check_url = f'{BASE_URL}/api/v3/oauth/sign_in/qrcode/scan_status'
params = {
'uuid': qr_uuid,
'source': 'com.zhihu.web',
'ref': 'www.zhihu.com',
'lang': 'zh'
}
print("等待扫码确认...")
while True:
time.sleep(2) # 每2秒检查一次
response = requests.get(check_url, headers=HEADERS, params=params)
data = response.json()
status = data.get('status')
print(f"当前扫码状态: {status}")
if status == 'scanned':
print("二维码已被扫描,请在手机上确认登录。")
elif status == 'confirmed':
print("登录成功!正在获取 cookies...")
# 登录成功后,cookies 会自动保存在 response.cookies 中
return response.cookies.get_dict()
elif status == 'expired' or status == 'failed':
print("二维码已过期或登录失败。")
return None
# 主函数
if __name__ == '__main__':
qr_uuid = generate_qrcode()
if qr_uuid:
# 将获取到的 cookies 保存到变量中
login_cookies = poll_qrcode_status(qr_uuid)
if login_cookies:
print("\n成功获取到 Cookies:")
print(login_cookies)
# --- 测试登录后的访问 ---
print("\n--- 测试访问个人主页 ---")
profile_url = "https://www.zhihu.com/api/v4/members/your-username?include=..." # 替换成你的用户名
profile_response = requests.get(profile_url, headers=HEADERS, cookies=login_cookies)
if profile_response.status_code == 200:
profile_data = profile_response.json()
print(f"你好,{profile_data['name']}!")
else:
print("访问个人主页失败,可能 cookies 无效或 URL 错误。")
代码解释:
get_xsrf_token():知乎为了防止 CSRF 攻击,在登录时需要验证一个_xsrftoken,这个 token 在登录页面的 cookie 中。generate_qrcode():向知乎请求一个二维码的 UUID,然后用qrcode库生成一个图片并保存,用户需要用手机 App 扫描这个二维码。poll_qrcode_status():这是关键,它会循环(轮询)地向知乎服务器询问二维码的状态,当状态变为confirmed时,说明用户已在手机上确认,服务器会在响应的cookies中返回登录凭证。login_cookies = poll_qrcode_status(qr_uuid):我们将成功获取到的cookies字典保存起来。- 后续使用:一旦你有了
login_cookies,之后所有需要登录的requests请求,都只需在cookies参数中传入这个字典即可,就像方法一那样。
第四步:进阶技巧与注意事项
-
Session 对象: 为了避免在每个请求中都重复传入
headers和cookies,可以使用requests.Session()对象,它会自动管理 cookies 和 headers。# 创建一个会话对象 session = requests.Session() session.headers.update(HEADERS) # 设置默认的 headers # 登录成功后,将 cookies 存入 session # session.cookies.update(login_cookies) # 之后的所有请求都直接使用 session 对象,它会自动带上 cookies response = session.get("https://www.zhihu.com/your-private-page") -
IP 封禁与代理: 如果你频繁地发送请求,知乎的 IP 封禁机制可能会将你的 IP 地址暂时屏蔽,解决方案是使用代理 IP,你可以在代码中为
requests请求设置proxies参数。proxies = { "http": "http://your_proxy_ip:port", "https": "https://your_proxy_ip:port", } response = requests.get(url, proxies=proxies) -
数据解析:
- JSON API:如上所示,知乎的很多 API 直接返回 JSON,这是最容易解析的。
- HTML 页面:对于一些没有提供 API 的页面,你需要获取 HTML 内容,然后用 BeautifulSoup4 或 lxml 库来解析 HTML,提取你需要的信息,找到特定的
div或span
from bs4 import BeautifulSoup html_content = response.text soup = BeautifulSoup(html_content, 'html.parser') # 找到所有 class 为 "ContentItem" 的 div answers = soup.find_all('div', class_='ContentItem') for answer in answers: # 在 answer 内部继续查找... author = answer.find('span', class_='UserLink').text print(f"作者: {author}") -
遵守
robots.txt: 一个有道德的爬虫应该遵守网站的robots.txt规则,你可以访问https://www.zhihu.com/robots.txt查看知乎对爬虫的约定。
| 目标 | 方法 | 难度 | 稳定性 | 备注 |
|---|---|---|---|---|
| 获取公开数据 | 直接 requests.get() + headers |
低 | 高 | 最基础的操作。 |
| 获取私有数据 | 手动复制 cookies |
低 | 极低 | 仅临时测试用,cookies 易失效。 |
| 获取私有数据 | 模拟扫码登录 | 高 | 高 | 推荐方案,技术实现最稳定,可自动化。 |
| 反反爬虫 | 使用 Session、代理、随机 User-Agent |
中 | 中 | 必要的进阶技巧,防止被封禁。 |
对于知乎这种反爬虫做得很好的网站,直接破解是行不通的。模拟用户行为(如扫码登录) 是目前最有效、最主流的思路,希望这份详细的指南能帮助你顺利上手!
