Python3.7使用urllib.request访问URL报404及UTF-8解码错误如何解决
问题解答
1. 可在浏览器、Perl请求正常访问的URL,urllib请求返回404的原因
雅虎财经服务端配置了反爬规则,会校验请求头的User-Agent字段。urllib默认携带的UA是Python-urllib/版本号这类特征明显的爬虫标识,会被服务端直接拦截返回404。Chrome浏览器和Perl的get请求默认会携带符合正常客户端规范的UA,因此不会被拦截。
解决方法是构造请求时手动添加浏览器UA,代码示例:
# 构造带UA的请求对象 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'} req = urllib.request.Request(url, headers=headers) # 用请求对象发起请求 junk = urllib.request.urlopen(req, timeout=4).read()
2. 根域名请求无404但出现字节转字符串错误的原因
报错提示里的0x8b是gzip压缩格式的固定起始字节,服务端为了降低传输体积,返回了gzip压缩后的二进制内容,你直接把压缩后的内容按UTF-8解码自然会触发错误。根域名的反爬校验规则比子路径宽松,所以没有直接返回404,但默认开启了压缩传输。
3. 打印可读字节字符串junk的方法
- 如果需要查看原始二进制的十六进制形式,直接调用
print(junk.hex())即可输出标准十六进制字符串 - 如果需要查看实际的网页文本内容,先判断响应头的压缩标识,解压后再转字符串即可,代码示例:
import gzip resp = urllib.request.urlopen(req, timeout=4) # 判断是否为gzip压缩内容 if resp.getheader('Content-Encoding') == 'gzip': junk = gzip.decompress(resp.read()) else: junk = resp.read() # 此时再转字符串就不会报错 page = junk.decode('utf-8')
4. 网页编码说明
雅虎财经的网页当前依然使用UTF-8编码,你遇到的解码错误不是编码格式变更导致的,是响应内容被gzip压缩导致的。如果不确定站点编码,可以从响应头的Content-Type字段提取指定的charset参数,代码示例:
content_type = resp.getheader('Content-Type', '') charset = 'utf-8' if 'charset=' in content_type: charset = content_type.split('charset=')[1].split(';')[0].strip() page = junk.decode(charset)
内容的提问来源于stack exchange,提问作者user1067305
相关产品推荐
相关产品推荐

