本篇主要讲述验证码的验证流程,包括如何验证码的实现、如何获取验证码、识别验证码(这篇是人来识别,机器识别放在下篇)、发送验证码。一样以一个例子来讲明。目标网址 http://icp.alexa.cn/index.php(查询域名备案信息)php
1.验证码的实现:python
简单的说,验证码就是一张图片,图片上有字符串。网站是如何实现的呢?有WEB基础的人可能会知道,每一个浏览器基本都有cookie,做为此次回话的惟一标示。每次访问网站,浏览器都会把这个cookie发送给服务器。验证码就是和这个cookie绑定到一块儿的。如何理解呢?举个例子,如今有网站W,有A和B两我的,同时访问W,W给A返回的验证码是X,给B返回的验证码是Y,这两个验证码都是正确的,可是若是A输入了B的验证码,确定验证不经过。那服务器是怎么区分A和B呢,就是用到的cookie。再举个例子,有些网站你登陆一次以后,下次继续访问可能就自动登录了,也是用cookie来标示惟一身份的,若是清除了cookie也就没法自动登录了。cookie具体是什么生成的,咱们没必要关心,只须要知道是一长串字符串就好了,你的和别人的都不同。(例子中的目标网址并非用cookie,而是用的其余方式,因此可能会存在一些BUG)浏览器
服务器后台生成验证码的流程就很容易理解了:首先,生成一个随机字符串,而后和cookie绑定,而后写到图片上返回给你。那么,如何生成一个图片验证码呢?下面是一个简单的生成验证码源码:服务器
from PIL import Image import ImageFilter,ImageDraw,ImageFont import random width = 80 height = 40 font = ImageFont.truetype('C:\\Windows\\Fonts\\AdobeFangsongStd-Regular.otf', 28) image = Image.new("RGB",(width,height),(0,0,0)) draw = ImageDraw.Draw(image) for t in range(4): draw.text((20*t,10),`random.randint(0,9)`,font=font,fill=(255,255,255)) image.show()
代码说明:cookie
a).PIL是python的图片库模块,须要本身安装网络
b).ImageFont.truetype()是选择字体dom
c).Image.new("RGB",(width,height),(0,0,0))新建一个Image,背景色是白色((0,0,0)就表明的颜色),若是须要别的颜色,可本身查询颜色代码。window自带的画板就能够看到:函数
d).random.randint(0,9)随机数 范围大于等于0,小于等于9学习
e).draw.text((20*t,10),`random.randint(0,9)`,font=font,fill=(255,255,255),anchor=False) 第一个参数表明位置,带二个表明内容,第三个表明字体,第四个表明字体颜色测试
f).image.show()显示图片,第一词会提示选择默认图片查看器。
运行结果以下图:
2).验证码的获取
a).分析目标网站,能够看到当鼠标点击验证码那个输入框时会显示验证码,如图:
那么获取验证码的请求是什么?以及请求发送的时间?(验证码显示的时间不必定是验证码获取的时间,虽然这个例子中是,觉得验证码多是页面刚开始的时候一块儿加载的,只是一直被隐藏)。火狐浏览器F12打开控制台,找到网络标签,刷新页面,能够看到以下图所示:
并无发现获取验证码的请求,那么咱们点击验证码的那个输入框,发现多了一个请求,没错,这就是获取验证码的请求。
b).下面咱们开始分析这个请求,首先点击这个请求,能够看到以下图所示:
完整URL:http://icp.alexa.cn/captcha.php?q=sina.com.cn&sid=82&icp_host=sxcainfo。能够看到三个参数:
q=sina.com.cn:查询的域名
sid=82:这个ID暂时不知道是什么,后面查看JS源代码会看到
icp_host:这个暂时也不知道。
这三个参数,那些是必须的呢?能够一个一个测试。测试方法就是删掉某个元素,而后再发请求。测试发现,三个参数缺省均可以获取到验证码,获取到验证码,不表明验证码可用,由于,没有与某些相似cookie的值绑定到一块儿,它就和图片没有任何区别,不具有验证的功能。经我测试,(测试很简单,不过要用到后面的东西,看完这篇,就知道怎么测了),这三个参数都须要。在测试的过程当中,我发现了sid就是一个随机数,没有什么特殊含义,基本能够肯定能够随便输入:js代码以下:
icp_host的取值有不少:sccainfo、ahcainfo、jscainfo......有没有发现什么规律?首先八个字母,最后六个都是cainfo,那么前面两个表明什么?sc=四川、ah=安徽、js=j江苏。因此,咱们能够猜想这个是省份的简写。那这个值有什么用呢?做用一,若是不按这个规则输入字符串(好比,aaaaaaaa),就获取不到验证码;做用二,验证码就是和这个绑定的。也就是说,你获取验证码的时候用sccainfo,那么验证的时候也要用sccainfo。
分析完参数,而后再分析请求头,方法和参数的分析方法同样,一个个删除,看能不能获取正确的结果。这个时候,能够本身写python代码测试,具体代码以下:
#encoding=utf8 import urllib2 from PIL import Image import cStringIO getCode_url = "http://icp.alexa.cn/captcha.php?q=163.com&sid=0&icp_host=hncainfo" header={"Referer":"http://icp.alexa.cn/captcha.php?q=163.com&sid=0&icp_host=hncainfo"} # header['Host']="icp.alexa.cn" # header['User-Agent']="Mozilla/5.0 (Windows NT 6.3; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0" header['Cache-Control']="max-age=0" request = urllib2.Request(getCode_url,headers=header) res = urllib2.urlopen(request).read() image = Image.open(cStringIO.StringIO(res)) image.show()
代码说明:
a).cStringIO python的流模块,不管是图片、文本、音频、视频都是流文件,能够相互转化。这里的做用是将图片流还原成图片
b).header中添加参数可直接用header['']="",这样就能够测试了。具体哪些参数必须,本身测试。
运行结果:
3).检验验证码
a).分析目标网站,寻找检验验证码的请求。咱们在输入框输入正确的验证码,点击备案查询,如图所示:
能够看到控制台中多了一个请求
点击请求,查看请求详情:http://icp.alexa.cn/index.php?q=163.com&code=65a89c&icp_host=lncainfo
三个参数:
q=163.com:查询的域名,必不可少
code=65a89c:验证码,必不可少
icp_host=lncainfo:和获取验证码相对应
而后再分析header,与上面的方法同样。这两次检验不一样的是:检验获取验证码时,是本身写代码获取验证码,而后放到网站上检验,验证码的正确性(必须保证icp_host一致);检验检查验证码时,是用网站获取验证码,填到代码里面,看看参数对不对。
验证代码以下:
#encoding=utf8 import urllib2 checkcode_url = "http://icp.alexa.cn/index.php?q=163.com&code=N3PE37&icp_host=hncainfo" header={} # header['Pragma']="Pragma" # header['Referer']="http://icp.alexa.cn/index.php?q=163.com&code=CUXWDV&icp_host=sccainfo" header['User-Agent']="Mozilla/5.0 (Windows NT 6.3; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0" request = urllib2.Request(checkcode_url,headers=header) res = urllib2.urlopen(request).read() print res
代码说明:icp_host=hncainfo这个参数必须和你获取验证码时候的参数一致
运行结果:
若是验证码不正确或者别的地方不一致,会返回:
到此,咱们就分析完了,不过如今是把获取和验证放在两个代码中运行,怎么放在一块儿呢?代码以下:
#encoding=utf8 import urllib2 from PIL import Image import cStringIO import BeautifulSoup def getCode(domain): print "获取验证码...." getcode_url="http://icp.alexa.cn/captcha.php?q="+domain+"&sid=0&icp_host=hncainfo" getcode_headers = {} getcode_headers['Referer']="http://icp.alexa.cn/captcha.php?q=163.com&sid=0&icp_host=hncainfo" getcode_headers['Cache-Control']="max-age=0" getcode_request = urllib2.Request(getcode_url,headers=getcode_headers) getcode_res = urllib2.urlopen(getcode_request).read() image = Image.open(cStringIO.StringIO( getcode_res)) print "获取验证码成功" image.show() def checkcode(domain,code): # print "您输入的验证码为:"+`code` print "开始检查验证码..." checkcode_url = "http://icp.alexa.cn/index.php?q="+domain+"&code="+code+"&icp_host=hncainfo" checkcode_headers={} checkcode_headers['User-Agent']="Mozilla/5.0 (Windows NT 6.3; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0" checkcode_request = urllib2.Request(checkcode_url,headers=checkcode_headers) checkcode_res = urllib2.urlopen(checkcode_request).read() if(checkcode_res.count("主办单位名称")>0): print "验证成功" checkcode_soup = BeautifulSoup.BeautifulSoup(checkcode_res) print "所属单位名称:"+checkcode_soup.findAll("table")[0].findAll("tr")[0].findAll("td")[1].text.encode("utf8") else: print "验证失败" domain = raw_input("请输入域名:") getCode(domain) code = raw_input("请输入验证码:") checkcode(domain,code)
代码说明:
a).def getCode(domain) 声明一个函数,getCode是函数名,domain是参数
b).raw_input() 获取用户输入
c).在获取和验证的时候,我把icp_host都写成了hncainfo,这样就能够保证一致。
d).encode("utf8") 对变量以utf8格式编码
e).验证码要人工识别输入
运行结果:
到此,整个验证码的获取,验证都讲述完了,验证码的识别放在下一节。
说明:
a).代码仅供学习交流
b).若有错误,多多指教
c).转载请注明出处