应对反爬
更换ip地址
比如我用requests
来发送请求
import requests
proxies = {
"http": "http://10.10.1.10:3128",
"https": "http://10.10.1.10:1080", # 这里用 https 代理会失效,取的是 https ip 也不行,可能我爬取的是 http 网站(猜测)
}
requests.get("http://example.org", headers=headers, proxies=proxies)
参数proxies
就是更换的代理ip,注意格式里https
的头还是http
至于ip怎么搞,一些卖ip的网站首页上有免费的ip可以用,写了个爬虫爬下来用
后来可能是爬多了,别人把我封了,就花钱买了ip
这里推荐一下大象代理,http://www.daxiangdaili.com
五块钱两万个ip,可能不太稳定,但自己用应该够了
requests
文档
http://docs.python-requests.org/zh_CN/latest/user/advanced.html#proxies
更换UserAgent
User-Agent 首部包含了一个特征字符串,用来让网络协议的对端来识别发起请求的用户代理软件的应用类型、操作系统、软件开发商以及版本号。
我是这么做的
去网上复制十几个UserAgent
,放到列表里,每次从中随机取一个
from random import choice
ua_list = [
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36',
'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv,2.0.1) Gecko/20100101 Firefox/4.0.1',
'Mozilla/5.0 (Windows NT 6.1; rv,2.0.1) Gecko/20100101 Firefox/4.0.1',
'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;',
'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)',
'Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11',
'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Maxthon 2.0)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SE 2.X MetaSr 1.0; SE 2.X MetaSr 1.0; .NET CLR 2.0.50727; SE 2.X MetaSr 1.0)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Maxthon 2.0)',
]
def ua_get():
ua = choice(ua_list)
headers = {"User-Agent": ua, }
return headers
看到更骚的操作是,使用搜索引擎爬虫的UserAgent
试了一下,但会报错,就没去深究了
redis 代理ip池
之前的做法是每次从代理接口取一个ip,所有的请求都用这一个ip去伪装
问题是,取的间隔至少得一秒,如果这个ip不能用或者速度慢,那这一秒内的请求全部不能用,并且会一直请求到超时
既然用的是五块钱两万个ip,那肯定一大堆不能用的
所以去网上看了别人的做法,然后按自己的想法做了一个ip池
具体做法是
每次从接口取10个ip,放进redis里,取的方式是先进后出,每次从头部取
设置请求的时间,如果请求超时或者报错了,就重新取一个ip再发请求
限制发送次数,超过次数就退出来
如果请求发送成功,拿到了想要的东西,就把那个能用的ip从尾部塞回去
如果去redis取ip的时候发现空了,就重新去接口拿10个
整个过程就是这样,贴一个丑陋的函数
def requests_send(url):
h = header_get()
code = 0
count = 0
while code != 200: # 如果请求不成功,就接着请求下去
count += 1
print('第{}次请求'.format(count))
if count > 10: # 限制次数
break
try:
ip = pop() # 取ip
p = dict(http='http://{}'.format(ip))
print('proxy', p)
r = requests.get(url, headers=h, proxies=p, timeout=3) # 发送请求
response = r.content.decode('utf-8')
code = r.status_code
path = response
except Exception as err: # 报错了的话,也会重新请求
print(str(err))
else:
print('path[-4:]', path[-4:])
if path[-4:] != '.mp3': # 如果没拿到想要的,重新开始一次
continue
rds.rpush('ip-proxy-pool', ip) # 成功了把ip塞回去
print('补充1个', ip)
return dict(code=200, path=path)
return dict(code=-1)
这种做法并不好,有条件的话,应该时刻保持着ip能用,但那样的话请求量就陡增了很多
文档
https://cloud.tencent.com/developer/article/1004915
https://www.jianshu.com/p/588241a313e7