目錄
背景
一、什么是本地代理IP池
二、代理IP池功能架構(gòu)圖
三、各個(gè)組件功能說明及示例代碼
1. IP池管理器
2. 代理IP獲取器
3. IP質(zhì)量檢測器
4、數(shù)據(jù)存儲(chǔ)器
5、API接口層
6、應(yīng)用程序
總結(jié)
背景
在我們進(jìn)行爬蟲工作時(shí),經(jīng)常需要使用代理IP。大多數(shù)代理IP服務(wù)商為了保障服務(wù)器的持久穩(wěn)定性,提供的代理IP往往都有最小提取間隔限制,雖然很合理,但有些特殊要求需要0間隔提取代理IP的業(yè)務(wù)就無法使用,那么建立本地IP池,可以很好的實(shí)現(xiàn)0間隔提取代理IP。
?
一、什么是本地代理IP池
代理IP池是一種由多個(gè)代理IP構(gòu)成的集合,可以通過接口等方式隨時(shí)獲取可用的代理IP。通俗地打個(gè)比方,它就是一個(gè)池子,里面裝了很多代理ip。代理IP具有以下幾個(gè)特征:
? ? ? 1、池子里的ip是有生存周期的,它們將被定期驗(yàn)證,其中失效的將被剔除。
? ? ? 2、池子里的ip是有補(bǔ)充渠道的,不斷會(huì)有新的代理ip加入其中。
? ? ? 3、池子中的代理ip是可以被隨機(jī)取出來使用的。
這樣,代理池中始終有多個(gè)不斷更換的、有效的代理ip,且我們可以無間隔隨機(jī)從池子中取出代理ip,然后讓爬蟲程序使用代理ip訪問目標(biāo)網(wǎng)站,解決在爬蟲或其他應(yīng)用中遇到的封禁、限制等問題。
二、代理IP池功能架構(gòu)圖
自建代理IP池的功能架構(gòu)圖包括以下組件:
-
IP池管理器:用于管理IP池,包括IP地址的添加、刪除、查詢和更新等操作。
-
代理IP獲取器:用于從外部資源中獲取代理IP,例如從公開代理IP網(wǎng)站上爬取代理IP、從代理服務(wù)商訂購代理IP等。
-
IP質(zhì)量檢測器:用于檢測代理IP的質(zhì)量,包括代理IP的連接速度、穩(wěn)定性、匿名性等特征。
-
數(shù)據(jù)存儲(chǔ)器:用于存儲(chǔ)IP池和代理IP的數(shù)據(jù),例如使用MySQL等關(guān)系型數(shù)據(jù)庫、Redis等非關(guān)系型數(shù)據(jù)庫等。
-
API接口層:用于接收來自應(yīng)用程序的請求,調(diào)用IP池管理器、代理IP獲取器、IP質(zhì)量檢測器和數(shù)據(jù)存儲(chǔ)器等組件進(jìn)行處理,并返回相應(yīng)的數(shù)據(jù)結(jié)果。
-
應(yīng)用程序:用于調(diào)用API接口層,實(shí)現(xiàn)代理IP的使用、監(jiān)控和管理等功能。
?
三、各個(gè)組件功能說明及示例代碼
1. IP池管理器
IP池管理器的作用是管理IP池,它可以實(shí)現(xiàn)以下功能:
- 添加新的IP地址到IP池中;
- 刪除不需要的IP地址;
- 查詢IP池中的可用IP地址;
- 更新IP池中的IP地址信息。
這里以Python語言舉例,實(shí)現(xiàn)一個(gè)簡單的IP池管理器:
class IPPoolManager:
? ? def __init__(self, db):
? ? ? ? self.db = db ?# 數(shù)據(jù)庫連接
? ? def add_ip(self, ip, port, protocol='http', source='', status='new'):
? ? ? ? ''' 添加新的IP地址到IP池 '''
? ? ? ? cursor = self.db.cursor()
? ? ? ? sql = "INSERT INTO ip_pool(ip, port, protocol, source, status) VALUES(%s, %s, %s, %s, %s)"
? ? ? ? data = (ip, port, protocol, source, status)
? ? ? ? cursor.execute(sql, data)
? ? ? ? self.db.commit()
? ? ? ? return cursor.lastrowid ?# 返回添加記錄的ID
? ? def delete_ip(self, ip_id):
? ? ? ? ''' 從IP池中刪除不需要的IP地址 '''
? ? ? ? cursor = self.db.cursor()
? ? ? ? sql = "DELETE FROM ip_pool WHERE id=%s"
? ? ? ? cursor.execute(sql, (ip_id,))
? ? ? ? self.db.commit()
? ? def get_ip(self, status='new'):
? ? ? ? ''' 查詢IP池中的可用IP地址 '''
? ? ? ? cursor = self.db.cursor()
? ? ? ? sql = "SELECT * FROM ip_pool WHERE status=%s ORDER BY id DESC LIMIT 1"
? ? ? ? cursor.execute(sql, (status,))
? ? ? ? result = cursor.fetchone()
? ? ? ? return result
? ? def update_status(self, ip_id, status):
? ? ? ? ''' 更新IP池中的IP地址信息 '''
? ? ? ? cursor = self.db.cursor()
? ? ? ? sql = "UPDATE ip_pool SET status=%s WHERE id=%s"
? ? ? ? cursor.execute(sql, (status, ip_id))
? ? ? ? self.db.commit()
2. 代理IP獲取器
?負(fù)責(zé)定時(shí)(最小提取間隔)從代理IP服務(wù)商那里調(diào)用API接口獲取代理IP。當(dāng)然也可以爬取免費(fèi)代理IP,但為了提高工作效率,建議購買優(yōu)質(zhì)代理IP,這里使用了站大爺代理IP(https://www.zdaye.com)。注冊后可以免費(fèi)試用所有的套餐2小時(shí),生成API接口后,就可以提取到代理IP。
這里以站大爺代理IP接口為例,實(shí)現(xiàn)一個(gè)簡單的代理IP獲取器(需要使用requests庫):
import requests
def get_ip():
url = "https://www.zdaye.com" //在后臺(tái)的實(shí)例管理里面可以直接生成api接口,選擇JSON格式
res = requests.get(url)
# print(res.text)
for i in json.loads(res.text)["data"]:
print(i, type(i))
ip = {
"http": str(i["ip"]) + ":" + str(i["port"]),
"https": str(i["ip"]) + ":" + str(i["port"])
}
return ip
注意:我們拿到的代理是 {"ip":"117.57.91.154","port":40021} 這種樣子的;
爬蟲使用的代理要裝成:{'http': '163.125.104.6:40011', 'https': '163.125.104.6:40011'}這種樣子。
3. IP質(zhì)量檢測器
IP質(zhì)量檢測器的作用是檢測代理IP的質(zhì)量,包括代理IP的連接速度、穩(wěn)定性、匿名性等特征。這里以驗(yàn)證代理IP的可用性為例,實(shí)現(xiàn)一個(gè)簡單的IP質(zhì)量檢測器。
import requests
class IPChecker:
? ? def __init__(self):
? ? ? ? self.timeout = 5 ?# 設(shè)置超時(shí)時(shí)間
? ? ? ? self.headers = {
? ? ? ? ? ? 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36'}
? ? def check_ip(self, ip, port):
? ? ? ? ''' 驗(yàn)證代理IP的可用性 '''
? ? ? ? proxies = {'http': 'http://%s:%s' % (ip, port), 'https': 'https://%s:%s' % (ip, port)}
? ? ? ? try:
? ? ? ? ? ? response = requests.get('http://www.baidu.com', headers=self.headers, proxies=proxies, timeout=self.timeout)
? ? ? ? ? ? if response.status_code == 200:
? ? ? ? ? ? ? ? return True
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? return False
? ? ? ? except:
? ? ? ? ? ? return False
上面的代碼使用requests庫發(fā)送HTTP請求,通過設(shè)置proxies參數(shù)和timeout參數(shù)來驗(yàn)證代理IP是否可用,如果能正常訪問百度網(wǎng)站,則驗(yàn)證通過返回True,否則返回False。
4、數(shù)據(jù)存儲(chǔ)器
數(shù)據(jù)存儲(chǔ)器的作用是存儲(chǔ)IP池和代理IP的數(shù)據(jù),例如使用MySQL等關(guān)系型數(shù)據(jù)庫、Redis等非關(guān)系型數(shù)據(jù)庫等。這里以MySQL為例,實(shí)現(xiàn)一個(gè)簡單的數(shù)據(jù)存儲(chǔ)器。
import pymysql
class MySQLDataStorage:
? ? def __init__(self, host, port, user, password, database):
? ? ? ? self.host = host
? ? ? ? self.port = port
? ? ? ? self.user = user
? ? ? ? self.password = password
? ? ? ? self.database = database
? ? def connect(self):
? ? ? ? ''' 連接數(shù)據(jù)庫 '''
? ? ? ? self.db = pymysql.connect(host=self.host, port=self.port, user=self.user, password=self.password, database=self.database)
? ? def disconnect(self):
? ? ? ? ''' 斷開數(shù)據(jù)庫連接 '''
? ? ? ? self.db.close()
? ? def create_table(self):
? ? ? ? ''' 創(chuàng)建IP池表 '''
? ? ? ? cursor = self.db.cursor()
? ? ? ? sql = '''
? ? ? ? CREATE TABLE IF NOT EXISTS ip_pool (
? ? ? ? ? ? id INT(11) NOT NULL AUTO_INCREMENT,
? ? ? ? ? ? ip VARCHAR(50) NOT NULL,
? ? ? ? ? ? port VARCHAR(10) NOT NULL,
? ? ? ? ? ? protocol VARCHAR(10) NOT NULL,
? ? ? ? ? ? source VARCHAR(50) NOT NULL,
? ? ? ? ? ? status VARCHAR(10) NOT NULL,
? ? ? ? ? ? created_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
? ? ? ? ? ? PRIMARY KEY (id)
? ? ? ? ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
? ? ? ? '''
? ? ? ? cursor.execute(sql)
? ? ? ? self.db.commit()
? ? def insert(self, ip, port, protocol, source, status):
? ? ? ? ''' 添加新的IP地址到IP池 '''
? ? ? ? cursor = self.db.cursor()
? ? ? ? sql = "INSERT INTO ip_pool(ip, port, protocol, source, status) VALUES(%s, %s, %s, %s, %s)"
? ? ? ? data = (ip, port, protocol, source, status)
? ? ? ? cursor.execute(sql, data)
? ? ? ? self.db.commit()
? ? ? ? return cursor.lastrowid ?# 返回添加記錄的ID
? ? def delete(self, ip_id):
? ? ? ? ''' 從IP池中刪除不需要的IP地址 '''
? ? ? ? cursor = self.db.cursor()
? ? ? ? sql = "DELETE FROM ip_pool WHERE id=%s"
? ? ? ? cursor.execute(sql, (ip_id,))
? ? ? ? self.db.commit()
? ? def select(self, status='new'):
? ? ? ? ''' 查詢IP池中的可用IP地址 '''
? ? ? ? cursor = self.db.cursor()
? ? ? ? sql = "SELECT * FROM ip_pool WHERE status=%s ORDER BY id DESC LIMIT 1"
? ? ? ? cursor.execute(sql, (status,))
? ? ? ? result = cursor.fetchone()
? ? ? ? return result
? ? def update(self, ip_id, status):
? ? ? ? ''' 更新IP池中的IP地址信息 '''
? ? ? ? cursor = self.db.cursor()
? ? ? ? sql = "UPDATE ip_pool SET status=%s WHERE id=%s"
? ? ? ? cursor.execute(sql, (status, ip_id))
? ? ? ? self.db.commit()
上面的代碼封裝了MySQL的連接、斷開連接、創(chuàng)建表、增刪改查等操作,可以通過調(diào)用接口實(shí)現(xiàn)IP池?cái)?shù)據(jù)庫的交互。注意,這里使用了execute()函數(shù)的帶參數(shù)方式來防止SQL注入攻擊。
5、API接口層
API接口層的作用是提供API接口,讓其他程序可以與IP池系統(tǒng)進(jìn)行交互,例如查詢可用代理IP、獲取新的代理IP等。這里以Python Flask框架為例,實(shí)現(xiàn)一個(gè)簡單的API接口層。```
from flask import Flask, jsonify
from ip_pool_manager import IPPoolManager
app = Flask(__name__)
manager = IPPoolManager() ?# 初始化IP池管理器
@app.route('/')
def hello_world():
? ? return 'Hello, World!'
@app.route('/get')
def get_proxy():
? ? ''' 查詢可用代理IP '''
? ? result = manager.get_ip()
? ? if result:
? ? ? ? ip = result['ip']
? ? ? ? port = result['port']
? ? ? ? protocol = result['protocol']
? ? ? ? manager.update_status(result['id'], 'using') ?# 更新IP狀態(tài)為使用中
? ? ? ? return jsonify({'ip': ip, 'port': port, 'protocol': protocol})
? ? else:
? ? ? ? # 如果沒有可用IP,則返回空
? ? ? ? return ''
@app.route('/add/<ip>/<port>')
def add_proxy(ip, port):
? ? ''' 添加新的代理IP '''
? ? manager.add_ip(ip, port)
? ? return 'ok'
@app.route('/delete/<int:id>')
def delete_proxy(id):
? ? ''' 刪除不需要的代理IP '''
? ? manager.delete_ip(id)
? ? return 'ok'
if __name__ == '__main__':
? ? app.run()
上面的代碼使用了Flask框架實(shí)現(xiàn)了三個(gè)接口:
- /get:查詢可用代理IP;
- /add:添加新的代理IP;
- /delete:刪除不需要的代理IP。
其中,get_proxy()函數(shù)從IP池管理器中獲取可用代理IP,并更新IP狀態(tài)為使用中,返回JSON格式的數(shù)據(jù);add_proxy()函數(shù)向IP池管理器中添加新的代理IP;delete_proxy()函數(shù)從IP池管理器中刪除不需要的代理IP。啟動(dòng)Flask應(yīng)用程序后,其他程序可以通過HTTP請求調(diào)用這些接口與IP池系統(tǒng)進(jìn)行交互。
6、應(yīng)用程序
以下是一個(gè)簡單的應(yīng)用程序示例。它使用IP池系統(tǒng)提供的可用代理IP,并使用requests庫實(shí)現(xiàn)了一個(gè)簡單的爬蟲示例。
import requests
from bs4 import BeautifulSoup
from ip_checker import IPChecker
from ip_pool_manager import IPPoolManager
import time
def main():
? ? checker = IPChecker()
? ? manager = IPPoolManager()
? ? while True:
? ? ? ? ip_info = manager.get_ip() ?# 獲取可用代理IP
? ? ? ? if ip_info:
? ? ? ? ? ? ip = ip_info.get('ip')
? ? ? ? ? ? port = ip_info.get('port')
? ? ? ? ? ? protocol = ip_info.get('protocol')
? ? ? ? ? ? if checker.check_ip(ip, port):
? ? ? ? ? ? ? ? print(f'使用代理IP {ip}:{port} 獲取數(shù)據(jù)')
? ? ? ? ? ? ? ? proxies = {'http': f'{protocol}://{ip}:{port}', 'https': f'{protocol}://{ip}:{port}'}
? ? ? ? ? ? ? ? response = requests.get('http://www.baidu.com', proxies=proxies)
? ? ? ? ? ? ? ? # 這里可以根據(jù)需要解析返回的數(shù)據(jù)
? ? ? ? ? ? ? ? soup = BeautifulSoup(response.text, 'html.parser')
? ? ? ? ? ? ? ? print(soup.title.string)
? ? ? ? ? ? ? ? time.sleep(5) ?# 延遲5秒后繼續(xù)獲取
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? # 如果代理IP不可用,則將其狀態(tài)設(shè)置為失效
? ? ? ? ? ? ? ? manager.update_status(ip_info['id'], 'invalid')
? ? ? ? else:
? ? ? ? ? ? # 如果沒有可用代理IP,則等待一段時(shí)間后再嘗試獲取
? ? ? ? ? ? time.sleep(60)
if __name__ == '__main__':
? ? main()
以上代碼的主函數(shù)中使用IP池系統(tǒng)提供的可用代理IP,使用requests庫發(fā)送HTTP請求,獲取返回的數(shù)據(jù)。如果返回的數(shù)據(jù)解析成功,控制臺(tái)輸出網(wǎng)站的標(biāo)題,然后等待5秒后繼續(xù)獲取。如果代理IP不可用或者IP池中沒有可用的IP,程序會(huì)等待一段時(shí)間后再嘗試獲取。文章來源:http://www.zghlxwxcb.cn/news/detail-481121.html
總結(jié)
有了本地IP池,可以更加方便的管理和使用代理IP,不僅可以0間隔提取代理IP,還能提高爬蟲的工作效率。文章來源地址http://www.zghlxwxcb.cn/news/detail-481121.html
到了這里,關(guān)于Python爬蟲——怎么搭建和維護(hù)一個(gè)本地IP池的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!