阅读提示
理解本文内容需要具备python基础知识和爬虫基础知识(HTML、JS)
爬虫基础可参考以往文章:
爬虫基础——HTTP基本原理
爬虫基础——网页基础
爬虫的基本原理
爬虫基础——会话和Cookie
爬虫基础——代理的基本原理
urllib库的作用
在爬虫的基本原理中,我们已经讲过,爬虫的第一个步骤是获取网页,urllib库就是用来实现这个功能:向服务器发送请求,得到服务器响应,获取网页的内容。
Python的强大就在于提供了功能齐全的类库,来帮助我们完成这个请求,通过调用urllib库,我们不需要了解请求的数据结构,HTTP、TCP、IP层的网络传输通信,以及服务器应答原理等等。
我们只需要关心以下三点,然后通过几行调用urllib库的代码,就能够获得我们想要的网页内容。
- 请求的URL是什么
- 传递的参数是什么
- 如何设置可选的请求头
urllib库的构成
在python2中,曾经有urllib和urllib2两个库来实现请求的发送,但目前通用的python3版本中,两个库的功能已经合并成一个库,统一为urllib,它是python内置函数,不需要额外安装即可使用。
urllib的四个模块:
![466f094410cc7dc04832a0770890948c.png](https://img-blog.csdnimg.cn/img_convert/466f094410cc7dc04832a0770890948c.png)
【1】requset:HTTP请求模块,可以用来模拟发送请求,只需要传入URL及额外参数,就可以模拟浏览器访问网页的过程。
【2】error:异常处理模块,检测请求是否报错,捕捉异常错误,进行重试或其他操作,保证程序不会终止。
【3】parse:工具模块,提供许多URL处理方法,如拆分、解析、合并等。
【4】robotparser:识别网站的robots.txt文件,判断哪些网站可以爬,哪些网站不可以爬,使用频率较少。
发送请求
1.urlopen( )
urlopen是request模块中的方法,用于抓取网页。
官方文档:(https://docs.python.org/3/library/urllib.request.html)
下面以代码举例,我们抓取百度的网页。
代码示例:
import
![df112e73ec97865071959a9724f36c71.png](https://img-blog.csdnimg.cn/img_convert/df112e73ec97865071959a9724f36c71.png)
返回的结果比较多,随便截取其中一部分,可以看出是百度的网页HTML源代码。
![a071661dcd7791b1cd65ac37973996e1.png](https://img-blog.csdnimg.cn/img_convert/a071661dcd7791b1cd65ac37973996e1.png)
我们只用几行代码,就完成了百度的抓取,并打印了网页的源代码,接下来,我们看一看我们获得的响应内容response到底是什么?利用type()方法来输出响应的类型。
import
![9283ff62c54fa7b386e0ea291748abd0.png](https://img-blog.csdnimg.cn/img_convert/9283ff62c54fa7b386e0ea291748abd0.png)
输出结果如下:
![35b21f429166bee64417ba2cd1b90fdf.png](https://img-blog.csdnimg.cn/img_convert/35b21f429166bee64417ba2cd1b90fdf.png)
它是一个HTTPResponse类型的对象
包含方法:read()、readinto()、getheader()、getheaders()、fileno()等
包含属性:msg、version、status、reason、debuglevel、closed等属性。
通过调用以上的方法和属性,就能返回我们所需的信息。
比如一开始我们打印获取网页内容时,就用到了read()方法。
调用status属性则可以得到返回结果的状态码,200代表强求成功,404代表网页未找到等。
再看一个代码示例加深理解:
import
![0779f57fef2303ca25425c30b3fad8de.png](https://img-blog.csdnimg.cn/img_convert/0779f57fef2303ca25425c30b3fad8de.png)
返回结果:
![31f2dd3816ce5956bf059484ca4b9f3b.png](https://img-blog.csdnimg.cn/img_convert/31f2dd3816ce5956bf059484ca4b9f3b.png)
在打印的三行代码中
第一行输出了响应的状态码(200代表正常)
第二行输出了响应的头信息
第三行通过调用getheader()方法并传递参数Server,获取了第二行响应头信息中的Server对应的值BWS/1.1。
参数
利用基本的urlopen()方法可以完成最基本的简单网页GET方法抓取。
如果想达成更复杂一些的任务,需要给链接传递一些参数,该如何实现?
urlopen()的函数原型如下:
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
除了第一个参数传递URL之外,我们还可以传递其参数,比如data(附加数据)、timeout(超时时间)等。
data参数
data用来指明发往服务器请求中的额外的参数信息,data默认是None,此时以GET方式发送请求;当用户给出data参数的时候,改为POST方式发送请求。
data参数是可选的,如果要添加该参数,需要使用bytes()方法将参数转化为二进制数据。
还是通过代码示例理解:
import
![4d3171ecda259936856fefc79c47895e.png](https://img-blog.csdnimg.cn/img_convert/4d3171ecda259936856fefc79c47895e.png)
首页这里请求的站点是http://httpbin.org,它是一个HTTP请求测试网站,记住它后面举例会经常用到它。
这次我们要使用post方式请求,而不是get,因为post是需要携带表单信息的(类似登陆的用户名和密码)所以我们要在urlopen函数中传递data参数。
前面讲了data参数必须是bytes型。
bytes()这个方法第一个参数需要str(字符串类型),这里就需要用到urllib库的parse模块里的urlencode()方法来将参数字典转化为字符串。第二个参数是指定编码格式,这里指定为utf-8。
运行结果如下:
![4bbb34fe9a7972040e67f11888f351c5.png](https://img-blog.csdnimg.cn/img_convert/4bbb34fe9a7972040e67f11888f351c5.png)
可以看到,我们传递的参数data中的字典键值对"word":"hello"出现在了form字段中,这表明了表单提交的方式,以POST方式传输数据。
timeout参数
timeout参数用于设置超时时间,单位为秒,意思是如果请求时间超过了设置的时间,还没有得到响应,就会抛出异常,在实际爬虫中,我们要对许多URL发起请求,中途肯定会出现爬取异常的URL,短时间无法获得响应,我们需要识别出这种异常,就需要用到timeout参数。
如果不指定timeout参数,会使用全局默认时间。它支持HTTP、HTTPS、FTP请求。
通过代码示例理解:
import
![1158d4910f34d31871a499e59a6e8c37.png](https://img-blog.csdnimg.cn/img_convert/1158d4910f34d31871a499e59a6e8c37.png)
这里我们把timeout参数设成0.01秒,网页反应时间是没这么快的,所以一定会报错,我们来看一下报错的信息:
![139d3597a691cc2654fad589dafb8ac8.png](https://img-blog.csdnimg.cn/img_convert/139d3597a691cc2654fad589dafb8ac8.png)
直接看结尾红框部分,显示异常属于urllib.error模块,错误原因是超时。
在实际爬虫中,我们可以用过设置这个超时时间来控制一个网页在长时间未响应时,就跳过它的抓取。这可以利用try except 语句来实现。
代码示例:
import
![30a8d25ce593edd3a40f31bf18b4870c.png](https://img-blog.csdnimg.cn/img_convert/30a8d25ce593edd3a40f31bf18b4870c.png)
在代码中加入try except 语句后,如果响应超时,便会跳过抓取,我们捕获了URLError异常后,接着判断异常是socket.timeout类型(意思就是超时异常),于是打印出了time out !
输出结果如下:
![1973be5bf7ba88f1bc1a4348d35e5d14.png](https://img-blog.csdnimg.cn/img_convert/1973be5bf7ba88f1bc1a4348d35e5d14.png)
其他参数(少用)
context参数:它必须是ssl.SSLContext类型,用来指定SSL设置,实现SSL加密传输。
cafile、capath:分别指定CA证书和它的路径,用于实现可信任的CA证书的HTTP请求。
cadefault:已经弃用,默认False。
2.Requset
上文已经讲解了如何利用urlopen()方法实现最基本的请求发起。但这几个简单的参数并不足以构建一个完整的请求(过于简单的请求会被浏览器识别为爬虫而拒绝响应)。如果请求中需要加入Headers等信息,就需要用到Requset类来构建。
同样通过实例展示Request用法:
import
![13bbae9665d05b8d27c17686276d9f34.png](https://img-blog.csdnimg.cn/img_convert/13bbae9665d05b8d27c17686276d9f34.png)
我们依然是用urlopen()方法来发送请求,只是这次的参数不再是url,而是一个Request类型对象。通过构造这个数据结构,我们可以将请求独立为一个对象,并且更灵活的配置参数。
Request的函数原型如下:
class urllib.request.Request(url,data = None,headers ={ },origin_req_host =None,unverifiable = False,method = None)
下面来看它的具体参数:
url:用于请求URL,这是必传参数,其他都是可选参数。
data:必须是bytes类型,如果它是字典,可以先用urllib.parse模块里的urlencode方法编码。(用于POST请求)
headers:是一个字典,它就是请求头,我们可以在构造请求时,通过headers参数直接构造,也可以通过调用请求示例的add_header()方法添加。
origin_req_host :指的是请求方的host名称或IP地址。
unverifiable:表示这个请求是否无法验证,默认为False,意思是说用户没有足够权限来选择接收这个请求的结果。比如我们请求一个HTML文档中的图片,但是我们没有自助抓取图象的权限,这是unverifiable的值就是True。
method:是一个字符串,用来指示请求使用方法,如GET、POST、PUT等。
下面我们给Request传入多个参数构建请求为例进行理解:
import
![34f544f55f150e32cf8d1b6d60d1045a.png](https://img-blog.csdnimg.cn/img_convert/34f544f55f150e32cf8d1b6d60d1045a.png)
在这个示例中,我们通过4个参数构造了一个请求,我们加入了url、data、headers、method,其中最重要的是把头信息(包含User-Agent和Host)写入了Request,让请求变得更完整。
运行结果如下:
![b1e9ed338e95dc9473496b978d59eae6.png](https://img-blog.csdnimg.cn/img_convert/b1e9ed338e95dc9473496b978d59eae6.png)
可以看到,我们成功通过新建的参数,设置了data、headers 和 method。
另外之前提到的headers也可以用add_header()方法添加,示例代码如下:
req
3.高级用法
在上面的过程中,我们虽然可以构造请求,但是对于一些更高级的操作,比如Cookie处理、代理设置等,我们还需要借助Handler工具。
本部分内容相对硬核,初学者可以跳过,笔者后续有使用到再更新。
本文总结参考《Python3网络爬虫开发实战》