在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。给客户端们颁发一个通行证,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。比如说有些网站需要登录后才能访问某个页面,在登录之前,你想抓取某个页面内容,登陆前与登陆后是不同的,或者不允许的。
1 opener {#1-opener}
基本的urlopen()方法不支持代理、cookie等其他的HTTP/HTTPS高级功能。所以要支持这些功能,使用相关的 Handler处理器来创建特定功能的处理器对象,然后通过 urllib.request.build_opener()方法使用这些处理器对象,创建自定义opener对象使用自定义的opener对象,调用open()方法发送请求。
2 http.cookiejar {#2-http-cookiejar}
http.cookiejar模块定义了用于自动处理HTTP cookie的类。通过web服务器的HTTP响应设置储存在客户机机器上,然后在稍后的HTTP请求中返回到服务器。
而创建一个带有cookie的自定义opener,在访问登录的URL时,将登录后的cookie保存下来,然后利用这个cookie来访问其他网址。查看登录之后才能看到的信息。就是利用http.cookiejar爬取登陆登录后信息的原理。
下面用代码举例http.cookiejar通常用法:
[sourcecode language="plain"]
import http.cookiejar, urllib.request ①
cj = http.cookiejar.CookieJar() ②
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj)③) ④
r = opener.open("http://example.com/")
[/sourcecode]
① 导入模块
② 创建空的cookie实例
③ 使用HTTPCookieProcessor类创建一个HTTP cookie处理器来处理cj
④ 重新自定义opener,加入cookie等信息后打开网页
3 测试 {#3-}
3.1 获取cookie {#3-1-cookie}
[sourcecode language="plain"]
-*- coding: utf-8 -*-
from http import cookiejar
from urllib import request
if name == 'main':
创建一个cookie实例
cookie = cookiejar.CookieJar()
创建一个http cookie处理器处理cookie
handler = request.HTTPCookieProcessor(cookie)
重新自定义opener,加入handler
opener = request.build_opener(handler)
用自定义的opener打开网页
response = opener.open('https://www.baidu.com')
打印cookie信息
for item in cookie:
print('Name: %s' % item.name)
print('Value: %s' % item.value)
[/sourcecode]
运行结果如下:
3.2 保存cookie {#3-2-cookie}
上面的例子可以实现通过循环获取cookie内容,接下来我们通过FileCookieJar类把cookie储存到本地磁盘的文件中,代码如下:
[sourcecode language="plain"]
-*- coding: utf-8 -*-
from urllib import request
from http import cookiejar
if name == 'main':
设置保存cookie的文件
cookie_file = 'cookie.txt'
创建一个MozillaCookerjar对象实例来保存cookie
cookie = cookiejar.MozillaCookieJar(cookie_file)
创建处理handler
handler = request.HTTPCookieProcessor(cookie)
创建自定义opener
opener = request.build_opener(handler)
response = opener.open('https://www.baidu.com')
保存cookie到文件
cookie.save(ignore_discard=True, ignore_expires=True)
[/sourcecode]
参数说明:
filename:要保存cookie的文件名
ignore_discard:即使cookie被丢弃依然保存
igore_expires:即使cookie已有缓存依然覆盖
执行结果如下:
3.3 使用cookie {#3-3-cookie}
上一节中我们已经将cookie存储到本地磁盘文件中,那如何使用本地保存的cookie呢?我们继续:
[sourcecode language="plain"]
-*- coding: utf-8 -*-
from urllib import request
from http import cookiejar
if name == 'main':
定义保存的cookie文件名
cookie_file = 'cookie.txt'
创建实例对象
cookie = cookiejar.MozillaCookieJar()
从文件加载cookie_file内容到变量
cookie.load(cookie_file, ignore_expires=True, ignore_discard=True)
创建处理handler
handler = request.HTTPCookieProcessor(cookie)
创建自定义opener
opener = request.build_opener(handler)
打开网页
response = opener.open('https://www.baidu.com')
打印内容
print(response.read().decode('utf-8'))
[/sourcecode]
通过 cookie.load(cookie_file, ignore_expires=True, ignore_discard=True)将保存本地的 cookie文件加载,加到request请求中。
4 开始干活 {#4-}
养兵千日,用兵一时,写了这么多了,该实际操作了,下面我们就拿登录豆瓣为例子讲解一下实际使用效果,发现找了好多网站,多数都是要验证码的,那个后面才会搞,没有合适的,这里只是找个网站做例子,供大家参考,大家可以试试登陆自己公司的网站、OA、或其他不需要验证码的网址,首先先了解一下一个抓包小工具
4.1 Fiddler {#4-1-fiddler}
下载地址:https://www.telerik.com/download/fiddler(需要输入邮箱)
或者直接到我网盘下载也可以:链接:https://pan.baidu.com/s/1i5H4uED 密码:lmfy
因为测试用的是公司OA,测试成功,但不大方便,就拿北京市保障性住房的网站来截图说明,记住要注册后登陆一次之后才会知道具体传了哪些参数,访问的网址是哪个:
打开fiddler,输入登陆信息后打开网址,fiddler获取的信息如下:
可以看到头信息,请求地址等信息,最底下是用户名密码和验证码,再看一张图,更清晰
可以看到传的信息很少,只有三个,idCard(用户名), password(密码),code(验证码)
我们想要看到的页面是下面这个页面:
挑转这个页面后,也可以通过fiddler查看跳转的连接,提交的参数,分析过程就是这样,具体代码如下:
[sourcecode language="plain"]
-*- coding: utf-8 -*-
from urllib import request, parse, error
from http import cookiejar
if name == 'main':
登陆地址
dl_url = 'http://www.bphc.com.cn/front/member/toLogin'
建立一个空字典,用来存储data传输的参数
dl_data = {}
添加参数
dl_data['idCard'] = 'xxxxxxxx'
dl_data['password'] = '123456789'
dl_data['code']='xxxxxx'
通过parse格式化数据
dl_data = parse.urlencode(dl_data).encode('utf-8')
声明一个cookie实例来保存cookie
cookie = cookiejar.CookieJar()
创建handler处理器
handler = request.HTTPCookieProcessor(cookie)
自定义opener
opener = request.build_opener(handler)
添加头信息
head = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0', 'Connection': 'keep-alive'}
打开url
req = request.Request(url=dl_url, data=dl_data, headers=head)
要获取信息的页面地址
lc_url = 'http://www.bphc.com.cn/article/list/b02e7e29e33642f789e4d1e41db08b7d.html'
lc_data = {}
格式化数据
lc_data = parse.urlencode(lc_data).encode('utf-8')
req2 = request.Request(url=lc_url, data=lc_data, headers=head)
try:
打开网址
response = opener.open(req)
response2 = opener.open(req2)
html = response2.read().decode('utf-8')
保存到文件
with open('test7.html', 'w') as f:
f.write(html)
print(html)
except error.URLError as e:
if hasattr(e, 'code'):
print("HTTPError: %d" % e.code)
elif hasattr(e, 'reason'):
print("URLError: %s" % e.reason)
[/sourcecode]
代码示例如上,这个因为涉及到验证码问题,而我的OA系统又因为不能公开,所以具体执行就没法演示,大家可以跟着这个思路区做,我也会找找不需要验证码的网址,后续替换一下。