从本篇开始,我们正式开始学习Python 网页爬虫的相关知识。
通过上面两篇基础教程的学习,相信大部分的小伙伴都了解了Python 和HTML 的相关开发技术,也可能有一小部分的同学因为刚学习新的知识,还没有完全明白,就迫不及待的点开了这篇文章。无论怎样,在正式学习网页爬虫的相关文章中,作者都会力求详细,对一些之前没有讲解过、讲解的不够细致的点再次复习,将Python 网页爬虫的学习坡度降到最低。
本篇使用Python 自带的 urllib 模块抓取简单的网页,在这过程中为读者提供一个较为详细的网页爬虫过程。
使用 urllib 爬取网页
urllib 是Python 中自带的一个用于网页信息获取的模块,这也就意味着你可以直接使用它来爬取网页信息,让我们看一下下面的这个小例子:
import urllib.request
response = urllib.request.urlopen('http://gitbook.cn/')
html = response.read()
print(html)
运行上述代码,我们可以得到的信息是:
b'<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, user-scalable=no"><title>GitChat</title><meta name="description" content="GitChat ....
Great!你已经成功的写出了第一个网页爬虫程序!让我们赶快看一下你写的代码每一行代表什么意思吧!
import urllib.request
import
是一个Python 关键字。Python 自带了很多的功能,但是如果一下子全部加载在程序里,那么就会大大增加时间,降低运行效率。因此,Python 将一部分的功能封装成一个个模块,只有当你真正需要时,自己导入,编译的时候才会帮你加载这部分的内容。这里我们导入的是urllib.request
模块。
response = urllib.request.urlopen('http://gitbook.cn/')
当我们在上面成功导入了urllib.request
模块后,我们就可以调用它包含的函数啦!urlopen()
就是我们加载的模块中的一个函数,它的作用是打开一个代表网页的URL,并返回一个类似文件
的对象。
html = response.read()
看到这里是不是很熟悉?没错!通过urlopen()
函数,变量response
成为了一个文件!在第二篇《Python 极速教程》中,我们读取一个文件的内容时,用的就是read()
函数!
print(html)
变量html
已经被赋值为了网页的内容,让我们直接打印它就行啦!怎么样?是不是很简单!
###“欺骗”服务器传输数据
趁着知识刚学完,让我们再写一个网页爬虫程序,爬取百度的首页吧!让我们开始Coding!
import urllib.request
response = urllib.request.urlopen('http://www.douban.com/')
html = response.read()
print(html)
这也太简单了吧!让我们直接运行一下看看我们日常使用的百度首页内容有哪些:
urllib.error.HTTPError: HTTP Error 502: Bad Gateway
啊哦,系统报错了!让我们仔细看看这个HTTP Error 502
是什么意思吧:
502 :错误网关,服务器作为网关或者代理,从上游服务器收到无效相应。
在讲解怎么解决该问题之前。我们需要理解这样一个概念:当我们访问一个网页的时候,我们使用的是浏览器软件。目前市面上有很多浏览器软件,例如Chrome、FireFox、IE等。不同浏览器之间,其展示网页的格式也有可能不相同。那么如何解决这种问题呢?
如下图所示,其实当我们访问网页的时候,我们传输的访问请求上,已经写入了浏览器的相关信息。
让我们想象这样一个情况:你是一家大型网站的CTO,你的网站本身流量就很大。因为你的网站结构合理、布局清晰,很多网页爬虫爱好者都爱爬取你的网站。你会不会很崩溃?
为了“干掉”一些新手(就像现在的我们),你索性在响应请求的时候,加入了请求是不是通过浏览器访问的判断:如果请求中存在浏览器的相关信息,就返回数据;如果请求只是光秃秃的请求URL,那就不“理睬”它。
听完了上面的假设,你是不是想到了为什么会有 502 错误了呢?没错,因为网站认为你没有用浏览器!那么有没有什么方法解决这个问题呢?当然有啦!俗话说:道高一尺,魔高一丈。虽然我们不是魔鬼,但是我们也可以踩着“魔鬼的步伐”,顺利的解决这个“难题”!
import urllib.request
req = urllib.request.Request('https://www.baidu.com/')
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36')
web = urllib.request.urlopen(req)
file = web.read()
print(file)
修改后的代码,多了两行,我们来解释一下这两行的代码
req = urllib.request.Request('https://www.baidu.com/')
我们使用了urllib.request.Request()
这个函数,除了URL ,该函数还有其他的参数,感兴趣的可以在这里查阅它的文档,我们可以简单的认为,这是一个URL请求的抽象
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36')
函数add_header()
用来“欺骗”服务器——我是通过浏览器访问网站的,请返回给我相关的数据。可以看到,函数里面相关字符串,是我们上面提到的浏览器标记数据。
爬取中文网站的正确姿势
是不是到现在,虽然完成了你的第二个网页爬虫的程序,还是感觉不对劲?亦或者是,当你兴致勃勃的翻了翻你爬取内容时候,一副生无可恋的样子:为什么没有中文字?为什么都是类似于“\xa8”这样的代码?
恭喜你已经具有了开发人员主动思考问题的的思维!没错,和英文不一样的是,中文的编码格式有很多,ASCII、GB2312、UTF-8、Unicode…如果我们不对网页信息进行正确的编码,那么最后显示的结果,也必将是乱码。
那么,如何知道网站的编码,爬取的时候如何对其进行重新编码呢?
首先,目前的大部分网页都会在HTML 代码中,写入网页的编码,我们可以方便的获取到相应的编码格式。
记得这篇文章说过的一句话吗?
urlopen()
就是我们加载的模块中的一个函数,它的作用是打开一个代表网页的URL,并返回一个类似文件
的对象
没错!我们可以直接对获取到到的网页信息,按照文件编码的方法对其进行正确的编码,其代码也就成为了下面这样:
import urllib.request
req = urllib.request.Request('https://www.baidu.com/')
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36')
web = urllib.request.urlopen(req)
file = web.read().decode("utf-8") #对网页信息进行编码
print(file)
让我们来运行一下修改后的程序:
......
<title>百度一下,你就知道</title>
......
果然,中文终于正常显示了!我们终于从什么都不懂的“爬虫小白”,成功进阶到“中英文网站全制霸”的“爬虫新手”了!
相关提醒
- 这篇文章使用的是Python 自带的urllib 模块。其实,不仅仅是urllib,Python 还有 urllib2 模块。但是在Python3 的版本中,这两个模块合并为一,很大程度上降低了开发的成本;
- 通过这篇文章,我们知道:有的服务器是拒绝脚本获取数据的,我们需要模拟浏览器,去“欺骗”服务器。这是一种常见,甚至是约定成俗的反爬虫方法,在接下来的网页爬虫技术中,我们默认都会加上这段代码。
- 虽然本篇文章解决了中文的编码问题,但是要注意的是:现实中,大型网页爬虫程序所要面对的编码问题,往往比这复杂的多得多得多,不是一个量级的。这篇文章仅仅是为读者提供一个解决的思路而已;
- 如果课后有时间,推荐阅读一下常见的HTTP响应状态码和中文编码问题等相关文章