赞
踩
urllib是Python3中内置的HTTP请求库,不需要单独安装,官方文档链接如下:
https://docs.python.org/3/library/urllib.html
从官方文档可以看出,urllib包含4个模块,如下图所示。
这4个模块的功能描述如下:
request:最基本的HTTP请求模块,可以用来发送HTTP请求,并接收服务端的响应数据。这个过程就像在浏览器地址栏输入URL,然后按Enter键一样。
error:异常处理模块,如果出现请求错误,我们可以捕获这些异常,然后根据实际情况,或者进行重试,或者直接忽略,或进行其他操作。
parse:工具模块,提供了很多处理URL的API,如拆分、解析、合并等。
robotparser:主要用来识别网站的robots.txt文件,然后判断哪些网站可以抓取,哪些网站不可以抓取。
本文会介绍这4个模块的核心用法。
urllib最基本的一个应用就是向服务端发送HTTP请求,然后接收服务端返回的响应数据。这个功能只需要通过urlopen函数就可以搞定。例如,下面的代码向百度发送HTTP GET请求,然后输出服务端的响应结果。
import urllib.request
response=urllib.request.urlopen('https://baidu.com')
# 将服务端的响应数据用utf-8解码
print(response.read().decode('utf-8'))
运行结果如下图所示:
我们可以看到,使用urllib与服务端交互是非常容易的,除了import语句外,真正与业务有关的代码只有2行,就完成了整个与服务端交互的过程。其实这个过程已经完成了爬虫的第一步,就是从服务端获取HTML代码,然后就可以利用各种分析库对HTML代码进行解析,提取出我们感兴趣的URL、文本、图像等。
其实urlopen函数返回的是一个对象,而read是这个对象的一个方法,可以利用type方法输出这个对象的类型,当我们知道了对象类型后,就可以很容易知道这个对象中有哪些API,然后调用它们。
import urllib.request
response=urllib.request.urlopen('https://baidu.com')
print(type(response))
这段代码会输出如下的结果:
<class 'http.client.HTTPResponse'>
现在我们了解到,urlopen函数返回的是HTTPResponse类型的对象,主要包含read、getheader、getheaders等方法,以及msg、version、status、debuglevel、closed等属性。
下面的例子编写一个程序,使用urllib访问京东主页,并通过HTTPResponse对象读取响应数据。
import urllib.request
# 向京东商城发送HTTP GET请求,urlopen函数即可以使用http,也可以使用https
response=urllib.request.urlopen('https://www.jd.com')
# 输出urlopen函数返回值的数据类型
print('response的类型:',type(response))
# 输出响应状态码、响应消息和HTTP版本
print('status:',response.status,' msg:',response.msg,' version:', response.version)
# 输出所有的响应头信息
print('headers:',response.getheaders())
# 输出名为Content-Type的响应头信息
print('headers.Content-Type',response.getheader('Content-Type'))
# 输出京东商城首页所有的HTML代码(经过utf-8解码)
print(response.read().decode('utf-8'))
运行结果如下图所示。
urlopen函数默认情况下发送的是HTTP GET请求,如果要发送HTTP POST请求,需要使用data命名参数,该参数是bytes类型,需要用bytes类将字符串形式的数据转换为bytes类型。
编写一个程序,使用urlopen函数向http://httpbin.org/post发送HTTP POST请求,并将返回结果输出到终端。
import urllib.request
# 将表单数据转换为bytes类型,用utf-8编码
data=bytes(urllib.parse.urlencode({'name':'Bill','age':30}),encoding='utf-8')
# 提交HTTP POST请求
response=urllib.request.urlopen('http://httpbin.org/post',data=data)
# 输出响应数据
print(response.read().decode('utf-8'))
这段代码中一开始提供了一个字典形式的表单数据,然后使用urlencode方法将字典类型的表单转换为字符串形式的表单,接下来将字符串形式的表单按utf-8编码转换为bytes类型,这就是要传给urlopen函数的data命名参数的值,要注意,一旦指定了data命名参数,urlopen函数就会向服务端提交HTTP POST请求,这里并不需要显式指定要提交的是POST请求。
本例将HTTP POST请求提交给了http://httpbin.org/post,这是一个用于测试HTTP POST请求的网址,如果请求成功,服务端会将HTTP POST请求信息原封不动地返回给客户端。
运行结果如下图所示。
URLError类属于urllib库的error模块,该类从OSError类继承,是error模块中的异常基类,由request模块产生的异常都可以通过URLError来捕捉。
URLError类有一个reason属性,可以通过这个属性获得错误的原因。
下面的例子向不同服务器发送多个请求,并用URLError类捕捉发生的异常。
from urllib import request,error try: response = request.urlopen('http://www.jd123.com/test.html') except error.URLError as e: # Bad Request print(e.reason) try: response = request.urlopen('https://geekori.com/abc.html') except error.URLError as e: # Not Found print(e.reason) try: response = request.urlopen('https://geekori123.com/abc.html') except error.URLError as e: # [Errno 8] nodename nor servname provided, or not known print(e.reason) try: response = request.urlopen('https://bbbccc.com',timeout=2) except error.URLError as e: # timed out print(e.reason)
程序运行结果如下图所示。
从输出的异常原因可以看出,前两个异常分别是Bad Request和Not Found,响应状态码分别是400和404。其实这两个异常原因都是因为URL的域名是存在的,只是指定的资源不存在,服务端遇到这种情况有可能返回400或404。第3个错误原因是因为域名geekori123.com不存在,DNS解析错误。最后一个错误原因是因为域名和资源都存在,只是服务器在超时时间内没有响应客户端,所以抛出了timeout异常。
HTTPError是URLError的子类,专门用于处理HTTP请求错误,比如400、404错误。该类有如下3个属性:
code:返回HTTP状态码,如404、400等表示服务端资源不存在,500表示服务器内部错误。
reason:用于返回错误原因。
headers:返回请求头。
HTTPError也并不是什么错误都能捕捉,例如time out异常无法用HTTPError捕捉,必须使用URLError捕捉。由于HTTPError是URLError的子类,所以通常的做法是在try…except语句中先捕捉HTTPError异常,如果抛出的不是HTTPError异常,再用URLError进行捕捉。所以URLError起到了兜底的作用。
urlparse函数用于拆分URL,也就是将URL分解成不同的部分,下面先看一个例子。
result = urlparse('https://search.jd.com/Searchprint;hello?keyword=Python从菜鸟到高手&enc=utf-8#comment')
print(type(result),result)
在上面的代码中使用urlparse函数解析了一个URL,并将解析结果类型以及解析结果输出,运行结果如下:
<class 'urllib.parse.ParseResult'>
ParseResult(scheme='https', netloc='search.jd.com', path='/Searchprint', params='hello', query='keyword=Python从菜鸟到高手&enc=utf-8', fragment='comment')
可以看到,返回结果是一个ParseResult类型的对象,包含6部分,分别是scheme、netloc、path、params、query和fragment。根据拆分结果,可以得出一个完整的URL的通用格式如下:
scheme://netloc/path;params?query#fragment
只要符合这个规则的URL,都可以被urlparse函数解析,urlparse函数除了可以传递url参数外,还可以传递另外两个参数。urlparse函数的定义如下:
urlparse(url, scheme='', allow_fragment=True)
我们可以看到,urlparse函数有3个参数,它们的含义如下:
url:必填参数,待解析的URL。
scheme:可选参数,如果url没有带协议(https、http、ftp等),那么scheme参数的值就会作为默认协议。该参数默认值为空字符串。
allow_fragments:可选参数,表示是否忽略fragment部分。该参数值如果为False,表示忽略fragment部分,默认参数值是True。
既然有用于拆分URL的urlparse函数,那么就会有将各个部分合并成一个完整URL的urlunparse函数。该函数接收一个可迭代的对象,对象中的元素个数必须是6,否则会抛出参数数量不足或过多的错误。
下面的例子使用urlparse函数拆分了一个URL,并输出拆分后的各个部分,以及使用urlunparse函数合并不同的部分,组成一个完整的URL。
from urllib.parse import urlparse,urlunparse # 拆分URL result = urlparse('https://search.jd.com/Searchprint;hello?keyword=Python从菜鸟到高手&enc=utf-8#comment') print('scheme:',result.scheme) print('netloc:',result.netloc) print('path:',result.path) print('params:',result.params) print('query:',result.query) print('fragment:',result.fragment) print('-----------------') # 拆分URL,指定默认的scheme,并且忽略fragment部分 result = urlparse('search.jd.com/Searchprint;hello?keyword=Python从菜鸟到高手&enc=utf-8#comment',scheme='ftp',allow_fragments=False) print('scheme:',result.scheme) print('fragment:',result.fragment) print('----------------') # 合并不同部分,组成一个完整的URL data = ['https','search.jd.com','Searchprint','world','keyword=Python从菜鸟到高手&enc=utf-8','comment'] print(urlunparse(data))
程序运行结果如下图所示。
Robots协议也称作爬虫协议、机器人协议,它的全名是网络爬虫排除标准(Robots Exclusing Protocol),用来告诉爬虫和搜索引擎哪些页面可以抓取,哪些不可以抓取。该协议的内容通常放在一个名为robots.txt的文本文件中,该文件一般位于网站的根目录下。
注意,robots.txt文件中的内容只是告诉爬虫应该抓取什么,不应该抓取什么,但并不是通过技术手段阻止爬虫抓取那些被禁止的资源,而只是通知爬虫而已。尽管编写爬虫可以不遵循robots.txt文件中的规则,但作为一只有道德、有文化、有纪律的爬虫,应该尽量遵循robots.txt文件描述的规则。
当爬虫访问一个网站时,首先会检查这个网址根目录下是否存在robots.txt文件,如果存在,爬虫就会根据该文件中定义的抓取范围来抓取Web资源。如果这个文件并不存在,爬虫就会抓取这个网站所有可直接访问的页面。
下面来看一个robots.txt文件的例子:
User-agent:*
Disallow:/
Allow:/test/
这个抓取规则首先告诉爬虫对所有的爬虫有效,而且除了test目录外的任何资源都不允许抓取。如果将这个robots.txt文件放在某个网站的根目录,那么搜索引擎的爬虫就会只抓取test目录下的资源,我们会发现搜索引擎中再也查不到其他目录下的资源了。
上面的User-agent描述了爬虫的名字,这里将其设置为*,则表示对所有的爬虫有效,我们还可以特指某些爬虫,如下面的设置明确指定百度爬虫。
User-agent:BaiduSpider
robots.txt文件中有2个重要的授权指令:Disallow和Allow,前者表示禁止抓取,后者表示允许抓取。也就是说,Disallow是黑名单,Allow是白名单。例如,下面是一些Robots协议的例子。
(1)禁止所有爬虫抓取网站所有的资源
User-agent:*
Disallow:/
(2)禁止所有爬虫抓取网站/private和/person目录中的资源
User-agent: *
Disallow: /private/
Disallow:/person/
(3)只禁止百度爬虫抓取网站资源
User-agent:BaiduSpider
Disallow:/
很多搜索引擎的爬虫都有特定的名称,下表列出了一些常用的爬虫名称。
感兴趣的小伙伴,赠送全套Python学习资料,包含面试题、简历资料等具体看下方。
一、Python所有方向的学习路线
Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。
二、Python必备开发工具
工具都帮大家整理好了,安装就可直接上手!
三、最新Python学习笔记
当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。
四、Python视频合集
观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
五、实战案例
纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
六、面试宝典
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。