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实现批量注册网站用户的示例
Feb 22 Python
Ubuntu18.04中Python2.7与Python3.6环境切换
Jun 14 Python
python文件选择对话框的操作方法
Jun 27 Python
django基础学习之send_mail功能
Aug 07 Python
django 自定义过滤器(filter)处理较为复杂的变量方法
Aug 12 Python
Python操作列表常用方法实例小结【创建、遍历、统计、切片等】
Oct 25 Python
python时间与Unix时间戳相互转换方法详解
Feb 13 Python
简单了解Python多态与属性运行原理
Jun 15 Python
查看keras的默认backend实现方式
Jun 19 Python
浅析Python 条件控制语句
Jul 15 Python
Python APScheduler执行使用方法详解
Dec 10 Python
python中K-means算法基础知识点
Jan 25 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.ini中的php-5.2.0配置指令详解
2008/03/27 PHP
php 执行系统命令的方法
2009/07/07 PHP
php中通过curl模拟登陆discuz论坛的实现代码
2012/02/16 PHP
解析:通过php socket并借助telnet实现简单的聊天程序
2013/06/18 PHP
php操作redis中的hash和zset类型数据的方法和代码例子
2014/07/05 PHP
Laravel5.4框架中视图共享数据的方法详解
2019/09/05 PHP
jQuery插件 tabBox实现代码
2010/02/09 Javascript
浅析Bootstrap表格的使用
2016/06/23 Javascript
JavaScript中this的用法及this在不同应用场景的作用解析
2017/04/13 Javascript
vue中父子组件注意事项,传值及slot应用技巧
2018/05/09 Javascript
Vue 获取数组键名的方法
2018/06/21 Javascript
elementUI Vue 单个按钮显示和隐藏的变换功能(两种方法)
2018/09/04 Javascript
Vue $emit $refs子父组件间方法的调用实例
2018/09/12 Javascript
微信小程序动态添加view组件的实例代码
2019/05/23 Javascript
react 移动端实现列表左滑删除的示例代码
2019/07/04 Javascript
vuex存储复杂参数(如对象数组等)刷新数据丢失的解决方法
2019/11/05 Javascript
PHP 502bad gateway原因及解决方案
2020/11/13 Javascript
[03:27]《辉夜杯》线下训练营 导师CU和海涛指点迷津
2015/10/23 DOTA
[43:41]VP vs RNG 2019国际邀请赛淘汰赛 败者组 BO3 第二场 8.21.mp4
2020/07/19 DOTA
基于Python闭包及其作用域详解
2017/08/28 Python
python K近邻算法的kd树实现
2018/09/06 Python
Python使用pyautocad+openpyxl处理cad文件示例
2019/07/11 Python
终于搞懂了Keras中multiloss的对应关系介绍
2020/06/22 Python
HTML5给汉字加拼音收起展开组件的实现代码
2020/04/08 HTML / CSS
Moss Bros官网:英国排名第一的西装店
2020/02/26 全球购物
企业管理部经理岗位职责
2013/12/24 职场文书
信电学院毕业生自荐书
2014/05/24 职场文书
银行开户授权委托书格式
2014/10/10 职场文书
故意伤害罪辩护词
2015/05/21 职场文书
教师师德工作总结2015
2015/07/22 职场文书
唱歌比赛拉拉队口号
2015/12/25 职场文书
Vue3.0中Ref与Reactive的区别示例详析
2021/07/07 Vue.js
SpringCloud项目如何解决log4j2漏洞
2022/04/10 Java/Android
java开发双人五子棋游戏
2022/05/06 Java/Android
解决Oracle数据库用户密码过期
2022/05/11 Oracle
mysql字段为NULL索引是否会失效实例详解
2022/05/30 MySQL