最近两天项目投产上线,比较忙,没有及时更新,实在抱歉。

在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。由于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系统又因为不能公开,所以具体执行就没法演示,大家可以跟着这个思路区做,我也会找找不需要验证码的网址,后续替换一下。