代理池Demo版,可供学习,不能用于生产
PS:本人第一次发随笔,文笔不好,请多多包涵。项目代买 github:https://github.com/liangxu789/ProxyPoolDemo
什么是代理池呢?代理池就是一个装着很多代理的容器(好像说的是废话,哈哈哈)。总之就是一个容器,那好,我就在想用什么来当这个容器呢,思来想去,我觉的用Redis,为什么要用Redis呢?大家可以百度一下。因为工作用的语言是java,c#。所以我觉得我这个代理池就用python来写吧(因为想练习练习,语法有点快忘记了)。
前后用了一天,写出了个小小的demo。
下面这个是文件目录:

我就不全部介绍了,主要就介绍两个模块:获取代理 和 检查代理(其实也就这两个模块)
1 获取代理模块
一共找到了4个网站,他们是有免费代理的。
分别是:http://www.66ip.cn/ http://www.xsdaili.com/dayProxy/ip/ https://www.xicidaili.com http://www.nimadaili.com
有了免费代理的网站。就需要将把这些网站上的代理给弄下来。怎么弄呢?就需要爬虫了。我用的是requets + pyquery
具体的代码在下面(就展示第一个吧):
from pyquery import PyQuery as pq import time, json, requests, multiprocessing import log.logModel as lm import redisitem.RedisOperation as ro import tools.randomCode as rc import tools.GetProxyIP as gip # 代理网页主页地址 Proxy_url = "http://www.66ip.cn/" # 浏览器信息 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/77.0.3865.90 Safari/537.36 ' } #获取网页内容 def get_page_content(url, proxy): try: if proxy: r = requests.get(url, headers=headers, timeout=10, proxies=proxy) else: r = requests.get(url, headers=headers, timeout=10) if r.status_code == 200: lm.log_info("获取" + url + "的页面数据成功") return r.text else: lm.log_warning("获取" + url + "的页面数据失败 正在换代理获取重新获取。。。") proxy_list = { "http": gip.GetProxyIP(), } get_page_content(url, proxy_list) except: lm.log_error(url + "链接错误 取消此次链接") get_page_content(url, None) #获取页码信息 def parse_page_num(url): doc = pq(get_page_content(url, None)) return int(int(doc(".style7 span").text()) / 7) #循环获取页面信息 def get_html(interval): page_num = parse_page_num(Proxy_url) for i in range(page_num): try: new_url = Proxy_url + str(i + 1) + ".html" lm.log_info("正在获取" + new_url + "的信息") html = get_page_content(new_url, None) parse_html(html) time.sleep(interval) except Exception as e: lm.log_error(e.args[0]) continue #获取代理,将其存到Redis中 def parse_html(html): doc = pq(html.encode('iso-8859-1').decode('gbk')) for i in doc("#main table tr"): i_html = pq(i) result_dic = {"ip": i_html("td").eq(0).text(), "port": i_html("td").eq(1).text()} if result_dic["ip"] != "ip": result = json.dumps(result_dic) ro.setDic(rc.getRandomCode(), result) lm.log_info(str(result_dic) + "已经存到Redis中") def start_up(): p = multiprocessing.Process(target=get_html, args=(3,)) p.start()
上面就是代码,其实很简单,一下子就能看懂了,主要的逻辑就是:先获取页码(parse_page_num) ----> 然后通过页码循环获取每页的信息 ----> 通过pyquery获取代理信息 ----> 将其存到Redis中。
其中需要注意的一点是,有些代理网站会监测是否是爬虫,会封ip。所以我在获取页面内容的哪里加上了使用代理,如果他封了ip,我就使用代理获取,继续封,我就换代理.....
获取代理就很容易,之前不是在Redis存了代理,随机取出一个,就先用,发现不能用,就再随机换一个代理。如此循环往复。
获取代理的代码如下:
import json import random import redisitem.RedisOperation as ro def GetProxyIP(): # 获取Redis对象 r = ro.getRedisObj() # 随机取出一个代理 i = random.sample(ro.getDicKeys(), 1)[0] # 将json字符串转为字典 ip_info = json.loads(r.hget("proxy_ip", i)) # 返回代理 return "http://" + ip_info["ip"] + ":" + ip_info["post"]
2 代理检查模块
代理检查其实就两步,一个是获取代理,一个是检查代理。
下面是代码:
import win32api, win32con, telnetlib, random, json from concurrent.futures.thread import ThreadPoolExecutor import redisitem.RedisOperation as ro import log.logModel as lm # 浏览器信息 head_data = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/77.0.3865.90 Safari/537.36 ', } # 获取代理ip def GetProxyIP(): # 获取redis对象 r = ro.getRedisObj() # 随机获取一条数据 i = random.sample(ro.getDicKeys(), 1)[0] if i: # 得到数据的value值,为字典类型的json字符串,将其转为字典类型 ip_info = json.loads(r.hget("proxy_ip", i)) try: # 测试代理是否可用 telnetlib.Telnet(ip_info["ip"], ip_info["post"], timeout=2) # 记录日志 lm.log_info(ip_info["ip"] + ":" + ip_info["post"] + "监测为可用代理") # 将可用代理写入桌面txt文件 with open(get_desktop() + "/可用代理.txt", 'a', encoding='utf-8') as f: f.write(ip_info["ip"] + " " + ip_info["post"] + "\r\n") except Exception as e: # 代理不可用,在redis中将其删除 r.delete(i) lm.log_info(ip_info["ip"] + ":" + ip_info["post"] + "监测为不可用代理,已删除") # 获取桌面路径 def get_desktop(): # 获取注册表值 key = win32api.RegOpenKey(win32con.HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders', 0, win32con.KEY_READ) # 返回桌面路径 return win32api.RegQueryValueEx(key, 'Desktop')[0] # 开始函数 def startup(): while True: # 开启线程池 pool = ThreadPoolExecutor(max_workers=20) for i in range(20): # 多线程运行检查函数 pool.submit(GetProxyIP) # 回收线程池 pool.shutdown()
具体流程就是:先随机获取一个代理 ----> 然后检查代理是否可用,如果可用就存到一个桌面名叫“可用代理”的txt文件里面,如果不可用,就从redis中删除此代理。开启线程池进行获取。
这样一个代理池的小小demo就完成了,虽然功能和逻辑还需要斟酌和完善(等以后闲下来的时候好好改改)。
其他模块代码如下:
日志模块
import logging # 创建一个logging对象 logger = logging.getLogger() # 创建一个屏幕对象 sh = logging.StreamHandler() # 配置显示格式 可以设置两个配置格式 分别绑定到文件和屏幕上 formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s') sh.setFormatter(formatter) logger.addHandler(sh) logger.setLevel(10) # 总开关 # requests模块在运行过程中无法记录日志 logging.getLogger().setLevel(logging.INFO) logging.getLogger("requests").setLevel(logging.WARNING) # debug日志 def log_debug(message): logging.debug(message) # info日志 def log_info(message): logging.info(message) #warning日志 def log_warning(message): logging.warning(message) #error日志 def log_error(message): logging.error(message)
Redis操作
import redis import redis_config as rc pool = redis.ConnectionPool(host=rc.HOST, port=rc.POST) r = redis.Redis(connection_pool=pool) def setDic(key, value): r.hset("proxy_ip", key, value) def getRedisObj(): return r def getDicKeys(): return r.hkeys("proxy_ip")
希望大家能给我这个博客小白一点意见,我会继续努力的!加油!!

浙公网安备 33010602011771号