- A+
人生苦短,我用 Python
前文传送门:
小白学 Python 爬虫(2):前置预备(一)基础类库的装置
小白学 Python 爬虫(3):前置预备(二)Linux基础入门
小白学 Python 爬虫(4):前置预备(三)Docker基础入门
小白学 Python 爬虫(6):前置预备(五)爬虫框架的装置
小白学 Python 爬虫(10):Session 和 Cookies
小白学 Python 爬虫(11):urllib 基础运用(一)
弁言
上一篇我们聊了 urlopen 的基础运用姿态,但这几个简朴的参数并不足以构建一个完全的要求。关于庞杂的要求,比方须要增加要求头就显得无计可施,这时刻我们能够挑选运用 Request 。
Request
官方文档:https://docs.python.org/zh-cn/3.7/library/urllib.request.html
起首来看一下 Request 的运用语法:
class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
- url:要求的地点链接,只要这个是必传参数,其他都是可选参数。
- data:假如这个参数须要通报,则必需传bytes(字撙节)范例的。
- headers:要求头信息,它是一个字典,能够在组织要求的时刻经由过程 headers 之间组织,也能够挪用 add_header() 增加。
- origin_req_host:提议要求一方的 host 称号或许也能够是 ip 地点。
- unverifiable:指的是这个要求是不是是没法考证的,默许是 False 。意义就是说用户没有充足权限来挑选吸收这个要求的效果。比方我们要求一个HTML文档中的图片,然则我们没有自动抓取图象的权限,这时刻 unverifiable 的值就是 True 。
- method:要求要领,如 GET 、 POST 、 PUT 、 DELETE 等等。
照样先来看一个简朴的示例,运用 Request 爬取博客网站:
import urllib.request
request = urllib.request.Request('https://www.geekdigging.com/')
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))
能够看到,这里照样运用 urlopen() 来提议要求,只是参数不再是之前的 URL 、 Data 、 timeout 等等信息,而是变成了 Request
范例的对象。
我们来构建一个轻微庞杂一点的要求。
import urllib.request, urllib.parse
import json
url = 'https://httpbin.org/post'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
'Content-Type': 'application/json;encoding=utf-8',
'Host': 'geekdigging.com'
}
data = {
'name': 'geekdigging',
'hello':'world'
}
data = bytes(json.dumps(data), encoding='utf8')
req = urllib.request.Request(url=url, data=data, headers=headers, method='POST')
resp = urllib.request.urlopen(req)
print(resp.read().decode('utf-8'))
效果以下:
{
"args": {},
"data": "{\"name\": \"geekdigging\", \"hello\": \"world\"}",
"files": {},
"form": {},
"headers": {
"Accept-Encoding": "identity",
"Content-Length": "41",
"Content-Type": "application/json;encoding=utf-8",
"Host": "geekdigging.com",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
},
"json": {
"hello": "world",
"name": "geekdigging"
},
"origin": "116.234.254.11, 116.234.254.11",
"url": "https://geekdigging.com/post"
}
这里我们经由过程 4 个参数构建了一个 Request
对象。
经由过程 url 指定了接见的链接,照样前面一片文章中提到的测试链接。
在 headers 中指定了 User-Agent
、 Content-Type
和 Host
3 个参数。
在 data 中运用 json.dumps()
将一个 dict 转换成 json 花样,并经由过程 bytes()
终究转换为字撙节。
末了,指定了接见体式格局为 POST 。
从终究的效果中,能够看到我们前面的设定全都胜利。
进阶操纵
前面我们运用 Request 完成了要求头的增加,假如我们想处置惩罚 Cookies 和运用代办接见,就须要运用到越发壮大的 Handler 了。 Handler 能够简朴理解为种种功用的处置惩罚器,运用它,险些能够为我们做到一切有关 HTTP 要求的事变。
urllib.request 为我们供应了 BaseHandler 类,它是一切其他 Handler 的父类,它供应了直接运用运用的要领以下:
- add_parent():增加director作为父类。
- close():封闭它的父类。
- parent():翻开运用差别的协定或处置惩罚毛病。
- default_open():捕捉一切的URL及子类,在协定翻开之前挪用。
接下来,就有种种 Handler 子类集成这个 BaseHandler 类:
- HTTPDefaultErrorHandler:用来处置惩罚http响应毛病,毛病会抛出HTTPError类的异常。
- HTTPRedirectHandler:用于处置惩罚重定向。
- ProxyHandler:用于设置代办,默许代办为空。
- HTTPPasswordMgr:用于治理暗码,它保护用户名和暗码表。
- AbstractBasicAuthHandler:用于猎取用户/暗码对,然后重试要求来处置惩罚身份考证要求。
- HTTPBasicAuthHandler:用于重试带有身份认证信息的要求。
- HTTPCookieProcessor:用于处置惩罚cookies。
等等, urllib 为我们供应的 BaseHandler 子类异常的多,小编这里就不一一列举,列位同砚能够经由过程接见官方文档来检察。
官方文档地点:https://docs.python.org/zh-cn/3.7/library/urllib.request.html#basehandler-objects
在引见怎样运用 Handler 之前,先引见一个高等类: OpenerDirector 。
OpenerDirector 是用来处置惩罚URL的高等类,它分三个阶段来翻开URL:
在每一个阶段中挪用这些要领的递次是经由过程对处置惩罚顺序实例举行排序来肯定的;每一个运用此类要领的顺序都邑挪用 protocol_request() 要领来预处置惩罚要求,然后挪用 protocol_open() 来处置惩罚要求;末了挪用 protocol_response() 要领来处置惩罚响应。
我们能够称 OpenerDirector 为 Opener 。我们之前用过 urlopen() 这个要领,实际上它就是 urllib 为我们供应的一个 Opener 。
Opener的要领包含:
- add_handler(handler):增加处置惩罚顺序到链接中
- open(url,data=None[,timeout]):翻开给定的URL与urlopen()要领雷同
- error(proto,*args):处置惩罚给定协定的毛病
下面我们来演示一下怎样猎取网站的 Cookies :
import http.cookiejar, urllib.request
# 实例化cookiejar对象
cookie = http.cookiejar.CookieJar()
# 运用 HTTPCookieProcessor 构建一个 handler
handler = urllib.request.HTTPCookieProcessor(cookie)
# 构建Opener
opener = urllib.request.build_opener(handler)
# 提议要求
response = opener.open('https://www.baidu.com/')
print(cookie)
for item in cookie:
print(item.name + " = " + item.value)
代码中详细的寄义小编就不再诠释了,解释已写得比较完善。末了获得的打印效果以下:
<CookieJar[<Cookie BAIDUID=48EA1A60922D7A30F711A420D3C5BA22:FG=1 for .baidu.com/>, <Cookie BIDUPSID=48EA1A60922D7A30DA2E4CBE7B81D738 for .baidu.com/>, <Cookie PSTM=1575167484 for .baidu.com/>, <Cookie BD_NOT_HTTPS=1 for www.baidu.com/>]>
BAIDUID = 48EA1A60922D7A30F711A420D3C5BA22:FG=1
BIDUPSID = 48EA1A60922D7A30DA2E4CBE7B81D738
PSTM = 1575167484
BD_NOT_HTTPS = 1
这里发生一个问题, cookie 既然能够打印,那末我们能不能将 cookie 的输出保留到文件中呢?
答案固然是能够的,由于我们晓得, cookie 自身就是保留在文件中的。
# cookies 保留 Mozilla 型文件示例
filename = 'cookies_mozilla.txt'
cookie = http.cookiejar.MozillaCookieJar(filename)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
cookie.save(ignore_discard=True, ignore_expires=True)
print('cookies_mozilla 保留胜利')
这里我们需修正之前的 CookieJar
为 MozillaCookieJar
,它在生成文件时会用到,是 CookieJar 的子类,能够用来处置惩罚 Cookies 和文件相干的事宜,比方读取和保留 Cookies ,能够将 Cookies 保留成 Mozilla 型浏览器的 Cookies 花样。
在运转完成以后,我们能够在当前顺序的目录下看到生成了一个 cookies.txt
的文件,详细内容以下:
# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This is a generated file! Do not edit.
.baidu.com TRUE / FALSE 1606703804 BAIDUID 0A7A76A3705A730B35A559B601425953:FG=1
.baidu.com TRUE / FALSE 3722651451 BIDUPSID 0A7A76A3705A730BE64A1F6D826869B5
.baidu.com TRUE / FALSE H_PS_PSSID 1461_21102_30211_30125_26350_30239
.baidu.com TRUE / FALSE 3722651451 PSTM 1575167805
.baidu.com TRUE / FALSE delPer 0
www.baidu.com FALSE / FALSE BDSVRTM 0
www.baidu.com FALSE / FALSE BD_HOME 0
小编比较懒,就不截图了,直接贴效果了。
固然我们除了能够将 cookies 保留成为 Mozilla 型浏览器的花样,还能够将 cookies 保留成为 libwww-perl(LWP) 花样的 Cookies 文件。
要保留成LWP花样的Cookies文件,在声明的时刻须要修正为 LWPCookieJar:
# cookies 保留 LWP 型文件示例
filename = 'cookies_lwp.txt'
cookie = http.cookiejar.LWPCookieJar(filename)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
cookie.save(ignore_discard=True, ignore_expires=True)
print('cookies_lwp 保留胜利')
实行效果以下:
#LWP-Cookies-2.0
Set-Cookie3: BAIDUID="D634D45523004545C6E23691E7CE3894:FG=1"; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2020-11-30 02:45:24Z"; comment=bd; version=0
Set-Cookie3: BIDUPSID=D634D455230045458E6056651566B7E3; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2087-12-19 05:59:31Z"; version=0
Set-Cookie3: H_PS_PSSID=1427_21095_30210_18560_30125; path="/"; domain=".baidu.com"; path_spec; domain_dot; discard; version=0
Set-Cookie3: PSTM=1575168325; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2087-12-19 05:59:31Z"; version=0
Set-Cookie3: delPer=0; path="/"; domain=".baidu.com"; path_spec; domain_dot; discard; version=0
Set-Cookie3: BDSVRTM=0; path="/"; domain="www.baidu.com"; path_spec; discard; version=0
Set-Cookie3: BD_HOME=0; path="/"; domain="www.baidu.com"; path_spec; discard; version=0
能够看到,两种范例发生的 cookie 文件花样差别照样异常大的。
已生成了 cookie 文件,下一步我们就是要在要求的时刻增加 cookie ,示例代码以下:
# 要求是运用 Mozilla 型文件
cookie = http.cookiejar.MozillaCookieJar()
cookie.load('cookies_mozilla.txt', ignore_discard=True, ignore_expires=True)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
print(response.read().decode('utf-8'))
这里我们运用 load() 要领来读取当地的Cookies文件,猎取到了 Cookies 的内容。
条件是,我们须要提早生成了 Mozilla 花样的 cookie 文件,然后读取 Cookies 以后运用一样的要领构建 Handler 和 Opener 即可。
要求一般的时刻能够响应摆渡首页的源码,效果小编也就不贴了,属实有点长。
本篇的内容就到这里了,愿望列位同砚记得本身动手写代码哦~~~
示例代码
本系列的一切代码小编都邑放在代码治理堆栈 Github 和 Gitee 上,轻易人人取用。