scrapy几种反反爬策略

一.浏览器代理

  1.直接处理:

    1.1在setting中配置浏览器的各类代理:

user_agent_list=[

"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36", ......
]

 

    1.2然后在各个请求中调用:

import random
from setting import user_agent_list
headers=
{
"Host":"",
......
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
}
def parse(self,response):
    ......
    
    user_agent=random.choice(user_agent_list)
    self.header["User-Agent"]=user_agent
    yeild scrapy.Request(request_url,headers=self.headers,callback=...)

 

    1.3缺点:

      使用麻烦,各个请求都要调用,而且耦合性高。   

  2.使用downloader-middlewares:

    2.1使用downloader-middleware(setting中默认是注销了的):

  

    2.2useragent源码如下(默认的User-Agent为Scraoy,可以直接在setting中配置USER_AGENT="......"就会替换Scrapy如红框中):

    2.3自定义useragentmiddleware(需要在setting中将默认的middleware致为none或数字比自定以的小):

官网简介

        2.3.1直接重写函数:
#这样能实现,写一个random()函数选择代理,但维护user_agent_list很麻烦,需要重启spider
class RandomUserAgentMiddleware(object):
    #随机选择User-Agent
    def __init__(self,crawler):
        super(RandomUserAgentMiddleware,self).__init__()
        self.user_agent_list=crawler.setting.get("user_agent_list","")
    @classmethod
    def from_crawler(cls,crawler):
        return cls(crawler)
    def process_request(self,request,spider):
        request.headers.setdefault('User-Agent',random())

 

       2.3.2fake_useragent的使用:  

        安装:pip install fake_useragent  

        使用:

from fake_useragent import UserAgent
......
class RandomUserAgentMiddleware(object):
    #随机选择User-Agent,所有浏览器
    def __init__(self,crawler):
        super(RandomUserAgentMiddleware,self).__init__()
        self.ua = UserAgent()
    @classmethod
    def from_crawler(cls,crawler):
        return cls(crawler)
    def process_request(self,request,spider):
        request.headers.setdefault('User-Agent',self.ua.random)

 

   

class RandomUserAgentMiddleware(object):
    # 随机选择User-Agent
    def __init__(self, crawler):
        super(RandomUserAgentMiddleware, self).__init__()
        self.ua = UserAgent()
        #RANDOM_UA_TYPE为setting中配置的浏览器类型
        self.ua_type = crawler.settings.get("RANDOM_UA_TYPE", "random")

    @classmethod
    def from_crawler(cls, crawler):
        return cls(crawler)

    def process_request(self, request, spider):
        #函数里定义函数(动态语言闭包特性),获取是哪种浏览器类型的随机
        def get_ua():
            #相当于取self.ua.ua_type
            return getattr(self.ua, self.ua_type)

        request.headers.setdefault('User-Agent', get_ua())

 

      2.3.3自定义中间件配置:

二.IP代理设置

  1.重启路由器:

    IP在绝大多数情况会变,用本机IP比用代理IP爬取速度更快。

  2.代理IP原理:

    1.本机向代理服务器发起请求访问某个网站——>

    2.代理服务器访问请求的网站——>

    3.数据返回给代理服务器——>

    4.代理服务器把数据返回给本机。

  3.免费ip网站获取ip(西刺网【设置一定间隔】):

 1 # _*_ encoding:utf-8 _*_
 2 __author__ = 'LYQ'
 3 __date__ = '2018/10/6 17:16'
 4 import requests
 5 from scrapy.selector import Selector
 6 import MySQLdb
 7 
 8 conn = MySQLdb.Connect(host="localhost", user="root", passwd="112358", db="xici", charset="utf8")
 9 cursor = conn.cursor()
10 
11 
12 def crawl_ips():
13     headers = {
14         "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36"
15     }
16     for i in range(1, 3460):
17         re = requests.get("http://www.xicidaili.com/nn/{0}".format(i), headers=headers)
18         selector = Selector(text=re.text)
19         ip_lists = selector.css('#ip_list tr')
20         get_ips = []
21         for ip_list in ip_lists[1:]:
22             speed = ip_list.css(".bar::attr(title)").extract_first()
23             if speed:
24                 speed = float(speed.split('')[0])
25             texts = ip_list.css("td::text").extract()
26             ip = texts[0]
27             port = texts[1]
28             proxy_type = ip_list.xpath("td[6]/text()").extract_first()
29             get_ips.append((ip, port, proxy_type, speed))
30         for ip_info in get_ips:
31             cursor.execute(
32                 "INSERT  REPLACE INTO proxy_ips(ip,port,type,speed) VALUES('{0}','{1}','{2}','{3}')".format(ip_info[0],
33                                                                                                             ip_info[1],
34                                                                                                             ip_info[2],
35                                                                                                             ip_info[3])
36             )
37             conn.commit()
38 
39 
40 class Get_ip(object):
41     def judge_ip(self, ip, port):
42         # 判断ip是否可用
43         http_url = 'https://www.baidu.com'
44         proxy_url = 'https://{0}:{1}'.format(ip, port)
45         try:
46             proxy_dict = {
47                 'http': proxy_url
48             }
49             response = requests.get(http_url, proxies=proxy_dict)
50         except:
51             print("该ip:{0}不可用".format(ip))
52             self.delete_ip(ip)
53             return False
54         else:
55             code = response.status_code
56             if code >= 200 and code < 300:
57                 print("ip:{0}有效".format(ip))
58                 return True
59             else:
60                 print("该ip:{0}不可用".format(ip))
61                 self.delete_ip(ip)
62                 return False
63 
64     def delete_ip(self, ip):
65         delete_sql = """
66         delete from proxy_ips where ip='{0}'
67         """.format(ip)
68         cursor.execute(delete_sql)
69         conn.commit()
70         return True
71 
72     def get_random_ip(self):
73         random_sql = """
74         SELECT ip,port from proxy_ips ORDER BY RAND() LIMIT 1
75         """
76         result = cursor.execute(random_sql)
77         for ip_info in cursor.fetchall():
78             ip = ip_info[0]
79             port = ip_info[1]
80             judge_re=self.judge_ip(ip, port)
81             if judge_re:
82                 return 'http://{0}:{1}'.format(ip,port)
83             else:
84                 return self.get_random_ip()
85 
86 if __name__=='__main__':
87     # crawl_ips()
88     get_ip = Get_ip()
89     a = get_ip.get_random_ip()
View Code

 

   4.ip代理中间件书写:

class RandomProxyMiddleware(object):
    #动态代理ip的使用
    def process_request(self, request, spider):
        get_ip=Get_ip()
        request.meta['proxy']=get_ip.get_random_ip()

   5.开源库的使用(scrapy_proxy处理ip):

      scrapy-crawla,haipproxy,scrapy-proxies等,可以在github上查看

   6.Tor(洋葱网络的使用),可以隐藏ip(需要vpn)

三.验证码的识别

  1.编码实现(tesseract-ocr):

    需要数据训练,识别率低。

  2.在线打码(识别率在90%以上):

    2.1云打码平台的使用:

注册之后(开发者和用户模式),可以下载对应的调用实列查看

软件添加

验证码类型

错误状态码,可以在官网查看所有

    2.2识别接口:

 1 import json
 2 import requests
 3 
 4 class YDMHttp(object):
 5     apiurl = 'http://api.yundama.com/api.php'
 6     username = ''
 7     password = ''
 8     appid = ''
 9     appkey = ''
10 
11     def __init__(self, username, password, appid, appkey):
12         self.username = username
13         self.password = password
14         self.appid = str(appid)
15         self.appkey = appkey
16 
17     def balance(self):
18         data = {'method': 'balance', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey}
19         response_data = requests.post(self.apiurl, data=data)
20         ret_data = json.loads(response_data.text)
21         if ret_data["ret"] == 0:
22             print ("获取剩余积分", ret_data["balance"])
23             return ret_data["balance"]
24         else:
25             return None
26 
27     def login(self):
28         data = {'method': 'login', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey}
29         response_data = requests.post(self.apiurl, data=data)
30         ret_data = json.loads(response_data.text)
31         if ret_data["ret"] == 0:
32             print ("登录成功", ret_data["uid"])
33             return ret_data["uid"]
34         else:
35             return None
36 
37     def decode(self, filename, codetype, timeout):
38         data = {'method': 'upload', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey, 'codetype': str(codetype), 'timeout': str(timeout)}
39         files = {'file': open(filename, 'rb')}
40         response_data = requests.post(self.apiurl, files=files, data=data)
41         ret_data = json.loads(response_data.text)
42         if ret_data["ret"] == 0:
43             print ("识别成功", ret_data["text"])
44             return ret_data["text"]
45         else:
46             return None
47 
48 if __name__ == "__main__":
49     # 用户名
50     username = ''
51     # 密码
52     password = ''
53     # 软件ID,开发者分成必要参数。登录开发者后台【我的软件】获得!
54     appid = 5921
55     # 软件密钥,开发者分成必要参数。登录开发者后台【我的软件】获得!
56     appkey = '4b29b3e33db637975d5e51bdf9f2c03b'
57     # 图片文件
58     filename = 'getimage.jpg'
59     # 验证码类型,# 例:1004表示4位字母数字,不同类型收费不同。请准确填写,否则影响识别率。在此查询所有类型 http://www.yundama.com/price.html
60     codetype = 1004
61     # 超时时间,秒
62     timeout = 60
63     # 检查
64     if (username == 'username'):
65         print ('请设置好相关参数再测试')
66     else:
67         # 初始化
68         yundama = YDMHttp(username, password, appid, appkey)
69 
70         # 登陆云打码
71         uid = yundama.login()
72         print ('uid: %s' % uid)
73 
74         # 查询余额
75         balance = yundama.balance()
76         print ('balance: %s' % balance)
77 
78         # 开始识别,图片路径,验证码类型ID,超时时间(秒),识别结果
79         text = yundama.decode(filename, codetype, timeout)
View Code

结果如下

 

 

  3.人工打码:

    识别率最高,费用高。

四.配置使爬虫被识别率降低

  1.cookie的禁用:

    1.1setting.py中(不需登录的网站):

COOKIES_ENABLED = False  

    1.2自动限速(AutoThrottle)扩展:

      主要配置(setting中):

        AUTOTHROTTLE_ENABLED  默认: False  启用AutoThrottle扩展。

        AUTOTHROTTLE_START_DELAY  默认: 5.0  初始下载延迟(单位:秒)。

        AUTOTHROTTLE_MAX_DELAY  默认: 60.0  在高延迟情况下最大的下载延迟(单位秒)。

        AUTOTHROTTLE_DEBUG  默认: False  起用AutoThrottle调试(debug)模式,展示每个接收到的response。 您可以通过此来查看限速参数是如何实时被调整的。

    1.3不同的spider设置不同的setting:

      在spider中设置(这里的属性会覆盖setting中的):

custom_setting={
"COOKIES_ENABLED":True,
......
}

 

 

posted @ 2018-10-06 21:00  biu嘟  阅读(3031)  评论(0编辑  收藏  举报