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,
......
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM