reCAPTCHA简介

reCAPTCHA项目是由卡内基梅隆大学所发展的系统,主要目的是利用CAPTCHA技术来帮助典籍数字化的进行,这个项目将由书本扫描下来无法准确的被光学文字辨识技术(OCR, Optical Character Recognition)识别的文字显示在CAPTCHA问题中,让人类在回答CAPTCHA问题时用人脑加以识别[1]。reCAPTCHA正数字化《纽约时报》(New York Times)的扫描存文件,目前已经完成20年份的数据,并希望在2010年完成110年份的数据。2009年9月17日,Google宣布收购reCAPTCHA。这是一个伟大的项目,在发挥验证码作用的同时,使得输入验证码的人对全人类做出了贡献。

项目初衷

有江湖的地方就有爬虫,为什么我会去爬一个带有验证码的网站呢?前段时间刚买了车,但是运到店里面需要一些时间,从销售那问了车架号就一直想蠢蠢欲动,看到车托之家有人可以用车架号查询车辆生产以及配置信息,那也是一个别人开发的系统,但是不知道为什么最近一直处于瘫痪状态,好在还有英文网站可以查询。但是因为英文网站带有reCAPTCHA,而天朝又因为某些不可抗力因素导致reCAPTCHA无法使用,除非挂VPN,一般人查不了配置,那么,为什么不自己开发一个呢?

实现过程

其他爬页面的细节就不说了,主要还是说说reCAPTCHA如何爬,验证码也没想着自动识别,那太复杂了,就把验证码爬下来让用户自己输入吧,reCAPTCHA使用很简单,在页面上嵌入一段JS,然后去问谷歌这个验证码的输入正确与否就OK了,所有遇到的问题如下:

  • script标签发出的请求带有referer头,显然申请reCAPTCHA服务的时候会生成一个唯一性的token,带着token才能请求到验证码,而发送请求的时候会验证`referer头,如果不是127.0.0.1或者localhost或者申请时候填写的网址,那么谷歌就拒绝提供服务。解决办法:本身因为天朝地址无法访问谷歌服务,就准备在服务端对这些请求做一次转发,转发时候不要带上referer头即可。

  • reCAPTCHA的运行原理很简单,首先页面加载一个谷歌JS文件:http://www.google.com/recaptcha/api/challenge?k=6Ldlev8SAAAAAF4fPVvI5c4IPSfhuDZp6_HR-APV,这个k参数就是上面提到申请reCAPTCHA服务的时候给你一个唯一性的token,当然要经过服务器转发,不然天朝子民无法获得这个请求,这个JS的返回格式如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    var RecaptchaState = {
    challenge : '03AHJ_VutQSbh3e1Zy9JyHmt_Zmt83Gl7r0UpTa7Hq8KHlT7XGb1zxpMDyON6W70ZB3K2rY1kxWj31xkzVCJEy4SI-KsxOac-Rvh32JMoIT2-IX6gbAgj24p-SiYSYhHyYu00OAcePod4nf5QZuFdOWNRwZfcCkemd55F6dfJOqDTmPp-i2ySI2lId8Eo5d557NGZvpYYBmLLwFtyewzBfhpEwYJgR2L0lSA',
    timeout : 1800,
    lang : 'zh-CN',
    server : 'https://www.google.com',
    site : '6Ldlev8SAAAAAF4fPVvI5c4IPSfhuDZp6_HR-APV',
    error_message : '',
    programming_error : '',
    is_incorrect : false,
    rtl : false,
    t1 : 'Ly93d3cuZ29vZ2xlLmNvbS9qcy90aC9TMFJ2cEhDbHY2a29udUt6cUtXYkxMUnY0WHM0bEVSblphTGlucDNfelo4Lmpz',
    t2 : '',
    t3 : 'OXVBWHdpOTZlcEp....(这里是一大串类似密文的东西)'
    };

    document.write('<scr'+'ipt type="text/javascript" s'+'rc="' + RecaptchaState.server + 'js/recaptcha.js"></scr'+'ipt>');

注意这个地方有个server属性,谷歌还是挺良心的,后续发的所有请求,比如获取验证码图片或者语音的请求,host都是这个server属性所带的值,同样,这些请求需要转发,不然请求不到,在服务端获取这个JS文件时,直接把server属性替换掉,替换你自己服务器转发地址,后续的请求就都往你自己服务器上发了,既能让天朝子民访问reCAPTCHA,又能在自己的域名上爬到别人域名的reCAPTCHA验证码。

  • 谷歌毕竟是谷歌,即使爬到了验证码,他也不会让你好用,谷歌的识别能力还是挺强的,原本想带上一些随机agentx-forwarded-for之类的头来模拟我是一个代理而已,但是无一例外,都被识别为了爬虫而拒绝服务,最后采用的还是没有带上任何头,直接请求,至少服务能用,但是等到用的人多了之后,验证码就会变得非常复杂,好在还有语音验证码可以用。

总结

这次爬得不算完美,当PV超过2 300的时候,验证码就变得非常恶心了,常人一般难以识别,这块还在想办法。最后贴出这个应用实例吧:宝马中文车架号查询系统