playwright抓取中文网页乱码主因是浏览器编码参数未设、响应解码策略不当或缺失中文字体;需分别通过launch传参(如--lang=zh-cn)、手动decode response.body()、安装wqy-zenhei等字体解决。

Playwright 启动浏览器时没指定 UTF-8 编码
Playwright 默认启动 Chromium/Firefox 时不会强制设置页面编码,而某些中文网页(尤其是没有 <meta charset="utf-8"> 或声明不规范的)会被浏览器按 ISO-8859-1 或 GBK 解析,导致 page.content() 或 page.inner_text() 返回乱码。
解决办法是在启动浏览器前,通过 launch 的 args 显式传入编码参数:
- Chromium/Edge:加
--lang=zh-CN和--disable-gpu(后者有时能避免渲染层编码 fallback) - Firefox:需配合
firefox_user_prefs设置intl.charset.default为"UTF-8"
示例(Chromium):
from playwright.sync_api import sync_playwright
<p>with sync_playwright() as p:
browser = p.chromium.launch(
args=["--lang=zh-CN", "--disable-gpu"]
)
page = browser.new_page()
page.goto("<a href="https://www.php.cn/link/0de008cd5a2b159fef2832f0d0a4e7ef">https://www.php.cn/link/0de008cd5a2b159fef2832f0d0a4e7ef</a>")
print(page.content()[:200]) # 此时更大概率是正常 UTF-8 字符
</p>
response.text() 返回乱码但 response.body() 是对的
这是最常被忽略的一点:Playwright 的 response.text() 会尝试根据响应头 Content-Type 中的 charset 自动解码,但很多中文站点响应头缺失或写错(比如写成 charset=gbk 却实际发 UTF-8),导致解码失败;而 response.body() 是原始字节,可手动 decode。
安全做法是绕过 text(),直接处理 body:
- 用
response.body()获取bytes - 先尝试用
response.headers.get("content-type", "")查看是否有charset=声明 - 若无或不可信,直接
body.decode("utf-8", errors="ignore")——errors="ignore"比replace更适合抓取场景,避免把半个汉字变成
示例:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
response = page.wait_for_response(lambda r: "article" in r.url)
body = response.body()
try:
text = body.decode("utf-8")
except UnicodeDecodeError:
text = body.decode("gbk", errors="ignore") # 备用 GBK 解码
page.inner_html() / inner_text() 中文显示为方块或问号
这通常不是 Python 层编码问题,而是浏览器渲染层缺少中文字体。Playwright 启动的无头浏览器默认不加载系统字体(尤其 Docker 容器或 CI 环境),导致即使 HTML 是 UTF-8,也无法正确渲染中文,inner_text() 可能返回空字符串或异常字符。
验证方式:用 page.screenshot(path="debug.png") 看截图里文字是否正常显示。
- Linux 容器中:安装
fonts-wqy-zenhei或fonts-noto-cjk(Debian/Ubuntu) - Dockerfile 示例:
RUN apt-get update && apt-get install -y fonts-wqy-zenhei - macOS/Windows 本地运行一般无此问题,但 CI 环境务必检查
requests + Playwright 混用时编码不一致
有些同学会用 requests 先请求 HTML,再用 Playwright 加载 data:text/html, 伪 URL 渲染,这时容易出问题:如果 requests.get().text 已被错误解码(比如响应头说 gbk 但实际是 UTF-8),再喂给 Playwright,页面源码就已损坏。
更稳妥的做法是只用 Playwright 加载真实 URL,或确保 requests 层拿到的是原始 bytes:
- 用
r = requests.get(url); r.content(不是r.text) - 再通过
page.goto(f"data:text/html;charset=utf-8,{r.content.decode('utf-8')}"注入,注意 URL 编码 - 或者直接用
page.set_content(r.content.decode("utf-8")),更简洁
关键点:所有中间环节,只要涉及字符串转换,必须明确来源编码,别依赖 requests 的自动猜测。
Playwright 抓中文网页的乱码,八成不是 Python 字符串处理的问题,而是浏览器启动参数、响应解码策略、字体环境这三个环节中某一个没对齐。最容易被跳过的其实是字体——截图一看是方块,就该立刻去查容器有没有装中文字体包。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










