人生苦短,我用 Python
上一篇我们聊了 urlopen 的基本使用姿势,但这几个简单的参数并不足以构建一个完整的请求。对于复杂的请求,例如需要添加请求头就显得无能为力,这时我们可以选择使用 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)
还是先来看一个简单的示例,使用 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 的父类,它提供了直接使用使用的方法如下:
接下来,就有各种 Handler 子类集成这个 BaseHandler 类:
等等, 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的方法包括:
下面我们来演示一下如何获取网站的 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)
代码中具体的含义小编就不再解释了,注释已经写得比较完善。最后得到的打印结果如下:
, , , ]>
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 即可。
请求正常的时候可以相应摆渡首页的源码,结果小编也就不贴了,属实有点长。
本篇的内容就到这里了,希望各位同学记得自己动手写代码哦~~
成长离不开与优秀的伙伴共同学习,如果你需要好的学习环境,好的学习资源,项目教程,零基础学习,这里欢迎每一位热爱Python的小伙伴,Python学习圈