Python 爬虫入门(四)—— 验证码上篇(主要讲述验证码验证流程,不含破解验证码)

  本篇主要讲述验证码的验证流程,包括如何验证码的实现、如何获取验证码、识别验证码(这篇是人来识别,机器识别放在下篇)、发送验证码。同样以一个例子来说明。目标网址 http://icp.alexa.cn/index.php(查询域名备案信息)

  1.验证码的实现:

  简单的说,验证码就是一张图片,图片上有字符串。网站是如何实现的呢?有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()

  代码说明:

    a).PIL是python的图片库模块,需要自己安装

    b).ImageFont.truetype()是选择字体

    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).转载请注明出处

    

  

    

    

时间: 2024-10-13 08:05:25

Python 爬虫入门(四)—— 验证码上篇(主要讲述验证码验证流程,不含破解验证码)的相关文章

转 Python爬虫入门四之Urllib库的高级用法

静觅 » Python爬虫入门四之Urllib库的高级用法 1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Headers 的属性. 首先,打开我们的浏览器,调试浏览器F12,我用的是Chrome,打开网络监听,示意如下,比如知乎,点登录之后,我们会发现登陆之后界面都变化了,出现一个新的界面,实质上这个页面包含了许许多多的内容,这些内容也不是一次性就加载完成的,实质上是执行了好多次请求,一般

[转载]Python爬虫入门四之Urllib库的高级用法

转自:http://cuiqingcai.com/954.html 1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Headers 的属性. 首先,打开我们的浏览器,调试浏览器F12,我用的是Chrome,打开网络监听,示意如下,比如知乎,点登录之后,我们会发现登陆之后界面都变化了,出现一个新的界面,实质上这个页面包含了许许多多的内容,这些内容也不是一次性就加载完成的,实质上是执行了好多次请

Python爬虫入门之Urllib库的高级用法

1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Headers 的属性. 首先,打开我们的浏览器,调试浏览器F12,我用的是Chrome,打开网络监听,示意如下,比如知乎,点登录之后,我们会发现登陆之后界面都变化了,出现一个新的界面,实质上这个页面包含了许许多多的内容,这些内容也不是一次性就加载完成的,实质上是执行了好多次请求,一般是首先请求HTML文件,然后加载JS,CSS 等等,经过多次

Python爬虫入门七之正则表达式

在前面我们已经搞定了怎样获取页面的内容,不过还差一步,这么多杂乱的代码夹杂文字我们怎样把它提取出来整理呢?下面就开始介绍一个十分强大的工具,正则表达式! 1.了解正则表达式 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个"规则字符串",这个"规则字符串"用来表达对字符串的一种过滤逻辑. 正则表达式是用来匹配字符串非常强大的工具,在其他编程语言中同样有正则表达式的概念,Python同样不例外,利用了正则表达式,我

转 Python爬虫入门七之正则表达式

静觅 » Python爬虫入门七之正则表达式 1.了解正则表达式 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑. 正则表达式是用来匹配字符串非常强大的工具,在其他编程语言中同样有正则表达式的概念,Python同样不例外,利用了正则表达式,我们想要从返回的页面内容提取出我们想要的内容就易如反掌了. 正则表达式的大致匹配过程是:1.依次拿出表达式和文本中的字符比较,2.如果每一个

Python爬虫入门之正则表达式

在前面我们已经搞定了怎样获取页面的内容,不过还差一步,这么多杂乱的代码夹杂文字我们怎样把它提取出来整理呢?下面就开始介绍一个十分强大的工具,正则表达式! 1.了解正则表达式 正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个"规则字符串",这个"规则字符串"用来表达对字符串的一种过滤逻辑. 正则表达式是用来匹配字符串非常强大的工具,在其他编程语言中同样有正则表达式的概念,Python同样不例外,利用了正则表达式,我

Python爬虫入门教程:博客园首页推荐博客排行的秘密

1. 前言 虽然博客园注册已经有五年多了,但是最近才正式开始在这里写博客.(进了博客园才知道这里面个个都是人才,说话又好听,超喜欢这里...)但是由于写的内容都是软件测试相关,热度一直不是很高.看到首页的推荐博客排行时,心里痒痒的,想想看看这些大佬究竟是写了什么文章这么受欢迎,可以被推荐.所以用Python抓取了这100位推荐博客,简单分析了每个博客的文章分类,阅读排行榜,评论排行榜及推荐排行榜,最后统计汇总并生成词云.正好这也算是一篇非常好的Python爬虫入门教程了. 2. 环境准备 2.1

Python爬虫利器四之PhantomJS的用法

前言 大家有没有发现之前我们写的爬虫都有一个共性,就是只能爬取单纯的html代码,如果页面是JS渲染的该怎么办呢?如果我们单纯去分析一个个后台的请求,手动去摸索JS渲染的到的一些结果,那简直没天理了.所以,我们需要有一些好用的工具来帮助我们像浏览器一样渲染JS处理的页面. 其中有一个比较常用的工具,那就是 PhantomJS Full web stack No browser required PhantomJS is a headless WebKit scriptable with a Ja

Python爬虫实战四之抓取淘宝MM照片

福利啊福利,本次为大家带来的项目是抓取淘宝MM照片并保存起来,大家有没有很激动呢? 最新动态 更新时间:2015/8/2 最近好多读者反映代码已经不能用了,原因是淘宝索引页的MM链接改了.网站改版了,URL的索引已经和之前的不一样了,之前可以直接跳转到每个MM的个性域名,现在中间加了一个跳转页,本以为可以通过这个页面然后跳转到原来的个性域名,而经过一番折腾发现,这个跳转页中的内容是JS动态生成的,所以不能用Urllib库来直接抓取了,本篇就只提供学习思路,代码不能继续用了. 之后博主会利用其它方