你可以用.decode('gdk', errors='ignore')或者.decode('gdk', errors='replace')来解码
Python
reqeusts抓取返回页面时,碰到页面乱码
requests的返回结果对象里有个apparent_encoding函数, apparent_encoding通过调用chardet.detect()来识别文本编码. 但是需要注意的是,这有些消耗计算资源.
#blog: xiaorui.cc
@property
def apparent_encoding(self):
"""使用chardet来计算编码"""
return chardet.detect(self.content)['encoding']
第三个问题,requests的text() 跟 content() 有什么区别?
requests在获取网络资源后,我们可以通过两种模式查看内容。 一个是r.text,另一个是r.content,那他们之间有什么区别呢?
分析requests的源代码发现,r.text返回的是处理过的Unicode型的数据,而使用r.content返回的是bytes型的原始数据。也就是说,r.content相对于r.text来说节省了计算资源,r.content是把内容bytes返回.
而r.text是decode成Unicode.
如果headers没有charset字符集的化,text()会调用chardet来计算字符集,这又是消耗cpu的事情.
通过看requests代码来分析text() content()的区别.
对于requests中文乱码解决方法有这么几种.
方法一:
由于content是HTTP相应的原始字节串,可以根据headers头部的charset把content decode为unicode,前提别是ISO-8859-1编码.
In [96]: r.encoding
Out[96]: 'gbk'
In [98]: print r.content.decode(r.encoding)[200:300]
="keywords" content="Python数据分析与挖掘实战,,机械工业出版社,9787111521235,,在线购买,折扣,打折"/>
另外有一种特别粗暴方式,就是直接根据chardet的结果来encode成utf-8格式
#http://xiaorui.ccIn [22]: r = requests.get('http://item.jd.com/1012551875.html')In [23]: print r.contentKeyboardInterruptIn [23]: r.apparent_encodingOut[23]: 'GB2312'In [24]: r.encodingOut[24]: 'gbk'In [25]: r.content.decode(r.encoding).encode('utf-8')---------------------------------------------------------------------------UnicodeDecodeError Traceback (most recent call last)in()
----> 1 r.content.decode(r.apparent_encoding).encode('utf-8')
UnicodeDecodeError: 'gb2312' codec can't decode bytes in position 49882-49883: illegal multibyte sequence
In [27]: r.content.decode(r.apparent_encoding,'replace').encode('utf-8')
如果在确定使用text,并已经得知该站的字符集编码时,可以使用 r.encoding = ‘xxx’ 模式, 当你指定编码后,requests在text时会根据你设定的字符集编码进行转换.
>>>import requests
>>>r=requests.get('https://up.xiaorui.cc')
>>>r.text
>>>r.encoding
'gbk'
>>>r.encoding='utf-8'
方法二:
根据我抓几十万的网站的经验,大多数网站还是很规范的,如果headers头部没有charset,那么就从html的meta中抽取.
In [78]: s
Out[78]: ' [^;\s]+)", flags=re.I)
In [80]: b.search(s).group(1)
Out[80]: 'gbk"'
python requests的utils.py里已经有个完善的从html中获取meta charset的函数. 说白了还是一对的正则表达式.
In [32]: requests.utils.get_encodings_from_content(r.content)
Out[32]: ['gbk']
文件: utils.py
def get_encodings_from_content(content):
charset_re = re.compile(r']', flags=re.I)
pragma_re = re.compile(r']', flags=re.I)
xml_re = re.compile(r'^<\?xml.*?encoding=["\']*(.+?)["\'>]')
return (charset_re.findall(content) +
pragma_re.findall(content) +
xml_re.findall(content))
最后,针对requests中文乱码的问题总结:
统一编码,要不都成utf-8, 要不就用unicode做中间码 !
国内的站点一般是utf-8、gbk、gb2312 , 当requests的encoding是这些字符集编码后,是可以直接decode成unicode.
但当你判断出encoding是 ISO-8859-1 时,可以结合re正则和chardet判断出他的真实编码. 可以把这逻辑封装补丁引入进来.
import requests
def monkey_patch():
prop = requests.models.Response.content
def content(self):
_content = prop.fget(self)
if self.encoding == 'ISO-8859-1':
encodings = requests.utils.get_encodings_from_content(_content)
if encodings:
self.encoding = encodings[0]
else:
self.encoding = self.apparent_encoding
_content = _content.decode(self.encoding, 'replace').encode('utf8', 'replace')
self._content = _content
return _content
requests.models.Response.content = property(content)
monkey_patch()
Python3.x解决了这编码问题,如果你还是python2.6 2.7,那么还需要用上面的方法解决中文乱码的问题.
END.