一个简单的ip池的搭建

在爬虫的时候总是会遇到跑的太频繁而导致ip被封号的问题,所以就想着做一个简单的ip池去规避这种反爬取的手段,当然我写的ip池功能稍微简单一点,但是也能满足在爬取时遇到的封禁ip的问题。整个流程就是先用get_ip()函数从网上爬取免费的代理ip地址,当然对于这些代理的ip的能使用率是比较低的,我们用redis数据库的zset对其进行存储,zset有序集合比一般的集合多了一个分数的字段,我们可以在存储的过程中给其初始的分数,在check_ip()函数中对其分数进行修改。 check_ip()函数拿出有序集合中的Ip,然后访问百度,测试其是否可用,如果可用就对其分数进行加1操作,(也可以可用就将其分数设为最大值),如果不可用就将其分数减去1,直到为0,从代理池中移去。当然我这个比较简单了,就是单纯的加一减一,能将就用就行了。
下面直接上代码。

import requests
from bs4 import BeautifulSoup
from redis import StrictRedis
store=StrictRedis(host='localhost',port=6379,db=0)
default=5
def get_ip():####从西刺ip代理爬取免费的代理ip。
    url='https://www.xicidaili.com/nn/'
    header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0', }
    r=requests.get(url=url,headers=header)
    soup=BeautifulSoup(r.text,'lxml')
    infos=soup.find(id='ip_list').find_all('tr')
    count=0
    for info in infos:
        if info.select('td'):
            ip=info.select('td')[1].text
            port=info.select('td')[2].text
            count+= 1
            store.zadd('xici_ip', {ip+':'+port: default})
    print(count)

def check_ip():
    TEST_URL='https://www.baidu.com'
    store.zremrangebyscore ('xici_ip',0,0)
    count2=0

    header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0', }

    for proxy in store.zrangebyscore('xici_ip', 1, 9):####只检测分数在1-9之间的,其它的没管
        count2+=1
        proxy = proxy.decode('utf-8')
        # proxy='http://'+proxys
        # proxys = '139.224.147.40:8080'
        print(proxy)
        proxys = {'http': 'http://' + proxy,
                  'https': 'https://' + proxy
                  }
        print('testing' + ' ...第' + str(count2) + '个 ')
        try:####异常就都捕获了。
            r = requests.get(url=TEST_URL, headers=header, proxies=proxys, timeout=1.0)
            if r.status_code == 200:
                store.zincrby('xici_ip', 1, proxy)
                print('第' + str(count2) + '个:  ' + '成功')
        except:
            store.zincrby('xici_ip', -1, proxy)
            print('第' + str(count2) + '个:  ' + '失败')
if __name__ == '__main__':
	get_ip()
	check_ip()

总体上来说,这个程序只能说是将就着用吧。还有许多可以改进的地方,首先就是多线程的问题。其次检测函数做的不好,我就是简单的加一减一就行了,实际上可以在检测成功后,直接赋予其默认值也就是最高值比较好一点,失败后减去1并且在分数为0后从ip池中删除掉,这样会更好一点的。用redis的zset去存储ip还是比较好用的,速度快就先不说了,本机上的其他程序可以很方便的去调用这个ip池。我ip池的程序是在pycharm上完成的,在jupyterlab上都很好的调用它,贼方便。
在调用的时候只需要将ip从redis中导出就行了,而且zset还提供按照分数排序,我们可以很方便的导出那些可用性比较高点的ip。
如果觉得ip量太少不够用,可以从网上多抓取点。

猜你喜欢

转载自blog.csdn.net/qq_42232193/article/details/88794551