
当使用 requests 获取含西里尔字符(如俄文)的网页时,若响应头未正确声明编码,requests 默认可能误判为 iso-8859-1 或 utf-8,导致乱码;此时应依据网页实际编码(如 windows-1251)显式解码 response.content。
在爬取历史水利数据等老旧网站(如 http://www.cawater-info.net/karadarya/1991/veg1991.htm)时,常见问题并非响应本身是 UTF-8,而是服务端未设置正确的 Content-Type 头,或明确声明为 charset=iso-8859-1,但实际内容以 Windows-1251(即 cp1251)编码存储——该编码广泛用于前苏联国家的俄语网页,能完整表示西里尔字母,而 ISO-8859-1 完全不支持这些字符。
requests.get() 会依据 HTTP 响应头、HTML 标签或默认启发式规则推断 response.encoding,但对这类无规范声明的老站往往失败(例如返回 'ISO-8859-1'),直接访问 response.text 就会产生乱码。
✅ 正确做法是:跳过自动解码,直接操作原始字节 response.content,并用真实编码显式解码:
import requests
url = "http://www.cawater-info.net/karadarya/1991/veg1991.htm"
response = requests.get(url)
# ❌ 错误:依赖自动推断的 encoding(通常是 ISO-8859-1,导致乱码)
# print(response.text[:100])
# ✅ 正确:用 cp1251(Windows-1251)解码原始字节
decoded_text = response.content.decode("cp1251")
print(decoded_text[:100])
# 输出:Оперативные данные по водозаборам бассейна реки Карадарья на период вегетации 199 ? 注意事项:
- 不要对 response.text 再次 .encode()(如 text.encode('utf-8')),这属于“错误解码后的二次编码”,毫无意义且易引发异常;
- cp1251 与 windows-1251 等价,Python 的 codecs 模块均支持;
- 若不确定编码,可先用 chardet.detect(response.content) 初步探测(但对短文本或无 BOM 的 cp1251 文件准确率有限,建议结合网页来源语言经验判断);
- 对于需要后续解析 HTML 的场景,可将解码后字符串传给 BeautifulSoup(..., from_encoding="cp1251"),或直接传入 response.content 并指定 features="html.parser" + from_encoding 参数,避免双重解码。
总之,面对老旧俄语网页,放弃 response.text,拥抱 response.content.decode("cp1251"),是解决西里尔字符显示异常最直接、可靠的方式。










