爬虫

应对反爬

更换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

原文地址:https://www.cnblogs.com/xb21/p/8386111.html