Python 网络爬虫 006 (编程) 解决下载(或叫:爬取)到的网页乱码问题
解决下载(或叫:爬取)到的网页乱码问题
使用的系统:Windows 10 64位
Python 语言版本:Python 2.7.10 V
使用的编程 Python 的集成开发环境:PyCharm 2016 04
我使用的 urllib 的版本:urllib2
注意: 我没这里使用的是 Python2 ,而不是Python3
上一节,我介绍了如何下载网页。这样节我们来讲:如果我们下载一个带有中文的网站,或者日文的网站,终止就是不全是英文的网站,解决乱码问题。
一 . 解释乱码原因
Q: 为什么会出现乱码问题?
A: 编码方式不匹配导致的。
Q: 请具体说明一下?
A: 好的。
我先将上一节 编写的download()
函数的代码贴出来:
import urllib2
def download(url, user_agent='wswp', num_retries=2):
print 'Downloading: ', url
headers = {'User-agent' : user_agent}
request = urllib2.Request(url, headers=headers)
try:
html = urllib2.urlopen(request).read()
except urllib2.URLError as e:
print 'Download error', e.reason
html = None
if num_retries > 0:
if num_retries > 0:
if hasattr(e, 'code') and 500 <= e.code < 600:
# recursively retry 5xx HTTP errors
return download(url, user_agent, num_retries-1)
return html
在 download()
函数 里面,我们使用 html = urllib2.urlopen(request).read()
这句代码得到网页的源代码(str数据)。那么得到的源代码是使用什么编码方式编码的str字符串呢?是使用网页源代码中 charset
属性设定的编码方式编码的str字符串。
比如:我们就来爬取本博客的源代码。我们可以在浏览器上查看到 本网页的编码方式是 utf-8
。所以,当你执行:html = download('xxx')
命令后,html
里面存储的就是一个以utf-8编码方式编码的字符串。
接着,我们就使用 print html
命令将其打印到终端上。PyCharm软件上有两个终端,一个是PyCharm软件自带的终端窗口:Run窗口;另一个就是Terminal窗口,Terminal窗口不是PyCharm软件自带的,它就是 Windows系统的DOS窗口。(如果是Linux系统,这个Terminal窗口就是 Console窗口)。
在 Run 窗口 :
打开 Setting 。
选择 Editor -> Code Style -> File Encodings ,将 Project Encoding 项设置为:UTF-8。
这样,我Run 窗口里面打印的内容都会按照UTF-8 编码的方式进行编码,然后显示在Run窗口里。
我们的代码中的 print html
这句话可以正常的将 html
字符串里面的内容正常的打印到 Run 窗口里,不会有乱码的问题。
在 Terminal 窗口 :
假设,我们现在在 Terminal窗口里使用命令 运行这个 Python脚本。那么 print html
这段代码,会在Terminal窗口里面打印html
这个被utf-8编码方式编码的str字符串里面的内容。如果Terminal窗口显示字符串的编码方式也是 utf-8 的话,那么就不会有乱码的情况发生。
但是,你要知道:我们安装 Windows 系统的时候,设置的是 简体中文(默认),所以DOS窗口(命令提示符窗口)里显示的内容是被使用 gb2312 编码方式进行编码的。所以如果我们要显示 UTF-8 字符就会乱码。
在DOS窗口(或者 PyCharm软件中的Terminal窗口)中执行下面的命令来查看现在Windows系统使用的编码方式:
chcp
输出:(936 就是 gb2312编码的编号。)
活动代码页: 936
你可以到这个网站里进行查表。
Windows系统使用的是 ANSI编码方式,ANSI 不是一个编码,它是一个总称。如果你在安装Windows系统的时候,选择 简体中文(默认),那么 ANSI 在你的电脑里指的就是gb2321编码。Windows系统中所有的文件都是会被 gb2321 编码方式进行编码,所以,你在Windows上新建的
txt
文件都是gb2321编码文件。
那么这个时候如果我有一个 其他编码的文件,比如UTF-8文件,你要是在 DOS窗口中使用type filename.txt
命令打开它,你所看到的就是一堆乱码。
那么这个时候我们怎么办?怎样在 Terminal窗口 中显示正确的 html
字符串里面正确的内容呢?我们只需要改写 print html
这句代码就可以,将其修改为:print html.decode('utf-8').encode('GB18030')
。
我来解释一下这句代码:代码中的 .decode('utf-8')
的意思是:将 html
字符串(str)通过 utf-8
编码方式解码为Unicode字节(Bytes);接着 .encode('GB18030')
的意思是:将 解码得到的 Unicode字节(Bytes) 使用 GB18030
编码方式 再编码成 Str字符串 (str)。
通过这样的转换,在 Terminal窗口中,就可以正常的被 gb2312编码方式正确的解析,并显示出来。(但是现在的代码,在 Run窗口上运行,就会是乱码了。你应该知道为什么。我不讲了。)
Q: 为什么要使用
GB18030
编码方式,不是要使用gb2312
吗?
A: gb2312、GBK、GB18030 这三个编码方式其实可以看做是等价的关系。但是它们里面的编码的汉字数量不用,从少到多排序为:gb2312 < GBK < GB18030。有的网页虽然它的源代码中的charset
属性写的是gb2312
或者,GBK ,我们还是使用 GB18030编码最保险,使用其他的两个可能不会成功。
总结:
我们使用的是 Windows 系统上的 PyCharm 软件 做为我们开发的继承开发环境。
所谓:工欲善其事,必先利其器。PyCharm 软件上可以运行程序的有两个窗口:Run窗口 和 Terminal窗口。
我们应该统一 Run窗口 和 Terminal窗口 的编码方式,既然设置不了 Terminal 窗口的编码方式,那我们以后让 Run窗口 和 Terminal窗口 的编码方式都统一为 GBK 编码。这样,我们的程序就可以在这两个窗口里运用出同样的结果。(以后都使用 print html.decode('网页源代码的charset属性').encode('GB18030')
这样的代码打印信息。)
将 Pycharm软件的 Project Encoding 项设置为:GBK 即可统一Run窗口 和 Terminal窗口的编码方式。
二 . 扩展:如何使用程序获取网页的编码方式
获取网页的编码方式,即网页源代码中 charset
属性的值:
使用 Python 第三方库:chardet。
下载:(在DOS窗口中执行下面的命令)
C:\Python27\Scritp\pip.exe install charset
使用:
html = download('http://blog.csdn.net/github_35160620/article/details/52203682')
import chardet
charset = chardet.detect(html)['encoding']
print charset
运行输出:
utf-8
三 . 练习
题目:爬取目标网站:http://www.dytt8.net/
分析:目标网站的源代码中,charset
属性值为:gb2312
所以,爬虫代码是:
html = download('http://www.dytt8.net/')
print html
其中 print html
这段代码也可以写成:print html.decode('GBK').encode('GB18030')
运行:现在,不管是 Run窗口,还是Terminal窗口,还是Windows 的 DOS窗口,显示都是正常的,没有乱码。
现在,我已经知道了为什么会出现乱码,也知道了如何解决乱码问题,现在我们就可以修改 download()
函数,将其变成一个永远都不会出现乱码问题的函数。
四 . 最终的 download()
函数的程序:
#-*- coding:utf-8 -*-
import urllib2
import chardet
def download(url, user_agent='wswp', num_retries=2):
print 'Downloading: ', url
headers = {'User-agent' : user_agent}
request = urllib2.Request(url, headers=headers)
try:
html = urllib2.urlopen(request).read()
charset = chardet.detect(html)['encoding']
if charset == 'GB2312' or charset == 'gb2312':
html = html.decode('GBK').encode('GB18030')
else:
html = html.decode(charset).encode('GB18030')
except urllib2.URLError as e:
print 'Download error', e.reason
html = None
if num_retries > 0:
if num_retries > 0:
if hasattr(e, 'code') and 500 <= e.code < 600:
# recursively retry 5xx HTTP errors
return download(url, user_agent, num_retries-1)
return html
这样,对于任何目标网页,我需要执行下面的代码,就可以在输出窗口中打印出没有乱码的目标网页源代码。
html = download('网页的网站')
print html
搞定
对了,我在说说这个 #-*- coding:utf-8 -*-
这段注释的用处:
如果你的.py 文件中有中文注释,会在非英文的注释,你就必须在Python脚本 的最前面加上这句注释。否则程序运行时会报错:
SyntaxError: Non-ASCII character '\xe9' in file filename.py on line 6, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
总结:
这样,我们在的download()
函数就完美了。
这个 download()
现在是一个灵活的下载程序,该函数能够捕获异常,并且可以自动尝试重新下载,并且我们设置了自定义的用户代理(user_agent),并且还解决了中文或其他非英文语言的乱码问题。
下一节,我介绍 下载一个站点里所有网页的方法1 — 使用网站地图 来下载一个站点里所有包含的网页源代码。
Python 网络爬虫 006 (编程) 解决下载(或叫:爬取)到的网页乱码问题的更多相关文章
- Python 网络爬虫 009 (编程) 通过正则表达式来获取一个网页中的所有的URL链接,并下载这些URL链接的源代码
通过 正则表达式 来获取一个网页中的所有的 URL链接,并下载这些 URL链接 的源代码 使用的系统:Windows 10 64位 Python 语言版本:Python 2.7.10 V 使用的编程 ...
- Python 网络爬虫 005 (编程) 如何编写一个可以 下载(或叫:爬取)一个网页 的网络爬虫
如何编写一个可以 下载(或叫:爬取)一个网页 的网络爬虫 使用的系统:Windows 10 64位 Python 语言版本:Python 2.7.10 V 使用的编程 Python 的集成开发环境:P ...
- Python 网络爬虫 008 (编程) 通过ID索引号遍历目标网页里链接的所有网页
通过 ID索引号 遍历目标网页里链接的所有网页 使用的系统:Windows 10 64位 Python 语言版本:Python 2.7.10 V 使用的编程 Python 的集成开发环境:PyChar ...
- Python 网络爬虫 007 (编程) 通过网站地图爬取目标站点的所有网页
通过网站地图爬取目标站点的所有网页 使用的系统:Windows 10 64位 Python 语言版本:Python 2.7.10 V 使用的编程 Python 的集成开发环境:PyCharm 2016 ...
- Python 网络爬虫 004 (编程) 如何编写一个网络爬虫,来下载(或叫:爬取)一个站点里的所有网页
爬取目标站点里所有的网页 使用的系统:Windows 10 64位 Python语言版本:Python 3.5.0 V 使用的编程Python的集成开发环境:PyCharm 2016 04 一 . 首 ...
- Python网络爬虫实战(五)批量下载B站收藏夹视频
我们除了爬取文本信息,有的时候还需要爬媒体信息,比如视频图片音乐等.就拿B站来说,我的收藏夹内的视频可能随时会失效,所以把它们下载到本地是非常保险的一件事. 对于这种大量列表型的数据,可以猜测B站收藏 ...
- [Python3网络爬虫开发实战] 7-动态渲染页面爬取
在前一章中,我们了解了Ajax的分析和抓取方式,这其实也是JavaScript动态渲染的页面的一种情形,通过直接分析Ajax,我们仍然可以借助requests或urllib来实现数据爬取. 不过Jav ...
- python网络爬虫之使用scrapy下载文件
前面介绍了ImagesPipeline用于下载图片,Scrapy还提供了FilesPipeline用与文件下载.和之前的ImagesPipeline一样,FilesPipeline使用时只需要通过it ...
- 《精通Python网络爬虫》|百度网盘免费下载|Python爬虫实战
<精通Python网络爬虫>|百度网盘免费下载|Python爬虫实战 提取码:7wr5 内容简介 为什么写这本书 网络爬虫其实很早就出现了,最开始网络爬虫主要应用在各种搜索引擎中.在搜索引 ...
随机推荐
- mongodb数据文件结构——record是内嵌BSON的双向链表,多个record或索引组成extent
数据文件结构 Extent 在每一个数据文件内,MongoDB把所存储的BSON文档的数据和B树索引组织到逻辑容器“Extent”里面.如下图所示(my-db.1和my-db.2 是数据库的两个数据文 ...
- js比较函数
//1.//bySort函数接受一个首要比较字符串和一个可选的次要比较函数做为参数//并返回一个可以用来包含该成员的对象数组进行排序的比较函数//当o[firstName] 和 p[firstName ...
- html 常用代码块
解决外边框不计入div尺寸的代码-moz-box-sizing: border-box;box-sizing: border-box;-webkit-box-sizing: border-box; 手 ...
- 排列(加了点小set就过了,哈哈哈)
Ray又对数字的列产生了兴趣: 现有四张卡片,用这四张卡片能排列出很多不同的4位数,要求按从小到大的顺序输出这些4位数. 输入描述: 1 2 3 4 1 1 2 3 0 1 2 3 0 0 0 0输出 ...
- js 科学计数转数字或字符串
- Linux之时间、地点、人物、事件、情节
时间 date 显示当前时间 time cmd 显示 cmd的运行时间 地点 locate 根据文件名,迅速找到文件.基于系统构建的索引 find 根据各种规则找到文件,更强大,但比较慢 wherei ...
- python3 之logging模块
logging.getLogger(name=None)Return a logger with the specified name or, if name is None, return a lo ...
- GPIO编程2:使用GPIO监听中断完整程序
一个完整的使用GPIO捕捉中断的程序: #include<stdlib.h> #include<stdio.h> #include<string.h> #inclu ...
- 一般处理程序+html 的CRUD
using Console_Core.BLL; using Console_Core.Common; using Console_Core.Model; using System; using Sys ...
- Spring Boot自定义配置与加载
Spring Boot自定义配置与加载 application.properties主要用来配置数据库连接.日志相关配置等.除了这些配置内容之外,还可以自定义一些配置项,如: my.config.ms ...