获取网页
1、urllib库
在 Python2 中,有 urllib 和 urllib2 两个库来实现请求的发送。 而在 Python3中,已经不存在urllib2这个库了 , 统一为urllib,其官方文档链接为: https://docs.python.org/zh-cn/3/library/urllib.html
urllib包含4个模块:
request : 它是最基本的 HTTP 请求模块,可以用来模拟发送请求。 它还带有处理授权验证( authenticaton )、重定向( redirection)、浏览器 Cookies 以及其他内容。
error: 异常处理模块,如果出现请求错误, 我们可以捕获这些异常,然后进行重试或其他操作以保证程序不会意外终止。
parse: 一个工具模块,提供了许多 URL 处理方法,比如拆分、解析、 合并等。
robotparser:主要是用来识别网站的 robots.txt 文件,然后判断哪些网站可以爬,哪些网站不可以爬,它其实用得比较少。
1.1 发送请求
1.1.1、urllib.request.urlopen()
以实现最基本请求的发起
urllib.request.urlopen(url,data = None,[ timeout,] **,*cafile = None*,*capath = None*,*cadefault = False*,*context = None* )
参数:
url:打开统一资源定位地址 url,可以是一个字符串或一个 Request 对象。
data:data 参数是可选的。如果要添加该参数,并且如果它是字节流编码格式的内容,即bytes类型,则需要通过 bytes()方法转化。另外,如果传递了这个参数,则它的请求方式就不再是 GET方式,而是POST方式。
timeout:timeout 参数用于设置超时时间,单位为秒,意
思就是如果请求超出了设置的这个时间,还没有得到响应, 就会抛出异常。 如果不指定该参数,就会使用全局默认时间。它支持 HTTP、HTTPS 、FTP 请求。。 程序时间后,服务器依然没有响应,于是抛出了 URLError 异常。 异常属于 urllib. error 模块,错误原因是超时。
cafile、capath : 可选的cafile和capath参数为HTTPS请求指定一组受信任的CA证书。 cafile应该指向包含一堆 CA证书的单个文件,而capath应该指向哈希证书文件的目录。可以在中找到更多信息ssl.SSLContext.load_verify_locations()
。
cadefault :cadefault参数被忽略
context: context 参数,它必须是 ssl.SSLContext 类型,用来指定 SSL设置。
返回值:
返回HTTPResposne 类型的对象,主要包含 read() 、 readinto()、 getheader(name)、 getheaders() 、 fileno()等方法,以及 msg、 version、 status 、 reason 、 debuglevel、 closed 等属性。
read():得到返回的网页内容
status:得到返回结果的状态码
geturl() :返回检索到的资源的URL,通常用于确定是否遵循了重定向
info() :以email.message_from_string()实例的形式返回页面的元信息
getcode()
:返回响应的HTTP状态代码
例如:
from urllib.request import urlopen
# 发起网络请求
resp = urllopen('http://www.hao123.com')
assert resp.code == 200
print('请求成功')
# 保存请求的网页
# f 变量接收open()函数返回的对象的__enter__()返回结果
with open('a.html', 'wb') as f:
f.write(resp.read())
urlopen(url, data=None)可以直接发起url的请求, 如果data不为空时,则默认是POST请求,反之为GET请求。
resp是http.client.HTTPResponse类对象。
1.1.2、urllib.request.Request类
在基本请求中加入 Headers 等信息
构造方法:
class urllib.request.Request(ur1, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
url: 用于请求URL, 这是必传参数,其他都是可选参数。
data: 如果要传,必须传 bytes (字节流)类型的。 如果它是字典,可以先用 urllib.parse 模块里的urlencode()编码。
headers:是一个字典,它就是请求头,我们可以在构造请求时通过 headers 参数直接构造,也可以通过调用请求实例的 add_header()方法添加。 添加请求头最常用的用法就是通过修改 User-Agent 来伪装浏览器,默认的 User-Agent 是Python-urllib ,我们可以通过修改它来伪装浏览器。 比如要伪装火狐浏览器,你可以把它设置为:Mozilla/s.o (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11
origin_req_host:指的是请求方的 host名称或者 IP 地址。
unverifiable:表示这个请求是否是无法验证的,默认是 False,意思就是说用户没 有足够权限来选择接收这个请求的结果。 例如,我们请求一个 HTML 文档中的图片,但是我 们没有向动抓取图像的权限,这时 unverifiable 的值就是 True。
method:是一个字符串 ,用来指示请求使用的方法,比如 GET、 POST 和 PUT 等。
属性:
Request.full_url:设置、获取和删除构造函数的URL
Request.type:请求类型
Request.host:URI授权,通常是主机,但也可以包含由冒号分隔的端口
Request.origin_req_host: 请求的原始主机,不含端口。
Request.selector:URI 路径。若 Request 使用代理,选择器将会是传给代理的完整 URL。
Request.data:请求的实体,或者None未指定。
Request.unverifiable:布尔,表明请求是否为 RFC 2965 中定义的无法证实的。
Request.method:要使用的HTTP请求方法。默认情况下,其值为None,这意味着get_method()将对要使用的方法进行常规计算。可以通过get_method()在Request子类的类级别设置默认值来提供默认值,或通过method 参数将值传递给Request构造函数,从而设置其值(从而覆盖中的默认计算)。
Request.get_method():返回指示HTTP请求方法的字符串。如果 Request.method不是None,返回其值,否则返回 'GET'如果Request.data是None,或者'POST'如果它不是。这仅对HTTP请求有意义。
Request.add_header(key,val ): 向请求添加另一个标头。目前,所有处理程序都会忽略标头,但HTTP处理程序除外,HTTP处理程序会将标头添加到发送到服务器的标头列表中。请注意,具有相同名称的头不能超过一个,并且如果密钥冲突,以后的调用将覆盖以前的调用。当前,这不会丢失HTTP功能,因为所有具有多次使用意义的标头都具有一种(标头专用)方式,仅使用一个标头即可获得相同的功能。
Request.add_unredirected_header(key,header ): 添加一个不会被加入重定向请求的头部。
Request.has_header(标题): 返回实例是否具有命名头(检查常规和未重定向)。
Request.remove_header(标题): 从请求实例中删除命名标头(从常规标头和未重定向标头中都删除)。
Request.get_full_url() : 返回构造器中给定的 URL。
Request.set_proxy(host,type ): 通过连接到代理服务器来准备请求。主机和类型将替换实例的主机和类型,实例的选择器将是构造函数中提供的原始URL。
Request.get_header(header_name,默认= None ) : 返回给定标头的值。如果标题不存在,则返回默认值。
Request.header_items() : 返回请求标头的元组列表(header_name,header_value)。
例如:
from urllib.request import Request
def search_baidu():
# 网络资源的接口(URL)
url = 'https://www.baidu.com'
# 生成请求对象,封装请求的url和头header
request = Request(url,
headers={
'Cookie': 'BIDUPSID=16CECBB89822E3A2F26ECB8FC695AFE0; PSTM=1572182457; BAIDUID=16CECBB89822E3A2C554637A8C5F6E91:FG=1; BD_UPN=123253; H_PS_PSSID=1435_21084_30211_30283; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; H_PS_645EC=6f7aTIObS%2BijtMmWgFQxMF6H%2FhK%2FcpddiytCBDrefRYyFX%2B%2BTpyRMZInx3E',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
})
response = urlopen(request) # 发起请求
assert response.code == 200
print('请求成功')
# 读取响应的数据
bytes_ = response.read()
# 将响应的数据写入文件中
with open('index.html', 'wb') as file:
file.write(bytes_)
1.1.3、高级用法
urllib. request.BaseHandler 类,它是所有其他 Handler的父类,它提供了最基本的方法。各种Handler子类继承这个 BaseHandler 类
BaseHandler.add_parent(director): 添加一个director作为父辈
BaseHandler.close():删除任何父辈
HITPDefaultErrorHandler:用于处理HTTP 响应错误,错误都会抛出 HTTPError类型的异常。
HTTPRedirectHandler:用于处理重定向。
HTTPCookieProcessor: 用于处理 Cookies。
ProxyHandler:用于设置代理, 默认代理为空。
HTTPPasswordMgr:用于管理密码,它维护了用户名和密码的表。
HTTPBasicAuthHandler : 用于管理认证,如果一个链接打开时需要认证,那么可以用它来解 决认证问题。
OpenerDirector,我们可以称为 Opener。就是利用 Handler 来构建 Opener
1.2、 处理异常
urllib 的 error 模块定义了由 request 模块产生的异常。 如果出现了问题, request 模块便会抛州 error 模块中定义的异常。
1.2.1、 URLError
URL Error 类来自 urllib 库的 error 模块,它继承自 OSError 类,是 error 异常模块的基类,由 request 模块生的异常都可以通过捕获这个类来处理。
reason属性:返回错误的原因。
1.2.2、 HTTPError
它是 URLError 的子类,专门用来处理 HTTP 请求错误,比如认证请求失败等。 它有如下 3 个属性。
code: 返回 HTTP 状态码,比如 404 表示网页不存在, 500 表示服务器内部错误等。
reason:同父类一样,用于返回错误的原因。
headers: 返回请求头。
1.3、解析链接
urllib 库里还提供了 parse 模块,它定义了处理 URL 的标准接口,例如实现 URL 各部 分的抽取、合并以及链接转换。 它支持如下协议的 URL 处理:file、ftp、 gopher、 hdl、 http、 https、 imap、 mailto 、 mms 、 news、 nntp 、 prospero 、 rsync、 rtsp、 rtspu、 sftp 、 sip、 sips 、 snews 、 svn 、 svn+ssh 、 telnet 和 wais。
1.3.1、urlparse()
该方法返回结果是一个 ParseResult 类型的对象,它包含 6个部分,分别是 scheme、 netloc、 path、 params 、 query 和 fragment。
urlparse()方法将URL拆分成了 6个部分。 解析时有特定的分隔符。 比如,://前面的就是 scheme,代表协议;第一个/符号前面便是 netloc ,即域名,后面是 path,即访 问路径;分号;前面是 params ,代表参数;问号?后面是查询条件 query, 一般用作 GET 类型的 URL; 井号#后面是锚点,用于直接定位页面内部的下拉位置。
urllib.parse.urlparse(urlstring, scheme=”, allow_fragments=True)
urlstring:必填项,即待解析的URL
scheme:是默认的协议,假如这个链接没有带协议信息,会将这个作为默认的协议
allow_fragments:即是否忽略fragment。 如果它被设置为 False,fragment部分就会被忽略, 它会被解析为 path、 parameters 或者 query 的一部分,而 fragment 部分为空。
1.3.2、urlunparse()
有了 urlparse(), 相应地就有了它的对立方法 urlunparse()。 它接受的参数是一个可迭代对象, 但是它的长度必须是 6, 否则会抛出参数数量不足或者过多的问题。
1.3.3、 urlsplit()
这个方法和 urlparse()方法非常相似, 只不过它不再单独解析 params 这一部分,只运回 5 个结果。 上面例子中的 params 会合并到 path 中。
1.3.4、urlunsplit()
与 urlunparse()类似,它也是将链接各个部分组合成完整链接的方法,传人的参数也是一个可迭代对象,例如列表、 元组等,唯一的区别是长度必须为 5。
1.3.5、urljoin()
有了 urlunparse()和 urlunsplit()方法,我们可以完成链接的合井,不过前提必须要有特定长度 的对象,链接的每一部分都要清晰分开。
此外,生成链接还有另一个方法,那就是 urljoin()方法。 我们可以提供一个 base_url (基础链接 ) 作为第一个参数,将新的链接作为第二个参数,该方法会分析 base_url 的 scheme、 netloc 和 path 这 3 个内容并对新链接缺失的部分进行补充,最后返回结果。
1.3.6、urlencode()
这个方法非常常用。 有时为了更加方便地构造参数,我们会事先用字典来表示。 要转化为 URL 的参数时,只需要调用该方法即可。
1.3.7、parse_qs()
有了序列化,必然就有反序列化。 如果我们有一串 GET 请求参数,利用 parse_qs()方法, 就可以将它转回字典。
1.3.8、parse_qsl()
它用于将参数转化为元组组成的列表
1.3.9、quote()
该方法可以将内容转化为 URL 编码的格式。 URL 中带有中文参数时,有时可能会导致乱码的问题,此时用这个方法可以将中文字符转化为 URL 编码。
1.3.10、 unquote()
有了 quote()方法,当然还有 unquote()方法,它可以进行 URL解码
1.4、分析Robots协议
利用 urllib 的 robotparser 模块,我们可以实现网站 Robots 协议的分析。
1.4.1、Robots协议
Robots 协议也称作爬虫协议、机器人协议,它的全名叫作网络爬虫排除标准( Robots Exclusion Protocol ),用来告诉爬虫和搜索引擎哪些页面可以抓取,哪些不可以抓取。 它通常是一个叫作 robots.txt 的文本文件,一般放在网站的根目录下。
当搜索爬虫访问一个站点时,它首先会检查这个站点根目录下是否存在 robots.txt 文件,如果存在, 搜索爬虫会根据其中定义的爬取范围来爬取。 如果没有找到这个文件,搜索爬虫便会访问所有可直接访问的页面。
User-agent 描述了搜索’爬虫的名称,这里将其设置为*则代表该协议对任何爬取爬虫有效。
Allow 一般和 Disallow 一起使用,一般不会单独使用,用来排除某些限制。 现在我们设置为 /public/,则表示所有页面不允许抓取,但可以抓取 public 目录。
1.4.2、爬虫名称
一些常见的搜索爬虫的名称及对应的网站。比如百度的就叫作 BaiduSpider。
1.4.3、robotparser
了解 Robots 协议之后,我们就可以使用 robotparser 模块来解析 robots.txt 了。 该模块提供了一个 类RobotFileParser,它可以根据某网站的 robots.txt 文件来判断一个爬取爬虫是否有权限来爬取这个网页。 该类用起来非常简单,只需要在构造方法里传人 robots.txt 的链接即可。
首先看一下它的声明:
urllib.robotparser.RobotFileParser(url=’’)
当然,也可以在声明时不传人,默认为空,最后再使用 set_url()方法设置一下也可。
下面列出了这个类常用的几个方法。
set_url(): 用来设置 robots.txt 文件的链接。 如果在创建 RobotFileParser 对象时传入了链接,那么就不需要再使用这个方法设置了。
read(): 读取 robots.txt 文件并进行分析。注意,这个方法执行一个读取和分析操作,如果不 调用这个方法, 接下来的判断都会为 False,所以一定记得调用这个方法。 这个方法不会返 回任何内容,但是执行了读取操作。
parse(): 用来解析robots.txt文件,传人的参数是 robots.txt某些行的内容,它会按照 robots.txt 的语法规则来分析这些内容。
can_fetch(): 该方法传人两个参数, 第一个是 User-agent,第二个是要抓取的 URL。 返回的 内容是该搜索引擎是否可以抓取这个 URL,返回结果是 True 或 False。
mtime(): 返回的是上次抓取和分析 robots.txt 的时间,这对于长时间分析和抓取的搜索爬虫是 很有必要的,你可能需要定期检查来抓取最新的 robots.txt。
modified() :它同样对长时间分析和抓取的搜索爬虫很有帮助,将当前时间设置为上次抓取 和分析 robots.txt 的时间。
例如:
"""
复杂的GET请求,多页面请求下载
"""
from urllib.request import Request, urlopen
from urllib.parse import urlencode
import ssl
import time
ssl._create_default_https_context = ssl._create_unverified_context
url = 'https://www.baidu.com/s?'
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
'Cookie': 'BIDUPSID=16CECBB89822E3A2F26ECB8FC695AFE0; PSTM=1572182457; BAIDUID=16CECBB89822E3A2C554637A8C5F6E91:FG=1; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1573184257; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; H_PS_PSSID=1435_21084_30211_30283; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; delPer=0; PSINO=1; to_lang_often=%5B%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%2C%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%5D; APPGUIDE_8_2_2=1; yjs_js_security_passport=0927713bf2c240ca607108086d07729426db4dbb_1577084843_js; __yjsv5_shitong=1.0_7_c3620451e4363f4aed30cbe954abf8942810_300_1577084847314_223.255.14.197_2d7151e0; from_lang_often=%5B%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%2C%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%5D',
'x-requested-with': 'XMLHttpRequest'
}
params = {
'wd': '',
'pn': 0 # 0, 10, 20, 30 ... = (n-1)*10
}
def pages_get(wd):
params['wd'] = wd
for page in range(1, 101):
params['pn'] = (page-1)*10
page_url = url+urlencode(params)
resp = urlopen(Request(page_url,
headers=headers))
assert resp.code == 200
file_name = 'baidu_pages/%s-%s.html' % (wd, page)
with open(file_name, 'wb') as f:
bytes_ = resp.read()
f.write(bytes_)
print(f'{file_name} 写入成功!')
time.sleep(0.5)
print('下载 %s 100页成功!' % wd)
if __name__ == '__main__':
pages_get('Python3.6')
2、使用requests
2.1、基本用法
2.1.1、Requests.request()
Requests.request(method,url,**kwargs)
-
method: 请求方式,对应get/post/put等7种方式
-
url: str 请求的资源接口(API),在RESTful规范中即是URI(统一资源标签识符)
-
**kwargs:控制访问参数,均为可选项,共13个
-
Params:字典或字节序列,作为参数增加到url中
-
Data:字典、字节序列或文件对象,作为requests的内容
-
Json:json格式的数据,作为request的内容
-
Header:字典,HTTP定制头
-
Cookies: 字典或cookiejar,request中的cookie
-
Auth:元组,支持HTTP认证功能
-
Files:字典类型,传输文件结构,如果是tuple, 则有三种情况:
- ('filename', file-like-object)
- ('filename', file-like-object, content_type)
- ('filename', file-like-object, content_type, custom-headers)
-
Timeout:设置以s为单位的超时时间
-
Proxies:字典类型,设定访问代理服务器,可增加登录认证(可防逆追踪)
-
Allow_redirects:默认为true,重定向开关
-
Stream:默认为true,获取内容立即下载开关
-
Verify:默认为true,认证ssl证书开关
-
Cert:本地ssl证书路径
-
2.1.2、Requests.get()
Requests.get(url,**kwargs)
requests.get() 发起GET请求, 查询数据
可用参数:
- url: str 请求的资源接口(API),在RESTful规范中即是URI(统一资源标签识符)
- **kwargs:控制访问参数,均为可选项,除Proxies其他12个控制访问参数
2.1.3、Requests.head()
Requests.get(url,**kwargs)
可用参数:
- url: str 请求的资源接口(API),在RESTful规范中即是URI(统一资源标签识符)
- **kwargs:控制访问参数,均为可选项,共13个
2.1.4、Requests.post()
Requests.post(url,**kwargs)
可用参数:
- url: str 请求的资源接口(API),在RESTful规范中即是URI(统一资源标签识符)
- **kwargs:控制访问参数,均为可选项,除data、json其他11个
2.1.5、Requests.put()
Requests.put(url,**kwargs)
可用参数:
- url: str 请求的资源接口(API),在RESTful规范中即是URI(统一资源标签识符)
- **kwargs:控制访问参数,均为可选项,除data其他12个控制访问参数
2.1.6、Requests.patch()
Requests.patch(url,**kwargs)
可用参数:
- url: str 请求的资源接口(API),在RESTful规范中即是URI(统一资源标签识符)
- **kwargs:控制访问参数,均为可选项,共13个
2.1.7、Requests.delete()
Requests.delete(url,**kwargs)
可用参数:
- url: str 请求的资源接口(API),在RESTful规范中即是URI(统一资源标签识符)
- **kwargs:控制访问参数,均为可选项,共13个
2.1.8、响应
r.text: HTTP响应内容的字符串形式,即url对应的页面内容
r.content: HTTP响应内容的二进制形式
r.encoding: 从HTTP header中猜测的响应内容编码方式
r.apparent_encoding: 从内容中分析出的响应内容编码方式(备用编码格式)
r.headers: 返回响应头
r.cookies: 返回响应的Cookies
r.url: 返回响应的url属性
r.history: 返回请求的历史
r.status_code: HTTP请求的返回状态,200表示连接成功,404表示失败
2.2、异常
2.3、requests.Respose
以上的请求方法返回的对象类型是Response, 对象常用的属性如下:
- status_code 响应状态码
- url 请求的url
- headers : dict 响应的头, 相对于urllib的响应对象的getheaders(),但不包含cookie。
- cookies: 可迭代的对象,元素是Cookie类对象(name, value, path)
- text : 响应的文本信息
- content: 响应的字节数据
- encoding: 响应数据的编码字符集, 如utf-8, gbk, gb2312
- json(): 如果响应数据类型为
application/json
,则将响应的数据进行反序化成python的list或dict对象。- 扩展-javascript的序列化和反序列化
- JSON.stringify(obj) 序列化
- JSON.parse(text) 反序列化
- 扩展-javascript的序列化和反序列化