查看原文
其他

简单聊聊工作中总结的爬虫经验

不吃夹生饭 Python爱好者社区 2019-04-07

作者:不吃夹生饭   爬虫工程师    Python爱好者社区专栏作者

知乎ID : https://www.zhihu.com/people/bu-chi-jia-sheng-fan


原本计划是开了这个专栏一周更新一篇,但是这段时间太忙了。


今天主要是说说工作中遇到的:


1.各类反爬虫

2.一些小技巧

3.我自己常用的爬虫框架

4.分享搭建一个简单的代理池


好了,进入正题。


首先是各类反爬虫和小技巧,我穿插着讲,好的,容我想想列一个表。


1.刚开始写脚本的时候经常忘记带 request headers,特别是host和user-agent这俩个字段(通常带这两个就足够了),这个就是体现在对http协议理解不够。具体是哪个网站我忘了,我因为没有带上ua,一直拿不到html,耽搁我不少的时间。


因为网站会检查你的 request headers 中的host,如果不对,好的你拿不到数据,然后是检测你的ua,嗯?什么是ua,就是User-Agent,不同的浏览器有不同的ua,也是爬虫伪装浏览器的第一步。


2.关于cookies,这个我就遇到过一次,也是我上一份工作中遇到的,我要拿数据的那个网站,分析了url,确定了参数,post过去,嗯?怎么是空网页,数据喃。


这里我们在用浏览器的开发者工具时,在network里要关注所出现的各种url。后来我注意到在每次post后还有一个url紧跟着请求,原来这个post请求数据是个障眼法。


所以呢,这个就是网站通过post请求把参数放到cookies里,然后到了真正出数据的url里,在请求时带上刚刚的cookies,服务器在读取完cookies接着就能看到数据了。


3.接下来就是ip的访问频率了。


我在入职现在这份工作时,老大让我在xx网抓一份全国的旅行社数据,结果我的ip被ban,整个公司那一周都不能上那网站。所以,当我给老大汇报这个事情的时候,老大淡淡说了句,你当人家网站的运维chishi的么。


同时,在这里作为一名爬虫工程师,基本的职业素养就包括,好比隔壁组坐着一个漂亮的菇凉,咱们看看就好了,不要去影响人家。所以说,在每两次请求间一定要有时延。这里我不是说,咱们通过测试来摸索出该网站的rps(request per second),然后就着rps来跑,这样的确算是提高效率的方法,但是我偷懒,统一设置为10秒的时延。


但是,处理办法有好几种。


一,每一次请求时变更ua,就可以理解为学校机房里,大家同时访问一个url,难不成就把这个机房的ip给ban了?


二,在request headers里带上 referer,既然是模拟人的操作,那就在每一次请求的headers的referer里带上上一次的请求url。什么?referer是做什么的,这个就是告诉服务器我是从哪一个url来到哪一个url去。


三, 设置时延,这个不解释,我们抓数据的同时不能给服务器造成太大压力,也不能影响别人的浏览体验。


四,使用代理, 通过改变代理ip的方式,让服务器没办法来阻止你拿数据。


4. 放在js中的反爬虫,这里我很愿意来举一个实际的栗子。客官们可以跟着我一起来看看人家怎么反爬虫的。


就说携程酒店的评论数据好了。

http://link.zhihu.com/?target=http%3A//hotels.ctrip.com/


然后随便点一个酒店进去,“shift+ctrl+i” 打开开发者工具


然后拖动页面去找评论,点击 更多评论, 这时候注意开发者工具里的network里的变化。


然后能看到这两个



可以看到,我画圈的就是关键,而下面那个AjaxHotelComment。是请求评论的页面,因为在请求这个ajax时里面有个参数eleven,看似是个token,实际不符合token的定义,总之就是在这个ajax请求前通过oceanball?这个请求得到一个eleven参数,然后交给请求ajax得到数据。


现在我们点进去那个画圈的url,复制开一个新窗口打开。


整理后的代码长这个样子


eval(function(arr, f) {
    if (typeof Array.prototype.map === "function") {
        return arr.map(f)
    }
    var res = [],
    j = 0;
    for (var i = 0,
    l = arr.length; i < l; i++) {
        res[j++] = f(arr[i], i, arr)
    }
    return res
} ([.....],
function(item) {
    return String.fromCharCode(item - 38644)


eval这个臭名昭著效率低的东西恰巧就是反爬虫利器,我们可以看到这段代码实际起作用的内容就是


arr.map(f)


好的,我们来模拟。


我们打开开发者工具的console,

在里面输入


var a = [那一大段的列表].map(function(item) {
    return String.fromCharCode(item - 38644)
}).join('')

a //输出结果


结果就可以看到这样的



也就是说,解码后,给了这么一段,(事实上这个跟网站底层的js有关联,不然在底层的js里找到 getElevenCode()这个function死活模拟不出来结果)。


好的,在站长工具里对解析出来的这段js代码进行格式化,看到的结果呢,只想骂马萌萌!!各个参数都是机器生成的。其中绕来绕去,被绕晕。


然后看到一段注释,心想,嘿,后门吧。转码过来看,结果如下


好的呀!结果我被嘲讽了!再一次马萌萌!!携程的人太骄傲了。


从这里我们数数人家的加密就有(1.请求得eleven 2.转码获取新的js 3.再解码)3层加密。


转过来一想,都被嘲讽了,说明我离真相就近了。


那我们换一个思路,从底层js去找。


这时候我们去看人家从哪个js来



然后点进去,“ctrl+f”搜 ‘eleven’,结果我们找到这个



可是我没看明白逻辑!!!!!!


于是我就卡在这了。


所以,携程的这个栗子的反爬虫就是通过恶心的js来完成。


为啥要这样做,因为这类网站的数据不需要通过登陆就能看到


5. 然后就是验证码咯


老大通过机器学习训练出可以识别xx网的验证码,已经上线了,所以验证码形同虚设(暂时的)


不过验证码依旧是我认为反爬虫强有力的手段,因为涉及的技术很多,学习成本很高,很容易就放弃了。


6. 至于像淘宝啊 京东啊微博啊的种种反爬虫,我还没抓过,所以我也不清楚。


等等,被老大叫出去抽根烟  -.-!


好了,我回来了,刚刚跟老大聊了聊后面的工作安排。原本今天还打算写一下框架和一个简单的代理池,放后面好了, 不好意思哈 各位。


接下来我的工作就是弄爬虫框架,还有分布式,所以我学到了什么再来分享。


Python的爱好者社区历史文章大合集

Python的爱好者社区历史文章列表

福利:文末扫码关注公众号,“Python爱好者社区”,开始学习Python课程:

关注后在公众号内回复“ 课程 ”即可获取:

小编的转行入职数据科学(数据分析挖掘/机器学习方向)【最新免费】

小编的Python的入门免费视频课程

小编的Python的快速上手matplotlib可视化库!

崔老师爬虫实战案例免费学习视频。

陈老师数据分析报告扩展制作免费学习视频。

玩转大数据分析!Spark2.X + Python精华实战课程免费学习视频。


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存