爬虫天坑系列-百度指数爬虫

原文地址:http://blog.shenjianshou.cn/?p=170
giithub:https://github.com/TTyb/Baiduindex
最近有不少朋友跟我说,“爬虫这东西很简单啊,好像还没学就已经会了,没啥深奥的东西哦。看了你以前的教程,不就是一个队列加一些Http请求吗,不就是写写XPath和正则吗,大家还作个神箭手云爬虫出来?我本身上个厕所就写完了啊。”php

看来是时候拿出咱们压箱底多年的老干妈了,哦不,老干货了。不吓屎大家这群小学生我就不在6年级混了。html

废话很少说,所谓爬虫天坑,敢对得起这个名字的必定不能是等闲之辈。起码得是过完年老板给你扔这个任务,你儿童节还在头大的级别。今天第一课,我们就先找个最难的热热身吧:爬取百度指数的关键词搜索指数。git

先贴一个logo让你们跪拜一下github

好了,你们平身吧,我们立刻就正式开始了,想上厕所的赶忙去,否则看完这篇文章估计你就忘了怎么上厕所了。api

正式开始以前,先插个广告:若是土豪朋友不想写代码或者中途看不下去的,咱们将如下代码已经打包成一个完整的应用,你们进入神箭手的云市场搜索百度指数(http://www.shenjianshou.cn/index.php?r=market/product&product_id=500036)就能够看到应用,直接调用既可。浏览器

——————————–前方高能预警看也看不完上厕所赶忙去分割线————————————-
我们正式开始:所谓知己知彼百战不殆,咱们要先了解一下咱们的对手。我们打开百度指数
http://index.baidu.com,映入眼帘的是一个简单的输入框。好开心啊,好像不用登陆啊,输入一个关键字试一下吧,输入神箭手,回车:cookie

果真百度老司机不会让咱们那么开心的。没事没事,不就是登陆吗,也不是没作过登陆,抓包研究下请求应该不难。咱们先找一个帐号登陆看下。登陆以后继续输入神箭手:less

出来了。哈哈,不难嘛,这不就直接显示了。而后就按照之前的爬虫的教程,用XPATH获取一下数字就能够了,哈哈哈…哈哈..哈……..dom

慢着,怎么感受这个数字看着怪怪。吓得我赶忙掀开被子看看这货究竟是啥:异步

什么?这是图!!!!什么?这仍是拼图!!!!什么?这货竟然是异步的拼图!!!!

怎么样,感觉到天坑的深度没有?

那我们就一块儿来看看怎么见招拆招,用神箭手把百度指数搞定的吧。
开始具体的代码以前,咱们先在神箭手后台新建三个应用,分别是百度指数API,百度登陆爬虫,百度指数图片识别AI。

第一章 登陆应用

第一节:咱先搞定登陆
模拟登陆一直是爬虫的一个老大难问题,虽然咱们神箭手提供了智能登陆接口login函数,可是赶上复杂一些的登陆依然无能为力。固然你能够登陆后复制本机Cookie直接用,但这种雕虫小技百度想封你真得比捏死一只蚂蚁还简单。我们要有不怕苦,迎难而上的精神,死磕登陆!算了~仍是先去搜一下有没有别人写过。不搜不知道,一搜吓一跳啊。咱就随便找个源码借鉴借鉴。乔布斯老人家说过嘛,greate artist steal。
https://github.com/qiyeboy/baidulogin/blob/master/baidulogin.py
这个不错,逻辑清晰,代码干净,万能的github果真不辜负个人重望。咱们steal到神箭手平台上来。

首先咱们理清这个流程,根据这个代码咱们知道百度的登陆流程是这样的:
1.经过请求百度首页或者任意一个百度url得到百度的基础cookie。
2.请求 https://passport.baidu.com/v2/api/?getapi 得到token
3.经过 https://passport.baidu.com/v2/getpublickey 得到密码加密的key
4.经过 https://passport.baidu.com/v2/api/?login 将以前得到到的token,生成的gid,生成的时间戳,用key加密密码,来提交登陆。
5.若是返回有验证码,获取codestring并请求 https://passport.baidu.com/cgi-bin/genimage 得到验证码图片并识别。
6.经过 https://passport.baidu.com/v2/?checkvcode 来验证是否识别成功
7.若是不成功经过 https://passport.baidu.com/v2/?reggetcodestr 来切换验证码,在重复前两步。
8.再次提交 https://passport.baidu.com/v2/api/?login 看是否登陆成功。
好了,这中间很麻烦的两个地方是

  1. 验证码识别 这个神箭手提供了验证码识别的函数,调用方式以下:
    var codeUrl = "https://passport.baidu.com/cgi-bin/genimage?" + codeString;
    var codeReg = getCaptcha(71, codeUrl);
    var imgCaptchaData = JSON.parse(codeReg);
    if (imgCaptchaData && imgCaptchaData.ret > 0) {
    var result = imgCaptchaData.result;
    verifycode = encodeURI(result,"UTF-8");
    tt = (new Date()).getTime();
    var codeCheck = site.requestUrl("https://passport.baidu.com/v2/?checkvcode&token=" + token + "&tpl=mn&apiver=v3&tt=" + tt + "&verifycode=" + verifycode + "&codestring=" + codeString + "&callback=");
    var checkInfo = JSON.parse(codeCheck);
    if (checkInfo.errInfo.no != "0") {
    console.log("验证码识别错误");
    }
    continue;
    } else {
    console.log("验证码识别失败");
    continue;
    }

  2. RSA加密

当咱们获取到key以后须要对密码进行RSA加密,百度是采用的JS的开源RSA加密库,神箭手也提供了RSAEncode的方法,具体代码以下:
var pubkeyJson = site.requestUrl("https://passport.baidu.com/v2/getpublickey?token=" + token + "&tpl=mn&apiver=v3&tt=" + tt + "&gid=" + gid + "&callback=");
var pubkeyInfo = JSON.parse(pubkeyJson.replace(/'/g, """));
var pubkey = pubkeyInfo.pubkey;
var rsakey = pubkeyInfo.key;
var crypttype = "";
var rsaPassword="";
if (rsakey != "") {
crypttype = "12";
//加密密码
pubkey = pubkey.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "").trim();
rsaPassword = (RSAEncode(password, pubkey));
}
其余的都是一些基础的请求,你们能够参考github中的代码进行编写。

第二节:疯狂登陆

完成了第一节的工做以后,你觉得登陆就没问题了吗?你觉得你能够用一个账号爬到天荒地老吗?有人说限制爬取频率,这固然是一个方法,但却不是最好的解决方案。毕竟缩手缩脚,感受很受限。最好的方案固然是登陆一堆账号,获取一堆的Cookie,而后从这堆Cookie中每次随机取一个Cookie,再经过这个Cookie去访问。那咱们就须要一个新的东西:Cookie池。
咱们看下神箭手如何调用Cookie池,首先咱们须要新建一个爬虫应用专门用于登陆:
var configs = {
shareUserWithKey:"bindex",
};
configs.onUserAdded = function (use, psw, site) {
var loginResult = login(use, psw, site);
if( loginResult !="success") {
return false;
}
return true;
}
这里的login方法就是刚刚咱们写的百度登陆,而后咱们再在beforeCrawl的回调函数中反复调用如下方法:
site.addUser(user, password);
固然这里还有一个问题,若是咱们一直使用一个IP来登陆,也很容易被百度封掉,因此咱们最好打开企业代理IP接入。

经过这种形式咱们就能够创建一个可共享的Cookie池。而后咱们在百度指数API应用(下一章会详细介绍)里经过设置如下代码来共享这个Cookie池:

var configs = {
shareUserWithKey:"bindex",
multiUser: true
}
这样在这个应用中会在每次访问一个Url的周期中随机从Cookie池取一个Cookie并请求Url。经过这种形式咱们还能够把登陆和请求代码解耦合。未来还能够复用登陆代码。

第三节:问题来了,账号从哪来呢?

除了把七大姑八大姨的手机都来注册一遍之外,没什么好办法,除非…(此处省略1000个字)。

第二章:获取指数图片API

第一节:异步请求数据
终于完成了登陆,感受怎么样,是否是有点天坑的意思?哈哈,万里长征咱才走了第一步。下面咱们才真正来揭开天坑的核心:数字图片。
而后咱们继续掀被子看看这个标签是怎么来的:

貌似不难找,不过看这个URL看着就头大,感受已经被百度登陆伤害过一次以后真的无力再一个一个参数分析,咱们直接使用神箭手提供的js渲染页面的接口,直接把页面渲染出来把:

var configs = {
domains: ["index.baidu.com"],
scanUrls: ["http://index.baidu.com/?tpl=trend&word=" + encodeURI(keyword, "GBK")],
enableJS:true
}
这样咱们在afterDownloadPage中拿到的就直接是渲染好的页面了,咱们再经过正则和XPath取出数字图片的容器标签代码和Css代码(Css代码就是把图片设置成背景的style标签),之因此要拿Style标签是由于两个数字图片共享了一个Style,而这个Style在第一个数字图片的标签中,因此咱们必须抽取出这个Style标签,在分别设置给两个不一样的数字的容器标签代码。这段代码我们再下一节中给出。

第二节:渲染数据成图片

咱们拿到了数字图片的容器标签代码有什么用呢,固然是要渲染出对应的图片了。那为何咱们要这么大的弯去获得这张图呢。这一点正是百度指数能当选天坑的缘由了,咱们看一下这个图片是如何拼出来的,咱们看下这段HTML代码。






咱们能够看到这里有两个imgval标签,imgval是用来当蒙版的,能够从一张背景图中抠出须要的部分,而imgtxt则是显示图片的,这里又有一个margin-left用来具体调整整张图要显示的位置。

而最最最变态的是,两个标签并非两个数字,而是三个数字!这就说明咱们不可能一个一个数字去识别,必须做为一个总体图片来识别了。

咱们知道PhantomJS这类Headless的浏览器都有渲染Html代码成图片的功能,神箭手渲染JS基于PhantomJS固然也支持这个功能,并且咱们的调用接口更简单只须要调用site.renderImage方法既可实现将代码渲染成图片的功能,

下面是结合第一节的完整代码以下:

var sevenReg = /class="mtable profWagv">(.+?)</table>/;
var sevenMatch = sevenReg.exec(indexInfo);
if(sevenMatch) {
var sevenInfo = extractList(sevenMatch[1],"//*[@class='ftlwhf enc2imgVal']");
var styleReg = /(

' if(styleMatch) { var html = sevenHtml + sevenInfo[0].substring(0,sevenInfo[0].length-7) +styleMatch[1] + "
"; var base64 = site.renderImage(html, 120, 25); index.week_all_index = base64ToImg(base64,site); var html2 = sevenHtml + sevenInfo[1].substring(0,sevenInfo[1].length-7) +styleMatch[1] + "
相关文章
相关标签/搜索