Python搭建 * 池实现存储IP的方法
作者:Steven·简谈 发布时间:2023-04-21 10:58:24
上一文写了如何从代理服务网站提取 IP,本文就讲解如何存储 IP,毕竟代理池还是要有一定量的 IP 数量才行。存储的方式有很多,直接一点的可以放在一个文本文件中,但操作起来不太灵活,而我选择的是 MySQL 数据库,因为数据库便于管理而且功能强大,当然你还可以选择其他数据库,比如 MongoDB、Redis 等。
代码地址:https://github.com/Stevengz/Proxy_pool
另外三篇:
Python搭建 * 池(一)- 获取 IP
Python搭建 * 池(三)- 检测 IP
Python搭建 * 池(四)- 接口设置与整体调度
使用的库: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()
# 添加 *
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()
结果:
来源:https://blog.csdn.net/weixin_44613063/article/details/102559219


猜你喜欢
- php mysql获取表字段名称和字段信息的三种方法先给出本实例中使用的表的信息:使用desc获取表字段信息php代码如下:<?php
- pygame实现代码雨动画如视频所示 利用pygame库实现了一个代码呈雨状下落的视觉效果部分代码如下import sysimport ra
- 本文实例为大家分享了python学生管理系统的具体代码,供大家参考,具体内容如下基于列表存储的学生管理系统,实现如下功能==========
- 好了,下面就是满足你设想的几个主程序,你还可以在实际应用中不断完善和扩充:login.asp' 考生验证<%@&nb
- 10个杀手级应用的Python自动化脚本重复的任务总是耗费时间和枯燥的。想象一下,逐一裁剪100张照片,或者做诸如Fetching APIs
- 环境准备卸载mariadbrpm -qa | grep mariadbrpm -e --nodeps mariadb-libs-5.5.60
- 自己也百度了一下,然后写的,分为了三个部分,见三段代码代码:主程序代码import timefrom selenium&
- 通常表中会有一个Create date 创建日期的字段,其它数据库均有默认值的选项。MySQL也有默认值timestamp,但在MySQL中
- 很高兴参加了这一期的薯片会,认识了几个朋友~~不料的却是今天我要来总结一下本次薯片会我们总共讨论了三个议题:A、 如何让“用户”更容易识别超
- MySQL当url连接不指定/数据库名可以访问到mysql服务器上有权限的任何库,但是所有sql需要加上库名前缀.pom<depend
- 这是用来快速学习 Python Socket 套接字编程的指南和教程。Python 的 Socket 编程跟 C 语言很像。Python 官
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&
- 本文实例讲述了SQLSERVER简单创建DBLINK操作远程服务器数据库的方法。分享给大家供大家参考,具体如下:--配置SQLSERVER数
- 简述在大多数此类教程中都会不遗余力的介绍如何使用数据库。今天我们对数据库暂且不表,而是来关注另一个在web应用中很重要的特性:如
- 快速入门In [1]: import time# 获取当前时间In [25]: time.strftime("%Y-%m-%d_%
- 本文详细介绍使用 PHP 动态构建 PDF 文件的整个过程。使用免费 PDF 库 (FPDF) 或 PDFLib-Lite 等开源工具进行实
- 今天我在练习python时,对字典里的键用sorted排序时发现并没有按照预期排序研究后发现字母大小写会影响排序首先创建一个字典,键里面的首
- 最近尝试写python GUI界面,决定先从tkinter开始。但是遇到了无法安装。执行pip install tkinter没有用,报了如
- 引言图片读入程序中后,是以numpy数组存在的。因此对numpy数组的一切功能,对图片也适用。对数组元素的访问,实际上就是对图片像素点的访问
- 1 背景&概述因某些需求,需要安装 TensorFlow ,很自然地在终端敲下了以下命令:pip install tensorflo