Python搭建代理IP池实现存储IP的方法
上一文写了如何从代理服务网站提取IP,本文就讲解如何存储IP,毕竟代理池还是要有一定量的IP数量才行。存储的方式有很多,直接一点的可以放在一个文本文件中,但操作起来不太灵活,而我选择的是MySQL数据库,因为数据库便于管理而且功能强大,当然你还可以选择其他数据库,比如MongoDB、Redis等。
代码地址:https://github.com/Stevengz/Proxy_pool
另外三篇:
Python搭建代理IP池(一)-获取IP
Python搭建代理IP池(三)-检测IP
Python搭建代理IP池(四)-接口设置与整体调度
使用的库:pymysql
定义规则
数据库存储的主要对象是各个IP,首先需要保证不重复,另外还需要标IP的可用情况,而且需要动态实时处理每个IP,因此还需要定义一个分数字段,分数是可以重复的,最好是整数类型,每个IP都有一个分数,表现其可用性
对于代理池来说,分数可以作为我们判断一个代理可用不可用的标志,我们将设置一个最高分(满分,值由自己设置),代表可用,0设为最低分,代表不可用。从代理池中获取代理的时候会先从满分IP中随机获取一个,注意这里是随机,这样可以保证每个可用IP都会被调用到,如果没有满分的就从所有IP从随机选一个
分数规则如下:
- 满分为可用,检测器会定时循环检测每个IP的可用情况,一旦检测到有可用的IP就立即置为满分,检测到不可用就将分数减1,减至0后移除。
- 新获取的代理添加时将分数置为10,当测试可行立即置100,不可行分数减1,减至0后移除
添加设置
先在一个文件中定义一些配置信息,如数据库的设置、一些不变量如满分的数值等
setting.py
#数据库地址 HOST='127.0.0.1' #MySql端口 MYSQL_PORT=3306 #MySQl用户名、密码 MYSQL_USERNAME='***' MYSQL_PASSWORD='***' #数据库名 SQL_NAME='test' #代理等级 MAX_SCORE=30 MIN_SCORE=0 INITIAL_SCORE=10 #代理池数量界限 POOL_UPPER_THRESHOLD=1000
MAX_SCORE、MIN_SCORE、INITIAL_SCORE分别代表最大分数、最小分数、初始分数
定义方法
定义一个类来操作数据库的有序集合,内含一些方法来实现分数的设置、代理的获取等
db.py
importpymysql fromerrorimportPoolEmptyError fromsettingimport* fromrandomimportchoice importre classMySqlClient(object): #初始化 def__init__(self,host=HOST,port=MYSQL_PORT,username=MYSQL_USERNAME,password=MYSQL_PASSWORD,sqlname=SQL_NAME): self.db=pymysql.connect(host=host,user=username,password=password,port=port,db=sqlname) self.cursor=self.db.cursor() #添加代理IP defadd(self,ip,score=INITIAL_SCORE): sql_add="INSERTINTOPROXY(IP,SCORE)VALUES('%s',%s)"%(ip,score) ifnotre.match('\d+\.\d+\.\d+\.\d+\:\d+',ip): print('代理不符合规范',ip,'丢弃') return ifnotself.exists(ip): self.cursor.execute(sql_add) self.db.commit() #减少代理分数 defdecrease(self,ip): sql_get="SELECT*FROMPROXYWHEREIP='%s'"%(ip) self.cursor.execute(sql_get) score=self.cursor.fetchone()[1] print(score) ifscoreandscore>MIN_SCORE: print('代理',ip,'当前分数',score,'减1') sql_change="UPDATEPROXYSETSCORE=%sWHEREIP='%s'"%(score-1,ip) else: print('代理',ip,'当前分数',score,'移除') sql_change="DELETEFROMPROXYWHEREIP=%s"%(ip) self.cursor.execute(sql_change) self.db.commit() #分数最大化 defmax(self,ip): print('代理',ip,'可用,设置为',MAX_SCORE) sql_max="UPDATEPROXYSETSCORE=%sWHEREIP='%s'"%(MAX_SCORE,ip) self.cursor.execute(sql_max) self.db.commit() #随机获取有效代理 defrandom(self): #先从满分中随机选一个 sql_max="SELECT*FROMPROXYWHERESCORE=%s"%(MAX_SCORE) ifself.cursor.execute(sql_max): results=self.cursor.fetchall() returnchoice(results)[0] #没有满分则随机选一个 else: sql_all="SELECT*FROMPROXYWHERESCOREBETWEEN%sAND%s"%(MIN_SCORE,MAX_SCORE) ifself.cursor.execute(sql_all): results=self.cursor.fetchall() returnchoice(results)[0] else: raisePoolEmptyError #判断是否存在 defexists(self,ip): sql_exists="SELECT1FROMPROXYWHEREIP='%s'limit1"%ip returnself.cursor.execute(sql_exists) #获取数量 defcount(self): sql_count="SELECT*FROMPROXY" returnself.cursor.execute(sql_count) #获取全部 defall(self): self.count() returnself.cursor.fetchall() #批量获取 defbatch(self,start,stop): sql_batch="SELECT*FROMPROXYLIMIT%s,%s"%(start,stop-start) self.cursor.execute(sql_batch) returnself.cursor.fetchall()
方法作用:
- init():初始化的方法,参数是MySQL的连接信息,默认的连接信息已经定义为常量,在init()方法中初始化建立MySQL连接。这样当MySqlClient类初始化的时候就建立了MySQL的连接
- add():向数据库添加代理并设置分数,默认的分数是INITIAL_SCORE也就是10,返回结果是添加的结果
- decrease():在检测无效的时候设置分数减1的方法,传入代理,然后将此代理的分数减1,如果达到最低值就删除
- max():将代理的分数设置为MAX_SCORE,也就是当IP有效时的设置
- random():随机获取IP的方法,首先获取满分的IP,然后随机选择一个返回,如果不存在满分的IP,则随机选择一个返回,否则抛出异常
- exists():判断IP是否存在于数据库中
- count():返回当前IP个数
- all():返回所有的IP,供检测使用
- batch():返回数据库中从第start行开始(从0开始数)的共stop-start行数据
抓取保存
当数据库设置好了之后,就可以直接把抓取的IP直接放在数据库中了
直接把前面用到的抓取代码更改一下就行了
getter.py
fromcrawlerimportCrawler fromdbimportMySqlClient fromsettingimport* importsys classGetter(): def__init__(self): self.mysql=MySqlClient() self.crawler=Crawler() #判断数量是否足够 defis_over_threshold(self): ifself.mysql.count()>=POOL_UPPER_THRESHOLD: returnTrue else: returnFalse defrun(self): print('获取器开始执行') ifnotself.is_over_threshold(): forcallback_labelinrange(self.crawler.__CrawlFuncCount__): callback=self.crawler.__CrawlFunc__[callback_label] #获取代理 all_ip=self.crawler.get_proxies(callback) sys.stdout.flush() foripinall_ip: self.mysql.add(ip) if__name__=='__main__': get=Getter() get.run()
结果:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。