爬虫中常见的问题,常见的反爬机制

1.请求头之User-agent

这个稍微接触过一点点爬虫的应该都不陌生,不是说接触Python爬虫,不管你用什么开发语言来写爬虫,应该都会用到这个。大概解释一下,就是一个身份的象征,这个可以用浏览器自带的调试工具查看,访问一个网站的时候,按f12键或者鼠标右键打开调试(有的浏览器叫检查,或者查看元素),然后切换到network(网络),重新刷新一次网站,就会出现所有的请求,随机点击一个,右边出现的就是请求头信息了

2.调试工具之痛

很多时候我们为了查看网页的DOM结构可能就直接用浏览器自带的调试工具(就是上面说的按f12键)来查看,这个的话,大部分网页是可以应对的,但是,少部分网站用调试工具查看的DOM结构和整个网页的源码是不一致的,说个最近的事,我爬某视频网站,调试工具打开他在每个重要信息都加了一个css样式,这个css样式是通过定位某个html标签(假设为标签)设置上的,我解析网页的时候就很痛苦,调了很久,就是得不到结果,最后发现这个span标签是用js拼接上的,换句话说,服务端回应的是不带有这个span标签的,所以就要没有这个span标签来处理。说这么多不知道看官您能不能理解,遇到过这个问题的朋友应该明白我在说什么。

3.异步请求

上面说的DOM结构不一致还有一种可能,就是前后端用的Ajax异步请求的,所以你打开浏览器的调试工具查看DOM结构和你用Python获取的结果也是不一致的,这个相信会玩爬虫的老哥们都不陌生。

4.请求头之Cookies

有一部分网站,当你访问首页时,会自动设置一个cookie,然后访问同站下的其他页面就会验证这个字段,如果不匹配就会禁止访问。

5.请求头之特殊字段

特殊字段是什么呢,就是某网站特有的一些字段。

6.请求头之Referer

这个referer是干嘛的呢?首先该字段的值都是上一级网站的url,根据我的理解,它有以下作用:

1.做前端的朋友知道,可以借用这个字段直接返回到上个页面

2.还可以通过这个追踪流量来源,比如某某公司在百度上做了SEO(打了个推广广告),当用户通过百度点进来的话,就可以通过referer追踪来源,对用户做进一步的行为分析

3.检测来源的合法性,因为都可以知道通过某某url路径过来的,那么就可以判断来源是否合法,如果异常的话就可以做拦截请求等等的
  
有的网站就是因为有这个验证,所以返回的数据不正常,带上就OK了。还有的网站更奇怪,你不带上也不会报错,返回的数据也是希望的数据,但是无法和页码匹配,比如你请求的是第一页的数据,它有可能返回的是第5页的数据。

7.请求头之accept:

不知道老哥您遇到过这个问题没有,在请求头里,如果服务端返回的结果是普通的html页面的话,值就应该是如下的:
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/c070df3272bf4a09a00fa5f3bdf62266.png
在这里插入图片描述

如果返回的是json字符串(返回json字符串的话,往往是属于异步请求)的话,值就应该是这个:
在这里插入图片描述

这个不知道你们有没有体会,反正我记得我爬某网站的时候,因为都通用的同一个请求头,有的网站就是返回json数据,我怎么改代码都无法得到正确的值,就是因为本来是json字符串的我的accept用的上面的html页面用的,导致返回数据不符合事实。

8.请求头之Connection

这个字段字面意思就是http连接嘛,http链接最根本的就是tcp/ip连接了,什么三次握手,四次握手之类的,这些就不展开了,要说就占篇幅了。我们都知道,http请求属于短连接,访问就有,关闭浏览器就会自动断开的,这种就是短连接,对应的长连接就是websocket,这个就不展开了,自行百度了。这个Connection字段有两个值,一个是keep-alive,一个是close,keep-alive的话往往就跟前面的带有cookie相关,他会保存session会话(如果关闭浏览器的话就没了,有的网站是保存一个字段,默认有几天的有效期),作为同一个连接来请求另一个页面,如果是close的话,就是每次访问都是重新和服务端建立一个连接,不会保存session

这个问题的话,在一般情况下还是不会遇到,主要就是在高并发请求的时候,有可能同一个时刻请求多次来自同一个站点的数据,触发该网站的反爬机制的频率限制,就会出现什么scoket.timeout,urllib3.connection.HTTPConnection之类的错误。所以从那次之后我的爬虫程序如果用了高并发的话,我都会把这个connection设置为close。

9.返回数据gzip

gzip的意思就是这个网站的数据是做呀gzip压缩的,在浏览器(客户端)访问之后,会自动处理这类格式的数据。但是使用Python的标准款urllib的话,是不会处理这类格式的, 解决方法就是用requests库,会自动处理gzip格式,反正这个库真的太强大了。

10.reqeusts库的弊端

嘿嘿,刚说完requests很强大,马上说它的弊端,是的,就是这么骚气。它有什么弊端呢,如果经常使用requests库作为主要的网络请求的话,使用时间越长的老哥,就越会发现它有个弊端,就是它封装的异常类不够全,在报错各种各样的异常的时候,它有时候捕获不到,无法进行针对性的处理,这就是它的弊端,这个怎么解决呢,目前我的话,没有一个很好的解决方法,只能用Exception或者BaseException类来捕获。

当然这个问题也不是一定会遇到,有时候只是某个其他的异常爆出,导致后续的代码跟着出错,然后跟着抛出异常,所以也不能盲目的用异常基类来捕获

11.登录验证

有的网站为了解决网络请求的拥塞,就做了账号登录验证,你必须登录账号之后才能正常访问页面,一般的网站登录之后返回的就是上面说的cookie字段,有的也会返回一个特殊的字段作为验证,我记得百度登录之后用的字段是BAIDUID。这个不需要多说什么,找到登录接口,提交账号密码参数访问登录接口就行了

12.请求头之token

这个token在语义上就是个令牌的意思,用的比较多的地方就是在手机端上用token验证,此手机端的验证对应的电脑端用的session验证,而电脑端用token的情况就是,特殊字段的变异,有的网站就放在请求头的authorized键里,值就是token,用uuid生成的,有的就是自定义的键,比如boss直聘的就是__zp_stoken__,必须要带上这个字段才能爬取(因为boss直聘的反爬机制升级了,以前直接可以爬,现在必须带上这个字段才行,说句题外话,目前我还没找到boss直聘这个字段是怎么生成的,用fiddler抓包发现请求了阿里云的服务端,但是返回的数据是空,反正没找到它是怎么生产的)

13.登录验证+token

有的网站在用户登录之后感觉还不够安全,就会再对token验证,如果登录验证和token都通过了说明是正常登录操作,才放行。当然也有的网站不需要登录也会分配一个token,比如上面的boss直聘,这个就不多说了,就是以上的结合

14.设备验证(手机,电脑)

一般情况下,电脑能访问的页面,手机一定能访问,只是如果该站没有作响应式的话,用手机访问的页面排版很乱,因为手机和电脑的尺寸不一样嘛。

但是手机能访问的,电脑不一定能访问,比如某app,或者微信小程序,它会做设备验证,发现不是手机页面的话就会拦截或者提示让你用手机下载该app查看。有朋友要问了,是用的什么来检测你是手机还是电脑的呢?就是前面最开始说的User-agent,说到这,怎么解决这个问题不用多说了吧,同样的伪造成手机的UA就行了,当然如果是针对app的爬取的话,一般就在电脑上下载模拟器(夜神模拟器啥啥的),然后fiddler抓包分析,然后再爬取

15.重定向

这个跟http的状态码有关了,不多说,返回的状态码是3**的就是重定向范畴里的,这种网站怎么爬取呢,requests会自动处理重定向的问题,没错,requests就是这么抗打。

16.触发跳转到新的标签页

什么意思呢,就是比如我在某一个网站点一下按钮,触发机制,用新的网页标签打开的,前端的朋友应该知道,就是a标签属性里加了个target=‘_blank’,这种的话,如果用浏览器的调试工具来分析的话就无法即时的查看请求了。因为习惯上我喜欢用浏览器自带的调试工具分析,比较方便快捷,实在不行的话就上fiddler啥的抓包工具。没错,解决方法我已经说了,像这种点击一个会以新的浏览器窗口打开的就用抓包工具来分析

17.调试工具触发js的debug监听器

这个我不知道你们遇到过没,我有一次抓某个网站,它就是为了防止我这类瞎jb搞的人分析它的代码,分析它的请求过程,所以当我一打开调试工具,就触发它的监听器,然后我就发现我电脑的CPU立马跑满了,一直在消耗我的电脑资源直到电脑卡死,所以我只能感觉关闭调试工具或者关闭浏览器,实在不行只能重启了,它就是监听的debuger,我不知道这个是一个函数还是一个类,以下是我保存的代码,看有缘人能不能看懂,看懂的话我就以…此处省略1111个字

var check = (function () {
    var callbacks = [], timeLimit = 50, open = false;
    setInterval(loop, 1);
    return {
        addListener: function (fn) {
            callbacks.push(fn);
        },
        cancleListenr: function (fn) {
            callbacks = callbacks.filter(function (v) {
                return v !== fn;
            });
        }
    }
    function loop() {
        var startTime = new Date();
        debugger;
        if (new Date() - startTime > timeLimit) {
            if (!open) {
                callbacks.forEach(function (fn) {
                    fn.call(null);
                });
            }
            open = true;
            window.stop();
        } else {
            open = false;
        }
    }
})();

18.js加密cookie

这个大概的原理就是,访问该网站的时候会访问两次,第一次服务端返回响应头里给了一段加密的js代码,前端(浏览器)自动调用js然后反解出cookie,然后第二次访问的时候带上cookie去访问,才会返回一个正常的值,这个我在写IPproxy项目的时候遇到的66ip(http://www.66ip.cn/)网站就是这样的,而且很多同类的网站都是类似的操作。解决方法就是打开浏览器的调试工具,然后打断点测试,看看流程,基本都会有一系列的操作然后赋值给一个变量,找到这个变量名被如果的替换就行了,主要的破解难点就在js的部分,有的是做了js混淆加密的,有的是做了自定义处理的,这个就只有多尝试了

说到这,如果是上面的监听debug工具的+js加密的话,那可就真的难操作了,你一打开调试工具想打断点分析,结果就立马卡死了。哈哈哈,好像我还没有遇到网站这么干的

相关的js加密cookie破解教程,可以移步这里:

https://www.cnblogs.com/zdfbk/p/8806282.html

19.urllib库之编码

有的时候如果要传递参数到服务端的话,那么就得做url编码,使用url编码解码就可以用urllIb.parse.quote和urlib.parse.unquote,使用quote方法作编码的话,默认使用的是utf-8的编码,但有时候一些网站用的gbk,所以这是一个坑,你得用quote(kw,encoding=‘gbk’)才能转为gbk的编码,不熟悉这个的话就很难发现这个,因为我们一般就直接用quote就行了,根本不在意是用了什么编码。

20.request.post之痛

嘿嘿,又是requests库的问题,准确说其实不是requests的问题,而是跟上面的quote一样,我们平常遇到的网站基本都是不会出现这个情况,当出现的时候我们就傻眼了,requests库的粉丝们,放下你们手上的菜刀,我是友军啊,我也一直在用requests,只是发现了这一两个情况而已

不多说了,requests做post请求时,提交的data字段会默认将data字段作url编码,且默认用的utf-8编码,对的,又是编码的锅,而有的网站用的并不是utf-8编码的,假如某网站用的是gbk编码,如果我们还是默认的操作的话,就会出错,解决办法就是,手动编码:
在这里插入图片描述

21.xpath解析tbody

解析网页结构的工具很多,比如一大杀气正则表达式,然后就是xpath,再然后就是bs4,最近我痴迷于xpath,我觉得写起来异常的顺畅,非常有感觉,但是在其中还是遇到了问题如下,无法解析带有tbody标签,这个是我最近发现的,不知道是不是版本问题,只要网页的DOM结构用tbody,比如table标签下有tbody/tr/td时,我要取td下的数据,按理就是写的response.xpath(‘//table/tbody/tr/td/text()’),但是这样写就是TMD的拿不到,得去掉tbody,写成这样就可以拿到:response.xpath(‘//table/tr/td/text()’),总之就是不能带tbody,如果有就直接跳到下一级就行,我估计是这个tbody被错误的解析成body标签了

22.xpath元素选取

一般情况下,我们获取某个数据的话,直接就根据class属性或者id属性,反正就一些非常特定的属性三两下就可以定位元素,但是有的元素就是什么属性都没带的,就只是一个标签名,而且这个标签用的还异常的多,此时此刻的话,你就可以你的目标元素就近的标签有没有很特殊的属性,直接就可以定位的,然后用following-sibling定位兄弟元素即可,比如:following-sibling::span[1]/text(),补充一个:回到上级:用 【…】表示回到上级,再补充一个,用contains(text(),‘xxx’):根据一个元素的内容包含某个字段来定位

当然这几个都是很简单的,这个本来就是xpath的基础部分,但是我跟你说,这三个配套使用的话就没有锁定不了的元素,通通一杀一个准,真的,我感觉用多了xpath,比用beautifulsoup还顺手

23.简单验证码
简单验证码,比如一些肉眼很好看出的验证码的话,可以借用tesseract库来识别,做ocr提取,比如以下就是我那个IPproxy里的某一段代码:
在这里插入图片描述

直接就可以把简单的验证码的数据提取出来,更多的操作就不说了,网上一大堆。

24.滑动验证码

滑动验证码的话,以极验的滑动验证码为典型,之前网上有一大堆的极验验证码破解,不过都是2.0的破解,更新到3.0之后,破解的人就少了,不过,嘿嘿,我还是破解了,

我不多说,感兴趣的可以看看我的源码,包括腾讯系的我也破解了:GitHub (就在我的github里,我不说是哪个,嘿嘿,皮一把)

网易系的就不多说了,坊间传闻的,网易的滑动验证码本来就是抄袭极验的(不是我说的),所以破解方法差不多,感兴趣的可以根据我的代码自行修改

25.ip代理

终于说到这个问题了,稍微接触过爬虫的人都知道,你知道访问频率太频繁你电脑的公网IP就会被ban的,那么你就需要用上ip代理防止ip被ban无法继续爬数据的github地址

26.访问频率控制

有的网站比较大型,每天的访问量很大,那么这个网站对访问频率的限制就没那么严格,如果是小网站限制就会严一点,当然凡是无绝对,这个真的就看你的感知了,你如果感觉按你的代码运行下去可能爬不了几个数据就请求超时了,多半是触发访问频率的峰值了。如何解决,就只能看你自己怎么优化代码,保证代码每次请求的都不走空了,这个就没法具体的说了,你可以用协程来回的切换啥啥的

27.提升性能:

提升性能的话,要说的还挺多的,我就说几个比较典型的,如果你发现你的代码运行是串行的,你可以用gevent协程做切换,或者用线程池,或者用线程池+异步的方法,然后网络请求属于IO操作,所以不适合上多进程的方式

如果你还觉得速度不够快,可以弃掉requests库改用aiohttp库,这个也是网络请求的库,不过是异步请求的,requests是阻塞式的请求

还觉得不够快,可以用JIT,即使编译技术,把你觉得比较耗时间的代码块用上JIT

还觉得不够快,可以再用上解释器来直接解释这段代码,比如win平台下,直接用cpython对你的代码进行处理,其他平台的就用其他平台的解释器了,不多说了

还觉得不够快,技术再强点的话,可以写原生的C代码,把几个关键的操作抽离出来,用C来重构,然后运行的使用直接调用这段C代码(python有直接运行C代码的库,很多,网上自行查询)

还觉得不够快,升级你的硬件配置了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值