Python搭建代理IP池实现存储IP的方法


Posted in Python onOctober 27, 2019

上一文写了如何从代理服务网站提取 IP,本文就讲解如何存储 IP,毕竟代理池还是要有一定量的 IP 数量才行。存储的方式有很多,直接一点的可以放在一个文本文件中,但操作起来不太灵活,而我选择的是 MySQL 数据库,因为数据库便于管理而且功能强大,当然你还可以选择其他数据库,比如 MongoDB、Redis 等。

代码地址:https://github.com/Stevengz/Proxy_pool

另外三篇:

使用的库: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

import pymysql
from error import PoolEmptyError
from setting import *
from random import choice
import re


class MySqlClient(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
 def add(self, ip, score=INITIAL_SCORE):
  sql_add = "INSERT INTO PROXY (IP,SCORE) VALUES ('%s', %s)" % (ip, score)
  if not re.match('\d+\.\d+\.\d+\.\d+\:\d+', ip):
   print('代理不符合规范', ip, '丢弃')
   return
  if not self.exists(ip):
   self.cursor.execute(sql_add)
   self.db.commit()

 # 减少代理分数
 def decrease(self, ip):
  sql_get = "SELECT * FROM PROXY WHERE IP='%s'" % (ip)
  self.cursor.execute(sql_get)
  score = self.cursor.fetchone()[1]
  print(score)
  if score and score > MIN_SCORE:
   print('代理', ip, '当前分数', score, '减1')
   sql_change = "UPDATE PROXY SET SCORE = %s WHERE IP = '%s'" % (score-1, ip)
  else:
   print('代理', ip, '当前分数', score, '移除')
   sql_change = "DELETE FROM PROXY WHERE IP = %s" % (ip)
  self.cursor.execute(sql_change)
  self.db.commit()

 # 分数最大化
 def max(self, ip):
  print('代理', ip, '可用,设置为', MAX_SCORE)
  sql_max = "UPDATE PROXY SET SCORE = %s WHERE IP = '%s'" % (MAX_SCORE, ip)
  self.cursor.execute(sql_max)
  self.db.commit()
  
 # 随机获取有效代理
 def random(self):
  # 先从满分中随机选一个
  sql_max = "SELECT * FROM PROXY WHERE SCORE=%s" % (MAX_SCORE)
  if self.cursor.execute(sql_max):
   results = self.cursor.fetchall()
   return choice(results)[0]
  # 没有满分则随机选一个
  else:
   sql_all = "SELECT * FROM PROXY WHERE SCORE BETWEEN %s AND %s" % (MIN_SCORE, MAX_SCORE)
   if self.cursor.execute(sql_all):
    results = self.cursor.fetchall()
    return choice(results)[0]
   else:
    raise PoolEmptyError

 # 判断是否存在
 def exists(self, ip):
  sql_exists = "SELECT 1 FROM PROXY WHERE IP='%s' limit 1" % ip
  return self.cursor.execute(sql_exists)
  
 # 获取数量
 def count(self):
  sql_count = "SELECT * FROM PROXY"
  return self.cursor.execute(sql_count)

 # 获取全部
 def all(self):
  self.count()
  return self.cursor.fetchall()

 # 批量获取
 def batch(self, start, stop):
  sql_batch = "SELECT * FROM PROXY LIMIT %s, %s" % (start, stop - start)
  self.cursor.execute(sql_batch)
  return self.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

from crawler import Crawler
from db import MySqlClient
from setting import *
import sys


class Getter():
 def __init__(self):
  self.mysql = MySqlClient()
  self.crawler = Crawler()

 # 判断数量是否足够
 def is_over_threshold(self):
  if self.mysql.count() >= POOL_UPPER_THRESHOLD:
   return True
  else:
   return False
 
 def run(self):
  print('获取器开始执行')
  if not self.is_over_threshold():
   for callback_label in range(self.crawler.__CrawlFuncCount__):
    callback = self.crawler.__CrawlFunc__[callback_label]
    # 获取代理
    all_ip = self.crawler.get_proxies(callback)
    sys.stdout.flush()
    for ip in all_ip:
     self.mysql.add(ip)


if __name__ == '__main__':
 get = Getter()
 get.run()

结果:

Python搭建代理IP池实现存储IP的方法

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python解决字典中的值是列表问题的方法
Mar 04 Python
python使用三角迭代计算圆周率PI的方法
Mar 20 Python
Python开发微信公众平台的方法详解【基于weixin-knife】
Jul 08 Python
Python SqlAlchemy动态添加数据表字段实例解析
Feb 07 Python
为什么入门大数据选择Python而不是Java?
Mar 07 Python
Tensorflow卷积神经网络实例
May 24 Python
pandas.dataframe中根据条件获取元素所在的位置方法(索引)
Jun 07 Python
Python爬虫之网页图片抓取的方法
Jul 16 Python
Python从数据库读取大量数据批量写入文件的方法
Dec 10 Python
Django实现一对多表模型的跨表查询方法
Dec 18 Python
Pytorch 实现数据集自定义读取
Jan 18 Python
Spring @Enable模块驱动原理及使用实例
Jun 23 Python
Python搭建代理IP池实现获取IP的方法
Oct 27 #Python
详解python statistics模块及函数用法
Oct 27 #Python
在 Jupyter 中重新导入特定的 Python 文件(场景分析)
Oct 27 #Python
python自动结束mysql慢查询会话的实例代码
Oct 27 #Python
python实现输入任意一个大写字母生成金字塔的示例
Oct 27 #Python
python 爬虫百度地图的信息界面的实现方法
Oct 27 #Python
python用类实现文章敏感词的过滤方法示例
Oct 27 #Python
You might like
php的计数器程序
2006/10/09 PHP
在php中判断一个请求是ajax请求还是普通请求的方法
2011/06/28 PHP
PHP乱码问题,UTF-8乱码常见问题小结
2012/04/09 PHP
php获取系统变量方法小结
2015/05/29 PHP
PHP全局使用Laravel辅助函数dd
2019/12/26 PHP
深入理解JavaScript系列(9) 根本没有“JSON对象”这回事!
2012/01/15 Javascript
Javascript浅谈之引用类型
2013/12/18 Javascript
web前端设计师们常用的jQuery特效插件汇总
2014/12/07 Javascript
jQuery实现表格颜色交替显示的方法
2015/03/09 Javascript
angularjs创建弹出框实现拖动效果
2020/08/25 Javascript
动态JavaScript所造成一些你不知道的危害
2016/09/25 Javascript
javascript的document中的动态添加标签实现方法
2016/10/24 Javascript
详解js中Number()、parseInt()和parseFloat()的区别
2016/12/20 Javascript
Nodejs中使用phantom将html转为pdf或图片格式的方法
2017/09/18 NodeJs
dropload.js插件下拉刷新和上拉加载使用详解
2017/10/20 Javascript
layui表格checkbox选择全选样式及功能的实例
2018/03/07 Javascript
Bootstrap 模态框自定义点击和关闭事件详解
2018/08/10 Javascript
vue+Element实现搜索关键字高亮功能
2019/05/28 Javascript
微信小程序 轮播图实现原理及优化详解
2019/09/29 Javascript
javascript this指向相关问题及改变方法
2020/11/19 Javascript
JavaScript字符串转数字的简单实现方法
2020/11/27 Javascript
python从ftp下载数据保存实例
2013/11/20 Python
python操作列表的函数使用代码详解
2017/12/28 Python
Python自定义线程类简单示例
2018/03/23 Python
用python脚本24小时刷浏览器的访问量方法
2018/12/07 Python
python  文件的基本操作 菜中菜功能的实例代码
2019/07/17 Python
基于 HTML5 的 WebGL 3D 版俄罗斯方块的示例代码
2018/05/28 HTML / CSS
预订从美国飞往印度的机票:MyTicketsToIndia
2017/05/19 全球购物
衰败城市英国官网:Urban Decay英国
2020/04/29 全球购物
国际贸易系求职信
2014/08/09 职场文书
思想作风纪律整顿心得体会
2014/09/04 职场文书
争先创优演讲稿
2014/09/15 职场文书
开展党的群众路线教育实践活动总结报告
2014/10/31 职场文书
小学班主任工作随笔
2015/08/15 职场文书
springboot+WebMagic+MyBatis爬虫框架的使用
2021/08/07 Java/Android
MySQL的prepare使用以及遇到的bug
2022/05/11 MySQL