ProxiesPool IP代理池

MongoDB和flask实现的一个IP代理池

源代码地址,直接下载既可以使用,已包含依赖包

​https://github.com/FelixZFB/ProxiesPool​

基本思路:

  • 获取代理IP: 爬取网站的免费代理。比如西刺、快代理之类有免费代理的网站, 但是这些免费代理大多数情况下都是不好用的,所以比较靠谱的方法是购买付费代理。当然,如果你有更好的代理接口也可以自己接入。
  • 检测IP代理可用性: 因为免费代理大部分是不可用的,所以采集回来的代理IP不能直接使用,可以写检测程序不断的去用这些代理访问一个稳定的网站,看是否可以正常使用。
  • 存储代理IP: 存储的代理IP首先要保证代理不重复 , 要检测代理的可用情况,还要动态实时处理每个代理,本文利用来MongoDB存储,当然也可用其他方式存储。
  • 使用代理:最简单的办法就是用 API 来提供对外服务的接口 。

实现逻辑:

- 1.爬取免费代理IP网站(西刺代理,快代理,66代理等)的高匿代理
- 2.检测出有效的高匿代理,存储到MongoDB数据库中
- 3.定时检测MongoDB数据库已有IP代理是否有效,进行更新删除
- 4.使用flask的api接口调用IP代理池中的IP代理

Python实现IP代理池(MondoDB和Flask实现)_IP

IP代理池启动方式:

- 1.启动本地MongoDB数据库
- 2.运行main.py
- 3.外部api调用

外部调用方式:

参考api_demo.py

import requests
PROXY_POOL_URL = 'http://127.0.0.1:5000/one' # one proxy
PROXIES_POOL_URL = 'http://127.0.0.1:5000/all' # all proxies

下面方几个主要代码,完整代码查看源码

main.py 主程序(调度器)

from multiprocessing import Process
from Crawler.check_crawl_ip import CheckIp, CrawlIp
from api import run

def proxy_run():
# 数据库中ip检测进程
check_process = Process(target=CheckIp().check)
# 爬取ip代理的进程
crawl_process = Process(target=CrawlIp().crawl)
# api接口进程,用于从数据库中取出一个或者全部ip代理
run_process = Process(target=run)

# 启动所有进程
check_process.start()
crawl_process.start()
run_process.start()

# 等待所有进程结束
check_process.join()
crawl_process.join()
run_process.join()


if __name__ == '__main__':
proxy_run()

get_proxy.py 下载模块(获取代理)

import requests
import chardet
import traceback
import user_agent
from lxml import etree
from requests.exceptions import ConnectionError


class GetProxy():
def __init__(self):
self.headers = {"User-Agent": user_agent.generate_user_agent()}

# 判断提供ip代理网站是否有效,返回网页html文档
def parse_url(self, url):
try:
response = requests.get(url, headers=self.headers)
response.encoding = chardet.detect(response.content)["encoding"]
if response.status_code == 200:
return response.text
else:
return None
except ConnectionError:
print("Error.")
return None

# 获取西刺代理网站免费代理ip
def xici_proxy(self):
# 只获取网站高匿代理前20页的代理
xici_list = list()
for i in range(1, 20):
url = "https://www.xicidaili.com/nn/{}".format(i)
response = self.parse_url(url)
# 上面的response类型有时候是NoneType,有些是str,下面使用str(response)
html = etree.HTML(str(response), etree.HTMLParser())
# 所有的ip和port都是放在属性为ip_list标签下的tr标签里面
# ip_list属性唯一,下面两种方式都是选取所有属性id='ip_list'的标签
ip_list = html.xpath("//table[@id='ip_list']/tr/td[2]/text()")
port_list = html.xpath("//*[@id='ip_list']/tr/td[3]/text()")

# ip和port生成一个一一对应的元组列表,然后取出
for ip, port in zip(ip_list, port_list):
proxy = ip + ":" + port
proxy = {"proxy": proxy} # 返回的代理是字典的格式,方便直接存储到mongodb数据库中
# yield proxy
xici_list.append(proxy)
return xici_list

# 获取快代理网站免费代理ip
def kuai_proxy(self):
# 只获取网站高匿代理前20页的代理
kuai_list = list()
for i in range(1, 20):
url = "https://www.kuaidaili.com/free/inha/{}/".format(i)
response = self.parse_url(url)
# 上面的response类型有时候是NoneType,有些是str,下面使用str(response)
html = etree.HTML(str(response), etree.HTMLParser())
# 所有的ip和port都是放在属性为list的div/table/tbody下的tr标签里面
ip_list = html.xpath("//div[@id='list']/table/tbody/tr/td[1]/text()")
port_list = html.xpath("//div[@id='list']/table/tbody/tr/td[2]/text()")

# ip和port生成一个一一对应的元组列表,然后取出
for ip, port in zip(ip_list, port_list):
proxy = ip + ":" + port
proxy = {"proxy": proxy} # 返回的代理是字典的格式,方便直接存储到mongodb数据库中
# yield proxy
kuai_list.append(proxy)
return kuai_list

# 获取快代理网站免费代理ip
def liuliu_proxy(self):
# 只获取网站高匿代理前20页的代理
# liuliu_list = list()
for i in range(1, 20):
url = "http://www.66ip.cn/{}.html".format(i)
response = self.parse_url(url)
# 上面的response类型有时候是NoneType,有些是str,下面使用str(response)
html = etree.HTML(str(response), etree.HTMLParser())
# 所有的ip和port都是放在属性为list的div/table/tbody下的tr标签里面,列表第一个元素是标题栏,去除掉
ip_list = html.xpath("//div[@class='containerbox boxindex']/div[1]/table[1]//tr/td[1]/text()")[1:]
port_list = html.xpath("//div[@class='containerbox boxindex']/div[1]/table[1]//tr/td[2]/text()")[1:]

# ip和port生成一个一一对应的元组列表,然后取出
for ip, port in zip(ip_list, port_list):
proxy = ip + ":" + port
proxy = {"proxy": proxy} # 返回的代理是字典的格式,方便直接存储到mongodb数据库中
yield proxy
# liuliu_list.append(proxy)
# return liuliu_list

# 自己可以扩充代理网站
def other_proxy(self):
pass


if __name__ == '__main__':
res = GetProxy().liuliu_proxy()
print(res)
for i in res:
print(type(i))
print(i)

mongo_db.py 存储模块(存储代理到数据库)

import pymongo
from pymongo.errors import DuplicateKeyError


class MongoDB():

def __init__(self):
# 连接mongodb服务器,先启动mongodb服务器和客户端
self.client = pymongo.MongoClient(host="localhost", port=27017)
# 连接ProxiesPool数据库,可以先在mongodb中创建ProxiesPool数据库,集合插入数据时会自动创建
self.db = self.client['ProxiesPool']
# 连接ProxiesPool数据库下的proxies集合
self.proxies = self.db['proxies']
# 给proxy字段创建一个新的索引,加快查询的速度
self.proxies.ensure_index('proxy', unique=True)

# 插入数据
def insert(self, proxy):
try:
self.proxies.insert(proxy)
print("插入成功:{}".format(proxy))
except DuplicateKeyError:
pass

# 删除数据
def delete(self, conditions):
self.proxies.remove(conditions)
print("删除成功:{}".format(conditions))

# 更新数据
def update(self, conditions, values):
self.proxies.update(conditions, {"$set": values})
print("更新成功:{},{}".format(conditions, values))

# 取出所有的数据,count是check_crawl_ip获取到的ip代理数量
def get(self, count, conditions=None):
conditions = conditions if conditions else {}
count = int(count)
items = self.proxies.find(conditions) # conditions=None,即默认查找所有的proxies集合下所有的文档
# 取出数据,按delay进行排序,延时小的放在列表前面,用的时候可以先拿出来
# items = self.proxies.find(conditions, limit=count).sort("delay", pymongo.ASCENDING)
items = list(items)
return items

# 统计数据库中代理个数
def get_count(self):
return self.proxies.count({}) # {}条件为空,即统计全部数据


if __name__ == '__main__':
mongodb = MongoDB()
print(mongodb.get(3))

test_proxy.py 检测模块(检测代理是否有效)

import requests
import time
from requests.exceptions import ProxyError, ConnectionError
from MongoDB.mongo_db import MongoDB
from multiprocessing.pool import ThreadPool


class TestIp():

def test_all(self, proxy_list, method):
# 进程池中同时最多16个进程
pool = ThreadPool(16)
# 向进程池中添加任务
for proxy in proxy_list:
pool.apply_async(self.test_one, args=(proxy, method))
# 关闭进程池,不在接受新的任务
pool.close()
# 等待所有子进程结束
pool.join()

def test_one(self, proxy, method):
url = 'https://www.baidu.com'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'
}
proxies = {
'http': 'http://' + proxy['proxy'],
'https': 'http://' + proxy['proxy']
}
try:
start_time = time.time()
resp = requests.get(url, headers=headers, proxies=proxies, timeout=5, verify=True)
# 记录ip代理请求用时
delay = round(time.time() - start_time, 2)
#
if resp.status_code == 200:
# 把delay加入到proxy字典中
proxy['delay'] = delay
if method == 'insert':
# 插入代理到数据库
MongoDB().insert(proxy)
elif method == 'check':
MongoDB().update({'proxy': proxy['proxy']}, {'delay': proxy['delay']})
else:
print("无效ip:{}".format(proxy))
if method == 'check':
MongoDB().delete({'proxy': proxy['proxy']})
except (ProxyError, ConnectionError):
print("无效ip:{}".format(proxy))
if method == 'check':
MongoDB().delete({'proxy': proxy['proxy']})
except Exception:
# traceback.print_exc()
pass

api.py 外部API接口

import flask
import json
from MongoDB.mongo_db import MongoDB
import random

app = flask.Flask(__name__)


# 从数据库中获取一个ip代理
@app.route('/one')
def get_one():
proxies = MongoDB().get(1)
# 所有代理数量减去一个,然后从result列表随机取出1个,MongoDB().get条件为None,取出的是所有的ip代理
result = [proxy['proxy'] for proxy in proxies]
x = random.randint(0, MongoDB().get_count() - 1)
# 返回json格式的类似字典的字符串
return json.dumps(dict(proxy=result[x]) )

# 从数据库中获取所有的ip代理
@app.route('/all')
def get_all():
# http://127.0.0.1:5000/many?count=2
# args = flask.request.args # 参数提交
proxies = MongoDB().get(1)
result = [proxy['proxy'] for proxy in proxies]
# x = random.randint(1,MongoDB().get_count()-1)

# 返回json格式的类似列表的字符串
return json.dumps(result)


@app.route('/delete')
def delete():
args = flask.request.args
MongoDB().delete({'proxy': args['proxy']})
return '删除成功:{}'.format(args)


def run():
app.run()

源代码地址,直接下载既可以使用,已包含依赖包

​https://github.com/FelixZFB/ProxiesPool​