无意看到一个很好玩的爬虫闯关游戏,后续会持续将每关心得贴出来游戏开始地址[1]
第一关
访问链接得到可以看到如下题目
捕获.PNG
- 测试思路:按提示将数字添加到网址的后方 例如:http://www.heibanke.com/lesson/crawler_ex00/75618
捕获.PNG
- 测试思路:发现会有新的数字跳转,同理将数字替换之前的网址上
捕获.PNG
- 测试思路:由此可以猜测出该关玩法应该是,将网页显示的数字添加到网页url上,直到找到成功的为止 由此开始写代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Word : python can change world!
# @Version : python3.6
import requests
import re
from bs4 import BeautifulSoup
def get_html(page):
url='http://www.heibanke.com/lesson/crawler_ex00/' str(page)
res=requests.get(url).text
return res
def main():
page=''
print('开始第一关')
while True:
req=get_html(page)
if u'恭喜' in req:
print('成功啦!可以试着将最后显示的数字填进网址里去看看哦!')
break
else:
soup=BeautifulSoup(req,"html.parser")
html=soup.h3.string
num=re.findall(r'd ',html)
page=str(num.pop())
print(page)
if __name__ == '__main__':
main()
成功后可以获取下一关的地址链接哦!试试吧,如果你也对python爬虫有兴趣,欢迎交流指正哦!继续第二关的爬虫闯关游戏下一关地址
第二关
访问链接得到可以看到如下题目
捕获.PNG
- 测试思路:按提示随便写个昵称和30以内数字的密码
捕获.PNG
- 测试思路:发现密码错误,由此可直到需要将1-30为密码遍历下去,直到成功!
代码思路
:通过request模块的post提交data参数,通过re模块抓取成功后的信息!就是这么简单!
由此开始写代码:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Word : python can change world!
# @Version : python3.6
import requests
import re
def main():
url='http://www.heibanke.com/lesson/crawler_ex01/'
num=0
a=30
while a >0:
data={'username':'admin','password':num}
res=requests.post(url,data=data).text
if u'错误' in res:
print(num,'错误')
num=num 1
a=a 1
else:
print(num,'正确')
title=re.findall("<title>(.*?)</title>",res)
word=re.findall("<h1>(.*?)</h1>",res)
word2=re.findall("<h3>(.*?)</h3>",res)
html=re.findall('<a href="(.*?)" class="btn btn-primary">下一关</a>',res)
print('n'.join([title[0], word[0], word2[0],'下一关地址是','http://www.heibanke.com' html[0]]))
break
if __name__ == '__main__':
main()
过关标识
轻松过关有木有!如果你也对python爬虫有兴趣,欢迎交流指正哦!继续第三关的爬虫闯关游戏下一关地址
第三关
访问链接得到可以看到如下题目:
捕获.PNG
- 测试思路:页面跳转到http://www.heibanke.com/accounts/login/?next=/lesson/crawler_ex02/,看来要先注册一个账号
捕获.PNG
- 测试思路:注册一个账号,登陆进去,发现一个记账点,但网页还没有跳转到题目网页, 还不知道玩法如何
捕获.PNG
- 测试思路:因为注册账号登陆了,重新访问下刚开始的题目地址http://www.heibanke.com/lesson/crawler_ex02/,发现可以开始玩了
- 测试思路:很明显长的和第二关有点像,但题目说多了两层保护,是哪两层呢?首先,多了账号登陆一层,还有一层是什么呢?重新登陆,打开firebug测试一下
登录时的post表单参数
- 测试思路:所以第一层request模块post访问,还有一个csrfmiddlewaretoken参数,可csrfmiddlewaretoken参数如何获得呢?是随机的还是固定的?回到登陆界面再探个究竟!
csr参数
- 测试思路:很明显每次在访问登录界面时会自动生成csrfmiddlewaretoken,是随机的!登录进去找第二层!同理开着firebug刷新页面,看看是不是也是有别的参数带入
捕获.PNG
- 测试思路:好吧,找到了在闯关登录界面,也会自动生成一个csr参数,不过刷新了几次都没变 很大可能是固定了,或许这就是第二层保护吧!
代码思路
:由此总结可知,通过request模块访问login页面,获取csr随机参数,再带入账号密码一起post提交表单登入,登入之后再获取csr固定参数,再带入账号,和随机的30以内的数字密码,只要密码对了就过关了!
由此开始写代码:
代码语言:javascript复制import requests
import re
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Word : python can change world!
# @Version : python3.6
def main():
login_data={'username':'user','password':'password'}
url='http://www.heibanke.com/lesson/crawler_ex02/'
login_url='http://www.heibanke.com/accounts/login/?next=/lesson/crawler_ex02/'
r2=requests.get(login_url)
c2=r2.cookies
login_data['csrfmiddlewaretoken']=c2['csrftoken']
r3=requests.post(login_url,data=login_data,allow_redirects=False,cookies=c2)
c3=r3.cookies
pass_data={'username':'user','csrfmiddlewaretoken':c3['csrftoken']}
for passwd in range(31):
pass_data['password']=pas
swd
r5=requests.post(url,pass_data,cookies=c3)
text=r5.text
result=re.findall(r'密码错误',text)
if u'密码错误' in text:
print("%s密码错误"%passwd)
else:
print("%s密码正确"%passwd)
title=re.findall("<title>(.*?)</title>",text)
word=re.findall("<h1>(.*?)</h1>",text)
word2=re.findall("<h3>(.*?)</h3>",text)
html=re.findall('<a href="(.*?)" class="btn btn-primary">下一关</a>',text)
print('n'.join([title[0], word[0], word2[0],'下一关地址是','http://www.heibanke.com' html[0]]))
break
if __name__ == '__main__':
main()
过关标识
轻松过关有木有!如果你也对python爬虫有兴趣,欢迎交流指正哦!继续第四关的爬虫闯关游戏[下一关地址]:(http://www.heibanke.com/lesson/crawler_ex03/)
第四关
访问链接得到可以看到如下题目
图片.png
- 测试思路:看来和第三关第一步一样,都是要先登录哟!随便输个密码试试,毕竟还不知道密码多少位,怎么玩
捕获.PNG
- 测试思路:密码错误会提示进入一个链接,点击发现有一个列表,是位置和密码值的对应,而且刷新一下竟然会变!猜测是随机产生,应该可以就单独一页进行密码爬取!再组成最后的密码
- 测试思路:翻页发现没有超过100 的数字,估计密码最大就是100位吧,而且访问过程特别慢 可以使用多线程进行快速抓取!
捕获.PNG
代码思路
:由此总结可知,通过request模块访问login页面,获取csr随机参数,再带入账号密码一起post提交表单登入,登入之后访问密码列表,爬取密码位置,和对应数值,再组成100位的密码,再带入账号密码登录,只要密码对了就过关了!
由此开始写代码:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Word : python can change world!
# @Version : python3.6
import requests
from bs4 import BeautifulSoup
import threading
from queue import Queue
dict1={}
vlauess=[]
web1="http://www.heibanke.com/accounts/login"
web2="http://www.heibanke.com/lesson/crawler_ex03/pw_list/"
web3="http://www.heibanke.com/lesson/crawler_ex03/"
global queuewz
global queuemm
queuewz=Queue()
queuemm=Queue()
class mythreads(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
work()
while not queuemm.empty():
try:
dict1[str(queuewz.get())]=queuemm.get()
print(dict1)
print("字典长度为%s"%len(dict1))
if int(len(dict1)) ==100:
print("凑到100啦!")
for i in range(1,101):
vlauess.append(dict1[str(i)])
c=vlauess[:100]
zzmm=''.join(c)
print("密码为%s"%zzmm)
print("正在登录.......")
dataWebsite1 = {'username': 'user','password': zzmm}
s=login_get()
res=s.post(web3, data=dataWebsite1).text
if u'恭喜' in res:
title=re.findall("<title>(.*?)</title>",res)
word=re.findall("<h1>(.*?)</h1>",res)
word2=re.findall("<h3>(.*?)</h3>",res)
html=re.findall('<a href="(.*?)" class="btn btn-primary">下一关</a>',res)
print('n'.join([title[0], word[0], word2[0],'下一关地址是','http://www.heibanke.com' html[0]]))
break
else:
print("网页有问题哦!可以尝试手动将获得的正确密码登入进去哦!")
break
else:
main()
except IndexError:
print("例表空了,下一页!")
def login_get():
try:
s = requests.Session()
r=s.get(web1) # 访问登录页面获取登录要用的csrftoken
token1 = r.cookies['csrftoken'] # 保存csrftoken
# 将csrftoekn存入字段csrfmiddlewaretoken
dataWebsite1 = {'username': 'user',
'password': 'password',
'csrfmiddlewaretoken': token1
}
res=s.post(web1, data=dataWebsite1)
except KeyError as e:
pass
return s
def get_html(s):
r=s.get(web2)
res=r.text
return res
def get_dict(res):
soup=BeautifulSoup(res,"html.parser")
for a in soup.find_all('td',attrs={'title':'password_pos'}):
wz=(a.string)
queuewz.put(wz)
for b in soup.find_all('td',attrs={'title':'password_val'}):
mm=(b.string)
queuemm.put(mm)
def work():
res=get_html(s)
get_dict(res)
def main():
global s
s=login_get()
threads=[]
threads_count=10
for i in range(threads_count):
threads.append(mythreads())
for t in threads:
t.start()
for t in threads:
t.join()
if __name__ == '__main__':
main()
账号为user,密码可得为:9263152516931477925579303326531490163668774566288173618538253675264972338183086744513535774895069524
登录过关标识
这里线程我给的是10,访问速度不算快,但比多线程快很多哦,写的有点杂乱,继续第五关的爬虫闯关游戏[下一关地址]:(http://www.heibanke.com/lesson/crawler_ex04/)
第五关
访问链接可以看到如下视图:
捕获.PNG
- 测试思路:看来和第四关第一步一样,都是要先登录哟!先建个session,然后到需要添加验证码的这个页面,手动随便输入账号密码firebug抓包看看表单参数
捕获.PNG
- 测试思路:username和password是需要输入的,captha_1为验证码,看来需要用到ocr来识别验证码,csr参数是登录开始时就可以获取,captha_0参数可以在源码中找到会随机变化
- 测试思路:手动将验证码另存为png图片,验证码不会刷新,看来可以用下载验证码再识别的方法,而不需要截图页面读取验证码,这里需要安装第三方tesseract-ocr模块,同时要训练机器学习识别验证码,具体识别需要的软件和步骤,可以点击这里查看
- 测试思路:需要从题目中下载大概100个样本,给机器学习识别,具体代码如下:
import requests
import re
import urllib.request
web_login="http://www.heibanke.com/accounts/login/?next=/lesson/crawler_ex04/"
web_ex04="http://www.heibanke.com/lesson/crawler_ex04/"
def get_s():
s=requests.Session()
s.get(web_login)
token1 = s.cookies['csrftoken'] # 保存csrftoken
# 将csrftoekn存入字段csrfmiddlewaretoken
dataWebsite1 = {'username': 'user',
'password': 'password',
'csrfmiddlewaretoken': token1
}
s.post(web_login, data=dataWebsite1)
return s
def get_img(s):
for i in range(1,101):
res=s.get(web_ex04).text
img=re.findall('![]((.*?))',res)
img_html='http://www.heibanke.com' str(img[0])
print("这是第%s张验证码"%i)
urllib.request.urlretrieve(img_html,"%s.png"%i)
# print(img_html)
def main():
s=get_s()
get_img(s)
if __name__ == '__main__':
main()
- 测试思路:通过tesseract可以对样本依次进行识别,如果机器没有学习,默认字体为eng,识别率惨不忍睹,所以可以用jTessBoxEditor软件对tesseract识别的答案进行纠正保存,提高识别率,这就是机器学习的过程。然后将训练过程生成一个num字体文件,用tesseract调用num字体进行识别。具体识别需要的软件和步骤,可以点击这里查看
以下是需要用到的cmd命令我把它整理成bat文件
代码语言:javascript复制rem 执行改批处理前先要目录下创建font_properties文件 ,内容为font 0 0 0 0 0
echo Run Tesseract for Training..
tesseract.exe num.font.exp0.tif num.font.exp0 nobatch box.train
echo Compute the Character Set..
unicharset_extractor.exe num.font.exp0.box
mftraining.exe -F font_properties -U unicharset -O num.unicharset num.font.exp0.tr
echo Clustering..
cntraining.exe num.font.exp0.tr
echo Rename Files..
rename normproto num.normproto
rename inttemp num.inttemp
rename pffmtable num.pffmtable
rename shapetable num.shapetable
echo Create Tessdata..
combine_tessdata.exe num.
echo. & pause
- 需要用到的命令:tesseract num.font.exp0.tif num.font.exp0 batch.nochop makebox 1.先创建font_properties文件 ,内容为font 0 0 0 0 0 2.执行如上批处理文件生成num.tessdata字体文件 3.将字体文件复制到tesseract字体目录下 4.在cmd中tesseract --list-langs 可以看到新的num文件 具体内容可以点击这里
代码思路
:由此总结可知,通过request模块访问login页面,获取csr随机参数,再带入账号密码一起post提交表单登入,登入之后下载验证码用pytesseract模块调用tesseract识别验证码,并提交给captha_1参数,再加上csr和captha_0参数以post方式访问,password从0开始遍历数字,只要密码对了就过关了!
由此开始写代码:
代码语言:javascript复制#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @word : python will change the world!
# @Version : 3.6
import requests
import re
import urllib.request
import pytesseract
from PIL import Image
import sys
web_login="http://www.heibanke.com/accounts/login/?next=/lesson/crawler_ex04/"
web_ex04="http://www.heibanke.com/lesson/crawler_ex04/"
def get_s():
s=requests.Session()
s.get(web_login)
token1 = s.cookies['csrftoken'] # 保存csrftoken
dataWebsite1 = {'username': 'user',
'password': 'password',
'csrfmiddlewaretoken': token1
}
s.post(web_login, data=dataWebsite1)
return s
def cleanyzm(yzm,s,num):
a=yzm
if len(a.replace(' ',''))!=4:
print("打回")
get_img(s,num)
else:
yzm=a.upper()
print(yzm)
return yzm
def get_img(s,num):
res=s.get(web_ex04).text
img=re.findall('![]((.*?))',res)
img_html='http://www.heibanke.com' str(img[0])
print("验证码下载完毕")
urllib.request.urlretrieve(img_html,"yzm.png")
yzm=pytesseract.image_to_string(Image.open('yzm.png'),lang='num')
cshu=re.findall(r'img src="/captcha/image/(.*)/" alt="captcha"', res)[0]
token1 = s.cookies['csrftoken']
yzm=cleanyzm(yzm,s,num)
dataWebsite1 = {'username': 'user',
'password': num,
'csrfmiddlewaretoken': token1,
'captcha_0':cshu,
'captcha_1':yzm
}
res=s.post(web_ex04, data=dataWebsite1).text
if u'密码错误' in res:
print(num,"密码错误")
num=num 1
get_img(s,num)
else:
if u'验证码输入错误' in res:
print(num,"验证码输入错误!")
get_img(s,num)
else:
print(num,"成功!")
title=re.findall("<title>(.*?)</title>",res)
word=re.findall("<h1>(.*?)</h1>",res)
word2=re.findall("<h3>(.*?)</h3>",res)
print('n'.join([title[0],word[0],word2[0]]))
sys.exit(0)
def main():
s=get_s()
#global num
num=0 ########设置开始运行的密码,直到成功程序退出!
get_img(s,num)
if __name__ == '__main__':
main()
账号为user密码可得为一个二位数字
登录过关标识
这里我用的是pytesseract模块,识别率也还不是很理想,不断循环直至验证码读对为止,还好下载验证码不会刷新,不然就只能用selenium模块进行操控浏览器进行模拟登陆了,这也不乏一种思路哦!感兴趣的朋友可以试试,如果你也对python爬虫有兴趣,欢迎交流指正,相互学习哦!
参考资料
[1]
游戏开始地址: http://www.heibanke.com/lesson/crawler_ex00/