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代理
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