Python代理IP池存储方案:基于MySQL的分数管理与实现

七月
七月
发布时间:2026-10-13 | 5人浏览过
原创

本文详解如何使用MySQL数据库存储Python代理IP池中的IP地址。通过定义MAX_SCORE、MIN_SCORE和INITIAL_SCORE等参数,实现IP可用性的动态评分机制。文章提供了完整的数据库连接配置、核心操作方法(添加、减分、获取)及抓取保存代码,帮助开发者构建高效、自动化的代理IP管理系统。

代理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,还需定义一个分数字段。该分数允许重复,建议采用整数类型,为每个IP分配一个代表其可用性的分数值。

在代理池中,分数是判断代理是否可用的关键指标。我们设定一个最高分(满分,具体数值由开发者自定义)代表IP可用,0分为最低分,代表不可用。从代理池获取代理时,系统会优先从满分IP中随机选取一个,这种随机机制确保了每个可用IP都有被调用的机会。若不存在满分IP,则从所有IP中随机选择一个。

具体的分数规则如下:

  • 满分表示IP可用。检测器会定时循环检测每个IP的状态,一旦检测到IP可用,立即将其分数置为满分;若检测到IP不可用,则将其分数减1,当分数减至0时,该IP将被移除。
  • 新获取的代理在添加时,初始分数设置为10。如果测试可行,立即将分数置为100;若不可行,分数减1,当分数减至0后,该IP将被移除。

数据库配置与分数规则定义

添加与配置设置

首先在一个配置文件中定义相关参数,包括数据库连接设置以及不变量(如满分的数值等)。

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类初始化时,即完成数据库连接的建立。
  • add():向数据库添加代理并设置分数,默认分数为INITIAL_SCORE(即10),返回添加结果。
  • decrease():在检测无效时调用,使传入代理的分数减1。若分数达到最低值,则执行删除操作。
  • max():将代理分数设置为MAX_SCORE,即当IP被判定为有效时进行设置。
  • random():随机获取IP的方法。首先尝试获取满分IP并随机返回一个;若不存在满分IP,则从所有IP中随机选择一个返回;否则抛出异常。
  • exists():判断指定IP是否存在于数据库中。
  • count():返回当前数据库中IP的总个数。
  • all():返回所有IP,供检测程序使用。
  • batch():返回数据库中从第start行开始(索引从0开始)的共stop-start行数据。

IP抓取与保存流程

抓取与保存流程

当数据库配置完成后,即可将抓取的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 相关产品和应用

全部下载

专题列表