JB的Python之旅-爬虫篇-图形验证码(3)-- 验证码的生成了解下

前言

最近在看怎么绕过图形验证码,虽然有思路,可是有点吃力,估计还要折腾几天,内心就想吐槽:验证码真难搞的;
这不,既然如今还没搞定验证码,那要不看看验证码是怎么生成的?原理是怎么处理的?
因而乎就有了此篇,写的不是很好,求各大神指教下;
php

前几天原本也想本身搞个网站,就去了解下备案是什么鬼,而后就找到这么一个网站:
http://icp.alexa.cn/index.phphtml

用来查询备案的,这里面也有验证码,那就用这个网站先玩玩吧; python

对了,这里的验证码指的是图形验证码web

流程

正常的流程:
验证码于服务器端生成,发送给客户端,并以图像格式显示。
客户端提交所显示的验证码,客户端接收并进行比较,若比对失败则不能实现登陆或注册,反之成功后跳转相应界面;
api

若是真这么简单,是否是用穷举的方式就能破解了?
浏览器

有web基础的人可能会知道,每一个浏览器都会有cookie,是做为此次回话的惟一标示;
服务器

cookie

防止有同窗不知道,先简单介绍下cookie:
cookie

1. 什么是Cookie,它的用途是什么?
Cookies是一些存储在用户电脑上的小文件。
它是被设计用来保存一些站点的用户数据,这样可以让服务器为这样的用户定制内容,后者页面代码可以获取到Cookie值而后发送给服务器。
好比Cookie中存储了所在地理位置,之后每次进入地图就默认定位到改地点便可。app

2. Cookie是何时生成的,完整的生成、传递和使用过程是怎么样的?
写数据到Cookie中一般是在一个页面被加载的时候,好比提交按钮被按下,后台处理完请求跳转到相应页面后会把Cookie值带回来;
以下是一个例子:dom

  • 在浏览器地址栏输入了一个站点,而后浏览器会发送请求到站点的Web服务器请求该页面
  • 与此同时,浏览器会在我的电脑上行查找和该站点对应的Cookie文件,若是发现了就会把里面的键值对内容所有发送给Web服务器,若是没找到则不发送。
  • 页面服务器接收到了Cookie的数据后,能够利用这些数据决定返回到前台的内容
  • 若是没键值对被Web服务器接收到,站点就知道该用户没有访问过,就会为这个访问地址新建一个ID而且发送一些键值对给前台,这些值会被放在此次响应中的Header带给浏览器,浏览器端因而有了Cookie的值
  • 任何到服务的访问和数据请求均可能很对Cookie中的键值对进行修改

实现

大体了解下cookie,不至于那么不清不楚;那就继续拉;

通常来讲,每次访问网址,浏览器都会把cookie发送给服务器,而验证码就是和这个cookie绑定在一块儿的;
举个例子:

  • 如今有网址T,有用户A和B两我的同事访问T
  • T给A返回的验证码是X,给B返回的验证码是Y,这两个验证码都正确
  • 若是A输入B的验证码,是验证不经过的

那服务器怎么区分A和B?那就是用cookie;

cookie是标示惟一身份的,好比有些网站,登陆一次后会自动登陆,可是若是清除了cookie,就没法自动登陆了,并且这cookie是个别人不同的;

说到这里,服务器后台生成验证码的流程就很容易理解了:

  • 先随机生产一个随机字符串
  • 而后和cookie绑定
  • 再写到图片上返回给你

那,怎么生成一个图片验证码?

生成图片验证码

from PIL import Image,ImageDraw,ImageFont
#PIL是python的图片库模块
import random
#随机函数

width = 80
height = 40
font = ImageFont.truetype('C:\\Windows\\Fonts\\STFANGSO.ttf', 28)
#选择字体
image = Image.new("RGB",(width,height),(120,10,200))
#新建一个Image,背景色是黑色(000),若是须要别的颜色,本身修改便可;图片大小就是开始定义的80X40
draw = ImageDraw.Draw(image)
#建立一个能够在给定图像上绘图的对象
for t in range(4):
    #4是表明几位,须要须要4位数字的验证码,这里输入4,须要10位,就10
    draw.text((20*t,10), repr(random.randint(0, 9)), font=font, fill=(255, 255, 255))
    #random.randint(0, 9),随机数,0-9
    #第一个参数表明位置,第二个表明内容,第三方表明字体,第四个表明字体颜色
image.show()
#显示图片
复制代码

效果图:

验证码就这样生成啦~

验证码的获取

回到一开始的网站:http://icp.alexa.cn/index.php

打开后发现,网页自动就显示验证码了,有办法获取到这个验证码吗?F12刷新一波试试

有一个这样的请求,点击后的确就是验证码的图片了;

连接以下:
http://www.alexa.cn/api/icp/vcode?host=hcainfo&flag=f419510445e39e61cc32a7efd7552ed1&R=0.37766116804135375

从连接分析,有3个参数:

  • host=hcainfo
  • flag = f419510445e39e61cc32a7efd7552ed1
  • R=0.37766116804135375

嗯,一脸懵逼,看不懂,先无论,咱们来测试下,看看这3个参数哪一个是必须的;
怎么测试?简单,直接copy上面的url,在浏览器打开,而后一个个参数删除,如:

  • http://www.alexa.cn/api/icp/vcode?host=gxcainfo&flag=8f7e4e73eb36c20033ed825238266823
  • http://www.alexa.cn/api/icp/vcode?host=gxcainfo
  • http://www.alexa.cn/api/icp/vcode
  • http://www.alexa.cn/api/icp/vcode?host=hcainfo&flag=&R=

还能够多试试排列组合,最终得出一个结论:host=gxcainfo是必须的,flag跟R不是必须的,空或者没有参数,都不影响获取验证码;

可是,能获取到验证码,不表明该验证码是可用的,由于若是没有与某些相似cookie的东西绑定在一块儿的话,那它自己就只是图片而已,没特殊含义,也不具有验证功能;

那host的值呢?尝试了一下,把host的值改为其余乱七八糟的,也同样获取不到验证码,这里面啥状况;

把网页刷新,每次刷新,host的值都在变化,好比ahcainfo、gxcainfo、ecainfo,若是不刷新网页,host的值则一直不变;
经过上面3个host的值,发现一点疑问,都是8个字母,并且后面六位都是cainfo,只有前面两个在变;ah\gx,给人感受就是安徽跟广西?可是ec想不出,怎么感受,有点像省份的意思?
亲自试了下,修改为gd,hn也能获取到验证码,莫非真是省份?那ec是啥??

这里继续猜就没意义了,但可知的是:
1)没有host这个值就获取不到验证码;
2)及时有host,值不对也是获取不到验证码;
3)那是否是说明,验证码是跟这个值绑定的?

url参数就到这里了,接下来请求头吧~
没太特别,直接把整个请求头copy过来用就好了:

import requests
from PIL import Image
import io

getCode_url = "http://www.alexa.cn/api/icp/vcode?host=hcainfo&flag=f419510445e39e61cc32a7efd7552ed1&R=0.37766116804135375"
header = {
    "Referer":"http://icp.alexa.cn/",
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"
}

response = requests.get(getCode_url,headers=header).content
image = Image.open(io.BytesIO(response))
image.show()
复制代码

这上面的代码,好像没什么特别,应该不须要说明的;

运行的结果就是:

总体的代码:

import requests
from PIL import Image
import io

def getCode(url):
    print("获取验证码")
    getCode_url = "http://www.alexa.cn/api/icp/vcode?host=jlcainfo&flag=61684048f21350aa2767b82315a0f487&R=0.5917477648057996"
    header = {
        "Referer":"http://icp.alexa.cn/",
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"
    }

    response = requests.get(getCode_url,headers=header).content
    image = Image.open(io.BytesIO(response))
    print("获取验证码成功")
    image.show()

def checkcode(url,code):
    print("开始检查验证码")
    checkcode_url = "http://www.alexa.cn/home/index/query?token=1a63a83b2xwDdXlEmmIldi-Cx729izemOE54BDjY8jnT-JCvU3Atg0W1gCrBVbMSs-O&flag=61684048f21350aa2767b82315a0f487&host=jlcainfo&flag&domain=qq.com&type=icp&type=icp&vcode="+code
    header = {
        "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "Accept-Encoding":"gzip, deflate",
        "Accept-Language":"zh-CN,zh;q=0.9",
        "Connection":"keep-alive",
        "Cookie":"SL_GWPT_Show_Hide_tmp=1; SL_wptGlobTipTmp=1; exi_query_history=nseyfqfp4SgNKMagNO-DctlkEDqameDvLLDbwUIuYCiHNkoLJPniHTUs0RIAq5jNEZ8ojjeoe8W8y1Df6vuMiy8r-H37690i99d0LZ3iyTWMVmstIOcGqb5H-DY1k2Gn3FNdj02TwpVtlca1b1lrvrdSfE-HbUGwP3Lfex0D9Hzeu48-N",
        "Host":"www.alexa.cn",
        "Referer":"http://icp.alexa.cn",
        "Upgrade-Insecure-Requests":"1",
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36"
    }
    response = requests.get(checkcode_url,headers=header)
    print(response.content)
    print(response.status_code)


if __name__ == "__main__":
    getCode("qq.com")
    code = input("请输入验证码:")
    checkcode("qq.com",code)
复制代码

原本是想弄个,自动拉取验证码图片,手动输入后自动拉取结果,可是执行的时候,仍是被网站识别出来了,想了好久还没想明白,算了留下了一个烂摊子吧~

小结

本文主要介绍了验证码是怎么生成的,原本也想结合作个机器识别的,但在调试过程,依然被网站识别出来了,折腾半天,目前无果,先弃疗,后面想到缘由再来更新吧~

谢谢你们~

相关文章
相关标签/搜索