在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。给客户端们颁发一个通行证,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。比如说有些网站需要登录后才能访问某个页面,在登录之前,你想抓取某个页面内容,登陆前与登陆后是不同的,或者不允许的。
1 opener
基本的urlopen()方法不支持代理、cookie等其他的HTTP/HTTPS高级功能。所以要支持这些功能,使用相关的 Handler处理器来创建特定功能的处理器对象,然后通过 urllib.request.build_opener()方法使用这些处理器对象,创建自定义opener对象使用自定义的opener对象,调用open()方法发送请求。
2 http.cookiejar
http.cookiejar模块定义了用于自动处理HTTP cookie的类。通过web服务器的HTTP响应设置储存在客户机机器上,然后在稍后的HTTP请求中返回到服务器。
而创建一个带有cookie的自定义opener,在访问登录的URL时,将登录后的cookie保存下来,然后利用这个cookie来访问其他网址。查看登录之后才能看到的信息。就是利用http.cookiejar爬取登陆登录后信息的原理。
下面用代码举例http.cookiejar通常用法:
import http.cookiejar, urllib.request ① cj = http.cookiejar.CookieJar() ② opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj)③) ④ r = opener.open("http://example.com/")
① 导入模块
② 创建空的cookie实例
③ 使用HTTPCookieProcessor类创建一个HTTP cookie处理器来处理cj
④ 重新自定义opener,加入cookie等信息后打开网页
3 测试
3.1 获取cookie
# -*- 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)
运行结果如下:
3.2 保存cookie
上面的例子可以实现通过循环获取cookie内容,接下来我们通过FileCookieJar类把cookie储存到本地磁盘的文件中,代码如下:
# -*- 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)
参数说明:
filename:要保存cookie的文件名
ignore_discard:即使cookie被丢弃依然保存
igore_expires:即使cookie已有缓存依然覆盖
执行结果如下:
3.3 使用cookie
上一节中我们已经将cookie存储到本地磁盘文件中,那如何使用本地保存的cookie呢?我们继续:
# -*- 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'))
通过 cookie.load(cookie_file, ignore_expires=True, ignore_discard=True)将保存本地的 cookie文件加载,加到request请求中。
4 开始干活
养兵千日,用兵一时,写了这么多了,该实际操作了,下面我们就拿登录豆瓣为例子讲解一下实际使用效果,发现找了好多网站,多数都是要验证码的,那个后面才会搞,没有合适的,这里只是找个网站做例子,供大家参考,大家可以试试登陆自己公司的网站、OA、或其他不需要验证码的网址,首先先了解一下一个抓包小工具
4.1 Fiddler
下载地址:https://www.telerik.com/download/fiddler(需要输入邮箱)
或者直接到我网盘下载也可以:链接:https://pan.baidu.com/s/1i5H4uED 密码:lmfy
因为测试用的是公司OA,测试成功,但不大方便,就拿北京市保障性住房的网站来截图说明,记住要注册后登陆一次之后才会知道具体传了哪些参数,访问的网址是哪个:
打开fiddler,输入登陆信息后打开网址,fiddler获取的信息如下:
可以看到头信息,请求地址等信息,最底下是用户名密码和验证码,再看一张图,更清晰
可以看到传的信息很少,只有三个,idCard(用户名), password(密码),code(验证码)
我们想要看到的页面是下面这个页面:
挑转这个页面后,也可以通过fiddler查看跳转的连接,提交的参数,分析过程就是这样,具体代码如下:
# -*- 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)
代码示例如上,这个因为涉及到验证码问题,而我的OA系统又因为不能公开,所以具体执行就没法演示,大家可以跟着这个思路区做,我也会找找不需要验证码的网址,后续替换一下。
原创文章,作者:kepupublish,如若转载,请注明出处:https://blog.ytso.com/54644.html