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()
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)
结果如下
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, ...... }