第三关开始有点难度了,本关的难点就是所谓的两层认证
,需要获取处理 cookie
。
闯关地址是:http://www.heibanke.com/lesson/crawler_ex02/
页面分析刚进入页面时没看懂是怎么玩,以为到这就结束了,抱着试试看的态度注册了下。
注册登录后,发现是一个记账点之类的,网页还没有跳转到题目网页,还不知道怎么玩。
重新从题目地址进入后,发现可以玩了:
页面提示 比上一关多了两层保护。
解题思路题目中提到了两层保护,是哪两层呢?
首先,多了账号登陆一层,还有一层是什么呢?重新登陆,打开 firebug 记录一下整个流程:
从动图中我们可以看到整个流程分为 4 步,依次点击 4 个步骤,分析记录请求标头、请求正文、响应标头、cookies 等是否有值,值为多少,值的来源与请求顺序之间的关系。
为了下文描述方便,我们约定两个变量:
- URL=
http://www.heibanke.com/lesson/crawler_ex02/
- LOGIN_URL=
http://www.heibanke.com/accounts/login/?next=/lesson/crawler_ex02/
首先访问 URL,浏览器会向 URL 发出 GET 请求,得到一个 302 的重定向的响应,响应标头中包含了一个 Location 字段,告诉浏览器新的访问地址 LOGIN_URL
。
如果之前用同样的浏览器闯过第一关或第二关,此请求的请求标头仍然会带上 cookie,但并无实际作用,可忽略;
第 2 步浏览器向 LOGIN_URL 发出新的 GET 请求。我们注意到请求和响应中带了一个 cookie,其中都有一个 csrftoken
字段,其值为 708NMR2acyRWlblKw0rBqSjayL70TJDT。
如果仔细观察,第一步请求头的 cookie 中也有这么一个字段,我们将其记下,此 csrftoken 都将作为以后访问过程中的依据之一。我们将此返回的 cookie 记为 c1;
第 3 步首先我们这里已经注册过了,直接填写登录信息,浏览器会再向 LOGIN_URL 发出 POST 请求,得到一个向第一步中 URL 的 重定向的 302 响应。
请求标头和请求正文中都附带上第二步中的 cookie c1,另外,我们发现请求正文参数中除了 username 和 password 字段外,还有一个 csrfmiddlewaretoken
字段,该字段的值就是 c1 中 csrftoken 的值。
返回的响应标头中附带了两个新的 cookie,其中一个中同样包含了 csrftoken 字段,值为 nmQXET2BHzNbhCksAur9XtLjEiYnfTC4,后面猜数字就会用到。我们将此返回的 cookies 记为 c2;
登录成功后,发现还是第二关的猜数字游戏。只不过,这次猜数字之前需要先进行登录,获取 cookie。
第 4 步页面填写昵称和数字,点击提交,浏览器向 URL 提交 POST 请求,请求标头附带的是第 3 步的 cookie c2,请求正文是昵称密码和 cookie c2 中的 csrftoken 对应的值。
后面的步骤就和第二关差不多了,只不过需要带上 cookie 和 csrftoken。
整个流程涉及两次 cookie 的获取,这就是题目所谓的两层保护。
requests 实现由于第 1 步返回结果中除了 Location 字段没有其他有价值的信息,所以在已知新的地址的情况下可省略第 1 步,直接从第 2 步开始。
# coding=utf-8
import requests
url = 'http://www.heibanke.com/lesson/crawler_ex02/'
login_url = 'http://www.heibanke.com/accounts/login'
login_data = {'username':'liuhaha', 'password':'123456'}
# 获取默认cookie
response = requests.get(url)
if response.status_code == 200:
print('Welcome')
cookies = response.cookies
# 登录
login_data['csrfmiddlewaretoken'] = cookies['csrftoken']
login_response = requests.post(login_url, allow_redirects=False, data=login_data, cookies=cookies)
if login_response.status_code == 200:
print('login sucessfully')
# 获取登录成功后的cookie
cookies = login_response.cookies
playload = {'username':'liuhaha', 'password':'1'}
playload['csrfmiddlewaretoken'] = cookies['csrftoken']
for i in range(31):
playload['password'] = i
print(u'传入参数为:' + str(playload))
r = requests.post(url, data=playload, cookies=cookies)
# print(u'执行结果:' + str(r.status_code))
if r.status_code == 200:
if u"成功" in r.text:
print(u'闯关成功!密码为:' + str(i))
break
else:
print(u'Failed')
break
运行:
$ python crawler_ex02.1.py
Welcome
传入参数为:{'username': 'liuhaha', 'csrfmiddlewaretoken': 'oQxtpIFUtJHIeg03aKGUuieGWSl4UXve', 'password':
0}
传入参数为:{'username': 'liuhaha', 'csrfmiddlewaretoken': 'oQxtpIFUtJHIeg03aKGUuieGWSl4UXve', 'password':
1}
传入参数为:{'username': 'liuhaha', 'csrfmiddlewaretoken': 'oQxtpIFUtJHIeg03aKGUuieGWSl4UXve', 'password':
2}
传入参数为:{'username': 'liuhaha', 'csrfmiddlewaretoken': 'oQxtpIFUtJHIeg03aKGUuieGWSl4UXve', 'password':
3}
传入参数为:{'username': 'liuhaha', 'csrfmiddlewaretoken': 'oQxtpIFUtJHIeg03aKGUuieGWSl4UXve', 'password':
4}
传入参数为:{'username': 'liuhaha', 'csrfmiddlewaretoken': 'oQxtpIFUtJHIeg03aKGUuieGWSl4UXve', 'password':
5}
闯关成功!密码为:5
使用 selenium 实现
使用 selenium 实现方式好像不涉及验证之类的问题,因为完全是模拟的人类登录浏览器的过程。
# coding=utf-8
from selenium import webdriver
url = 'http://www.heibanke.com/lesson/crawler_ex02/'
browser = webdriver.Chrome()
# browser = webdriver.Firefox()
browser.get(url)
# 登录
username = browser.find_element_by_id('id_username')
username.clear()
username.send_keys('liuhaha')
password = browser.find_element_by_id('id_password')
password.clear()
password.send_keys('123456')
password.submit()
# 重新进入问题页面
browser.get(url)
for i in range(31):
username = browser.find_element_by_name('username')
username.clear()
username.send_keys('liuhaha')
password = browser.find_element_by_id('id_password')
password.clear()
password.send_keys(i)
# FireFox下异步,Chrome下同步,submit方法会等待页面加载完成后返回
# password.submit()
# 两种浏览器下click()方法都会等到加载完成后返回
browser.find_element_by_id('id_submit').click()
returnText = browser.find_element_by_tag_name('h3')
print(returnText.text + ', password ' + str(i))
if u"成功" in returnText.text:
break
browser.back()
browser.quit()
运行成功页面:
总结这关主要考察了登录过程的模拟,涉及到 cookie 和 post 数据的处理。登录模拟重点在于过程的分析,post 数据中各字段意义的分析。仅仅一个猜数字的网站就这么复杂,要是其他更复杂的网络,要顺利模拟登录必须知道每个字段的来源、关联、意义,那会更加困难!