urllib模块提供了一系列用于操作URL的功能。
urllib可以被看作一个包,它由四个模块组成,分别为:
什么是robots.txt?
robots.txt 也叫 robots协议,它是一种存放于网站根目录下的ASCII编码的文本文件,robots.txt主要用于告诉搜索引擎或者网络爬虫这个网站中的哪些内容是可被收录的或者是可爬取的,而哪些内容是不可爬取的,主要是起到一个保护隐私的作用。
以网络爬虫为例,当一个网络爬虫访问一个站点时,它会首先检查该站点根目录下是否存在robots.txt,如果存在,网络爬虫会按照该文件中的内容来确定访问的范围。如果不存在,那么网络爬虫将能够访问并爬取所有在该网站上没有被特殊保护的页面。
robots协议并不是一个规范,而是约定俗成的。这就好比你在外出时在家门前写上"禁止入内"的提示语,你写上提示语的目的当然是不希望有人在你不在家的情况下擅自进入你的家中,但很可惜的是,你无法阻止恶意的窃贼或者非法闯入者。
robots.txt 是一个文本文件,因此任何常见的文本编辑器都可以创建或者编辑robots.txt。但要注意 robots.txt 的文件名统一是小写,因为一些系统中的URL是大小写敏感的。
自觉遵守robots协议,是每一个互联网人士都应该做到的基本道德底线。
urllib.request模块定义了在各种复杂情况下打开URL的函数和类,该模块定义的函数有如下:
urllib.request.urlopen()
作用:
创建一个远程URL的类文件对象,然后像本地文件一样操作这个类文件对象来获取远程网页数据。
语法格式:
urllib.request.urlopen(url,data=None,[timeout],cafile=None,capath=None,cadefault=False,context=None)
注意:urllib.request模块默认使用HTTP/1.1版本,并且在HTTP请求头中设置有Connection:close 头域。
参数说明:
url:
目标网址,url参数可以是url字符串,也可以是Request对象。
data:
可选参数,内容为bytes类型,也可以是iterable对象,不过是iterable对象时必须在头中指定Content-Length。目前只有HTTP请求中用到data参数。如果指定data参数,urlopen将使用POST方式发出请求。
另外,如果要指定params,因为params是字典键值对,在Python中,用urlencode()方法将字典数据编码,urlencode()方法内置在urllib.parse模块内,它接收一个dict,并返回一个ASCII文本字符串。但是要注意,如果要把它用在data参数内,还需要将它转换为bytes类型。
转换为bytes类型有多种方法。一种是直接在字符串对象前加b修饰,一种是用字符串对象的encode()方法,也可以用bytes()强制转换。
示例:分别用GET方法和POST方法创建URL类文件对象
GET方法:
import urllib.request
import urllib.parse
dict = {'color':'red','number':7} #随便写的参数数据
params = urllib.parse.urlencode(dict)
url = "http://baidu.com?%s" % params #GET方法的参数在url后面,也可以不带参数,此时默认为GET方法
with urllib.request.urlopen(url) as f:
print(f.read().decode("utf-8"))
POST方法:
import urllib.request
import urllib.parse
dict = {'color':'red','number':7}
data = urllib.parse.urlencode(dict)
data = params.encode('ascii')
with urllib.request.urlopen("http://baidu.com",params) as f:
print(f.read().decode("utf-8"))
timeout:
设置等待时间,单位为秒,如果请求超出了该时间还未得到响应则抛出urllib.error.URLError异常,仅支持HTTP、HTTPS、FTP。
示例(示例中出现的某些方法不明白的可以先看下面的属性与方法介绍)
import urllib.request
import urllib.parse
import urllib.error
import socket
try:
dict = {'color':'black'}
data = urllib.parse.urlencode(dict).encode('ascii')
res = urllib.request.urlopen('http://baidu.com',data = data,timeout = 0.01)
print(res.read().decode('utf-8'))
except urllib.error.URLError as e:
if isinstance(e.reason,socket.timeout):
print(e.reason)
#output:
timed out
context:
如果指定了context参数,则它必须是描述各种ssl选项的ssl.SSLContect实例
什么是SSL?
说起SSL,不得不顺道提一下TLS。
在SSL/TLS之前,很多应用层协议都存在着网络安全问题,例如HTTP协议在传输过程中使用的是明文信息,因此传输报文很容易被截获,如果传输报文在中途被篡改,人们也无法轻易发现。为了解决这种安全隐患,于是在应用层和传输层之间加入了SSL/TLS协议。
TLS与SSL在传输层与应用层之间对网络连接进行加密。
其中,
SSL,英文全称Secure Socket Layer,即安全套接字层。
TLS,英文全称Transport Layer Security,即传输层安全协议。
我们熟知的HTTPS协议就是基于此而来(你会发现HTTPS = HTTP + SSL),但SSL与TLS并不只用于HTTPS,SSL与TLS相当于在应用层与传输层之间多加了一个层,因此很多应用层中的协议都可以被SSL/TLS协议应用。
关于它们的更多内容与细节可参考下面的博客:
SSL详解
TLS详解
SSL与TLS的基本概念与区别
SSL与TLS的区别与介绍
cafile与capath:
cafile与capath参数为HTTPS请求指定一组可信的CA证书。cafile指向CA证书,而capath指向它的路径。
推荐一篇博客:
HTTPS原理与CA证书申请(满满的干货)
cadefault:
该参数被忽略。
方法和属性:
urlopen()函数总是返回一个可以作为上下文管理器工作的对象,type()函数查看显示为http.client.HTTPResponse对象。该对象包含的方法和属性如下:
属性:
import urllib.request
res = urllib.request.urlopen('http://www.python.org')
print(res.msg) #访问成功返回ok
print(res.version) #返回版本信息
print(res.reason) #返回状态信息
print(res.status) #返回状态码200
print(res.closed) #返回对象是否关闭,返回值为一个bool值
print(res.debuglevel) #返回调试等级
方法:
import urllib.request
res = urllib.request.urlopen('http://www.python.org')
print(res.read().decode('utf-8')) #返回网页内容
print(res.readline().decode('utf-8')) #逐行读取,只返回当前行的内容
print(res.readlines()) #逐行读取之后,返回一个字符串列表,注意列表list没有decode()方法
print(res.info()) #返回网页的头信息
print(res.getheader(name)) #返回响应头中键为name的值
print(res.getheaders()) #以列表元组的形式返回响应头信息
print(res.getcode()) #返回响应的HTTP状态码
print(fileno()) #返回文件描述符
print(geturl()) #返回检索的URL
urllib.request.Request()
作用:
urllib.request.Request是一个类,实例化Request得到Request对象。Request类常被用来包装HTTP请求,一般Request()之后,再用urlopen()获取页面。
语法格式:
urllib.request.Request(url,data=None,headers={},origin_req_host=None,unverifiable=False,methon=None)
参数说明:
url:
请求的URL,不可省略。除该参数外,其它参数均为可选参数。
data:
指定要发送的服务器的数据对象。可以是bytes、iterable或者类文件对象。目前只有HTTP请求使用参数data。
headers:
headers是一个dict,可直接指定,也可用add_header()方法向headers参数中传入数据,它被用来构造请求头。
例如可以通过设置User-Agent头的值来伪装浏览器。有关头域在上一篇博客HTTP协议中已经介绍过。
另外,如果设置headers,则应该包含一个合适的Content-Type头域,如果没有指定,Content-Type: application/x-www-form-urlencoded 会被默认添加。
origin_req_host:
指定请求方的host名或者IP地址。
unverifiable:
判断该请求是否是无法验证的,默认为Fasle,但如果我们请求一个资源但却没有权限访问并获取它,那它的值就是True。
method:
用于指定该请求用什么方法,例如GET、POST等。如果没有指定data参数,默认为GET,如果指定了data参数,默认为POST。
示例:
from urllib import parse,request
url = "http://baidu.com"
headers = {'User-Agent':'Mozilla/5.0 (compatible; MSIE 5.5; Windows NT)'} #模拟火狐浏览器
dict = {'name':'Jerry','password':'abc123'}
data = bytes(parse.urlencode(dict),encoding='ascii')
req = request.Request(url=url,data=data,headers=headers,method='POST')
res = request.urlopen(req)
print(res.read().decode('utf-8'))
Request Objects的属性和方法:
属性:
Request.full_url #返回完整的URL
Request.type #返回URI方案
Request.host #通常返回主机名,也可能包含一个由冒号分隔的端口号,
Request.origin_req_host #返回原始主机名,不带端口号。
Request.selector #URI路径。如果请求使用代理,那么selector将被传递给代理的full URL
Request.data #请求体数据,如果未指定则为None。
Request.unverifiable #布尔值,设置是否请求是无法验证的。
Request.method #请求方法,可在子类中设置它的默认值
方法:
Request.get_method()
Request.add_header(key,val) #向请求头中添加一个头域,注意不能有多个具有相同名称的头,后面的覆盖前面的
Request.add_unredirected_header(key,header) #添加一个头,该头不会被添加到重定向请求中
Request.get_header(header_name,dafault=None) #获取给定name的值,不存在则返回default值
Request.has_header(header) #返回实例是否具有命名的头(检查常规头和未定向头)。
Request.remove_header(header) #从Request instance中移除header(包括常规头和未定向头)。
Request.get_full_url() #返回构造器中给定的URL。
Request.header_items() #返回一个元组列表。每个元组包含header_name,header_value两个值。
Request.set_proxy(host,type)
附:add_data,、has_data、get_data、get_type、get_host、get_selector, get_origin_req_host、is_unverifiable。以上这些Request方法自Python3.3之后已被移除。
学的不必太系统,urllib.request这个模块先接触这么多吧,以后需要用到其它的就再另说。
urllib.parse、urllib.error模块下次介绍。
参考:
https://docs.python.org/zh-cn/3.7/library/urllib.request.html#openerdirector-objects
https://www.cnblogs.com/zhangxinqi/p/9170312.html