from random import choice,randint
from fake_useragent import UserAgent
from pymongo import MongoClient
from bson.binary import Binary
from datetime import datetime
import lxml.html
import requests
import time
import pickle
class MongoCache_Proxies(object):
"""
数据库缓存
"""
def __init__(self,client=None):
"""
初始化函数
:param client: 数据库链接
"""
self.client = MongoClient('localhost',27017)
self.db = self.client.IP_Proxies
ip_proxies_ = self.db.Proxies
self.db.Proxies.create_index('time')
if self.db.Proxies.find().count() == 0:
record = {"result": Binary(pickle.dumps({'http': 'http://localhost:80'})), 'time': datetime.now()}
self.db.Proxies.update({'_id': 1}, {'$set': record}, upsert=True)
def __setitem__(self, key, value):
"""
向数据库中添加数据
:param key: 缓存关键字
:param value: 缓存内容
:return:
"""
# 将proxies 数据序列化,并转化为mongodb能够存储的格式存储起来
record = {"result":Binary(pickle.dumps(value)),'time':datetime.now()}
self.db.Proxies.update({'_id':key},{'$set':record},upsert=True)
def __getitem__(self, item):
"""
将缓存数据按照item作为key取出
:param item:
:return:
"""
record = self.db.Proxies.find_one({'_id':item})
if record:
return pickle.loads(record['result'])
else:
raise KeyError(str(item) + 'does not exist')
def __contains__(self, item):
"""
当调用in,not in 会调用该方法判断对应网址是否在数据库的缓存中
:param item: 下载的url链接
:return:
"""
try:
self[item]
except KeyError:
return False
else:
return True
def clear(self):
self.db.Proxies.drop()
def count_all(self):
return self.db.Proxies.find().count()
class Random_Proxies(object):
"""
从指定代理网址下载代理ip
"""
def __init__(self):
"""
初始化下载
"""
_au = UserAgent()
# 需要下载的代理网址的网址格式化处理,
# 如果有特殊的规律需要自行添加占位符,方便后续处理
self.url_base = 'https://www.xxxx/xxxxx/{}/'
self.headers = {'UserAgent':_au.random}
self.db = MongoCache_Proxies()
def url_lists(self):
"""
下载列表
"""
# 处理格式化的网址,并返回列表
return [self.url_base.format(i) for i in range(2,35)]
def download_html(self,url_str):
"""
下载页面
:param url_str:
:return:
"""
result = requests.get(url_str,headers=self.headers,proxies=self.random_proxies())
return result.content.decode('utf-8')
# 有些网址获取后不能是使用utf-8解码,需要使用不同的解码格式或者不解码
# return result.content.decode('gbk')
def parse_lxml(self,html_str):
"""
提取ip并拼接为指定格式
:param html_str:
:return:
"""
ip_list = []
html = lxml.html.fromstring(html_str)
# ip和prot的xpath路径
# // 代表的是当前的位置,可以随意指定
# table 表示标签
# 下级标签用 / 隔开
# td[@data-title="IP"] 表示 td标签中 属性名为data-title 值为"IP"的标签 用于筛选指定的标签下的内容
# /text() 表示提取标签中的文档内容
# 可以根据实际需要修改路径
ip_data = html.xpath('//table/tbody/tr/td[@data-title="IP"]/text()')
port_data = html.xpath('//table/tbody/tr/td[@data-title="PORT"]/text()')
if not ip_data or not port_data:
raise KeyError('ip list or port list is None!')
for i in range(len(ip_data)-1):
ip_str = ip_data[i] + ':' + port_data[i]
ip_list.append(ip_str)
return ip_list
def save_ip_str(self,ip_list):
"""
保存数据
:return:
"""
id_ = self.db.count_all()
for i in ip_list:
id_ += 1
dict_ = {"http":"http://" + i}
self.db[id_] = dict_
def download(self):
url_lists = self.url_lists()
for i in url_lists:
print('开始存储::::::', i)
time.sleep(randint(2,5))
html_str = self.download_html(i)
ip_list = self.parse_lxml(html_str)
self.save_ip_str(ip_list)
print('下载完成')
def random_proxies(self):
"""
随机取出存储的proxies
"""
return self.db[randint(1,self.db.count_all())]
def random_proxies():
"""
生成随机的proxies
:return: 随机的proxies 字典格式
"""
self = Random_Proxies()
return self.db[randint(1,self.db.count_all())]
# 测试
if __name__ == '__main__':
cc = Random_Proxies()
# 清空数据表中的内容
# cc.db.clear()
# 下载内容到数据表中
# cc.download()
# 随机生成5个数据,并查看类型
for i in range(5):
print(cc.random_proxies())
print(type(cc.random_proxies()))
使用条件:安装了python MongoDB
文件保存为.py
格式
先在本文保存的地方运行
cc.download()
下载数据到数据库中在需要的地方导入
from 这个文件保存的名字 import random_proxies
然后直接使用 random_proxies() 会返回随机的proxies字典,如需保存可以赋值给其他变量即可