反爬与反反爬

​ 接触爬虫一段时间后,多多少少都会遇到反爬的问题。这里就简单讲一些反爬原理、反扒方式,同时说一些对付这些机制的方法。这里所提到的只不过是蜻蜓点水罢了。

原因

反爬的出现大多归咎于:

  • 爬虫访问过于频繁,给服务器造成压力
  • 数据资产流失

出于利益保护意识,很多网站都不希望自己的数据被爬,那么他们应对的措施就是反爬虫!

反爬机制与破解机制

身份识别反爬

请求参数

User-Agent

user-agent是何物

user-agent是一种请求头,服务器可以从它对应的值来识别用户端的一些信息。它通常由浏览器标识、版本信息、渲染引擎标识组成

绕过原理

一般情况下,我们通过浏览器访问某网站的方式:

爬虫访问某网站的方式:

说白了,你可以把那只当作是套了头套伪装成浏览器的臭虫!user-agent相当于那个头套,欺骗服务器。

应对方式

​ 所以爬虫实际上是模拟浏览器对服务器发送请求来得到数据。当然爬虫默认是遵守Robot协议的,既然是只臭虫了,还遵守什么协议。如果不加user-agent是及其容易被服务器识别出是爬虫(裸奔的感觉)。

​ 道高一尺,魔高一丈。不是加了user-agent就万能了,比如将常用的请求头放入服务器的黑名单,当有网络请求时检测它们的请求头判断是不是爬虫,如果是就不允许访问。不过这种很容易产生误伤,正常客户会莫名躺枪。

​ 说回正题,user-agent不能单一写死,可以试试fake-useragent

fake-useragent是一个python库,用前先安装:

1
pip install fake-useragent

以下是在Scrapy中实现的方法

  • 在settings.py上使用
1
2
3
#先把默认的UserAgent删掉
from fake_useragent import UserAgent
USER_AGENT=UserAgent().random
  • 在middlewares.py中使用

先关掉settings.py中的UserAgent

1
2
3
DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
}

之后在process_request()中修改:

1
2
3
4
from fake_useragent import UserAgent
def process_request(self, request, spider):    
    userAgent = UserAgent()
    request.headers['User-Agent'] = userAgent.random
  • 在spider上添加
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# -*- coding=utf-8 -*-
import scrapy
from fake_useragent import UserAgent

class ExampleSpider(scrapy.Spider):
   name = 'example'
   start_url = 'http://example.com'
   header={'User-Agent':UserAgent().random}
   def start_requests(self):
       yield scrapy.Request(url=start_url,headers=self.header)

原理(该原理摘自《python3 反爬虫原理与绕过实战》)

​ Cookie不仅可以用于Web服务器的用户身份信息存储或状态保持,还能够用于反爬虫。大部分的爬虫程序在默认情况下只请求HTML文本资源,这意味着它们并不会主动完成浏览器保存Cookie的操作。

​ Cookie反爬虫指的是服务器端通过校验请求头中的Cookie值来区分正常用户和爬虫程序的手段,这种手段被广泛应用在Web应用中,例如浏览器会自动检查响应头中是否存在Set-Cookie头域,如果存在,则将值保存在本地,而且往后的每次请求都会自动携带对应的Cookie值,这时候只要服务器端对请求头中的Cookie值进行校验即可。

​ 服务器会校验每个请求头中的Cookie值是否符合规则,如果通过校验,则返回正常资源,否则将请求重定向到首页,同时在响应头中添加Set-Cookie头域和Cookie值。

应对方式

  • 手动处理

​ 这种方式比较简单,就是直接用抓包工具把cookie信息粘贴到headers中。不过这种方法有弊端,cookie有时效性和变化性,如果过了有效期或者自身的值变动了,这种方法使用起来就很鸡肋。

1
2
3
url = 'http://www.example.coml'  
# 把cookie值粘贴进去
headers = {'Cookie': 'xxxxxxxx'}  
  • 自动处理

​ 这种方法可以使用session对象实现自动处理,用构造函数requests.Session()返回一个session对象。这个对象可以像requests一样像服务器发送请求,在请求过程中产生cookie。此时session对象会自动保持cookie值。

1
2
3
4
5
6
import requests

headers = {'User-Agent' : 'xxxxx'}
session = requests.Session() #构造一个session对象
url = 'http://example.com'
session.get(url=url, headers=headers) # 基于session发送请求,为了获取和存储cookie

行为识别反爬

请求频率

爬虫行为与普通用户最明显的区别就是,爬虫的请求频率太高了。

IP

IP 反爬原理

​ 正常用浏览器发送请求,速度不会太快、请求间隔随机、请求次数少。但是爬虫却和这些相反。它发送的请求速度快,间隔固定,量大。通过这几点就可以识别是否是爬虫。

如何应对IP反爬

​ 有攻就有防,对付IP反爬还是算比较简单的。只需要换一个别的IP去访问就行。

​ 通俗的举个例子:现在有个政策是防止未成年沉迷游戏,规定非放假日不得玩游戏,直到满18岁成年为止这些束缚才能解开。小A未满18岁,但是玩游戏受到限制,无法体现出他对游戏的热爱,于是他拿着妈妈的身份证去绑定游戏实名验证,从而逃过了这个束缚

​ 这个例子的身份证就是一个典型的代理IP作用。实际上真正给服务器发送请求的是代理端,然后代理端将得到的响应返回给请求端。

应对方式

  • 设置代理IP(单一IP)
1
2
3
4
5
6
7
import requests
url = 'http://www.example.com'
#换上IP(下面的IP是随便写的)
proxy = {
	'http': '123.45.67.89:1011'
}
r = requests.get(url=url,proxies=proxy)
  • IP代理池(多IP)

这里推荐一个开源的IP代理池ProxyPool ,不用重复造轮子,直接使用就行

ProxyPool简介

爬虫代理IP池项目,主要功能为定时采集网上发布的免费代理验证入库,定时验证入库的代理保证代理的可用性,提供API和CLI两种使用方式。

使用

  • clone代码
1
git clone git@github.com:jhao104/proxy_pool.git
  • 安装依赖
1
pip install -r requirements.txt
  • 修改配置
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 配置API服务
HOST = "127.0.0.1"               # IP
PORT = 5000                    # 监听端口

# 配置数据库
# 无密码
DB_CONN = 'redis://:@127.0.0.1:6379/0'

# proxy table name 表名(自己建的)
TABLE_NAME = 'use_proxy'

# 配置 ProxyFetcher
PROXY_FETCHER = [
    "freeProxy01",      # 这里是启用的代理抓取方法名,所有fetch方法位于fetcher/proxyFetcher.py
    "freeProxy02",
    # ....
]
  • 运行

    • 启动Redis,即打开redis-server.exe(得先安装Redis)
    • 方法一:启动调度程序
    1
    
    python proxyPool.py schedule
    
    • 写个demo读取数据库中的代理
    1
    2
    3
    4
    5
    
    import redis
    
    r = redis.StrictRedis(host="127.0.0.1", port=6379, db=0)
    result = r.hgetall('use_proxy')
    print(result.keys())
    

    结果:

    • 方法二:启动webApi服务
    1
    
    python proxyPool.py server
    

    启动后打开http://127.0.0.1:5000/ 将会看到:

在爬虫中使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import requests

def get_proxy():
    return requests.get("http://127.0.0.1:5000/get/").json()

def delete_proxy(proxy):
    requests.get("http://127.0.0.1:5000/delete/?proxy={}".format(proxy))

def getHtml():
    retry_count = 5
    proxy = get_proxy().get("proxy")
    while retry_count > 0:
        try:
            html = requests.get('http://www.example.com', proxies={"http": "http://{}".format(proxy)})
            # 使用代理访问
            return html
        except Exception:
            retry_count -= 1
    # 删除代理池中代理
    delete_proxy(proxy)
    return None

结尾

​ 还有很多种反爬手段,比如说数据加密反爬(CSS数据偏移/数据图片/特殊编码/自定义字体/js逆向加密)、验证码反爬等。这些没有提到是因为我还才疏学浅,还没有研究透彻,就不拿出来说了。等我研究透彻了,会开新的文章。

参考

  • python3 反爬虫原理与绕过实战