当前位置:   article > 正文

爬虫代理池项目

爬虫代理池

本文章案例仅供参考


前言

提示:这里可以添加本文要记录的大概内容:


一、代理池概述

1.什么是代理池?

代理池就是有代理IP组成的池子, 它可以提供多个稳定可用的代理IP

2.为什么要实现代理池?

  1. 我们在做爬虫的时候, 最常见一种反爬手段就是 ip反爬; 也就是当同一个IP访问这个网站次数过多, 频率过高,就会限制这个IP访问. 怎么解决这个问题呢? 就是需要经常换IP; 使用代理IP是其中一个比较常用的方案。
  2. 免费代理都是非常不稳定的, 有10%是可用就很不错了。
  3. 一些收费代理稳定性也不好, 便宜一点只有30%~50%左右是可用。 注: 如果代理IP提供商, 提供接口很好, 稳定性也很高, 就无需使用代理池

3.代理池开发环境

平台: Mac,可以运行Window和Linux上
开发语言: Python3
开发工具: PyCharm
使用到的主要技术:
requests: 发送请求, 获取页面数据
lxml: 使用XPATH从页面提取我们想要的数据
pymongo: 把提取到代理IP存储到MongoDB数据库中和从MongoDB数据库中读取代理IP,给爬虫使用.
Flask: 用于提供WEB服务

二、代理池设计

在这里插入图片描述

1.代理池五大核心模块

1.1 数据库模块

实现对代理ip的增删改查操作,这里使用MongoDB来存储代理IP

1.2 代理IP的检测模块

  • 测试代理速度, 支持的协议以及匿名程度 ,原因: 网站上所标注的协议类型和匿名类型是不准确的
  • 这里使用httpbin.org进行检测

1.3 爬虫模块

  • 从代理ip网站上采集代理ip
  • 进行校验(获取代理响应速度,协议类型,匿名类型)
  • 把可用代理ip存储到数据库中

1.4 检验模块

  • 从数据库读取所有的代理ip
  • 对代理ip进行逐一检测,可用开启多个协程
  • 以提高检测速度 依据检测结果对代理ip进行更新

2.代理池的其他模块

程序启动入口: `main.py`  代理池提供一个统一的启动入口
数据模型: `domain.py`:   代理IP的数据模型 
工具模块: 
		1.日志模块: 用于记录日志信息
		2.http模块: 用于获取随机User-Agent的请求头
配置文件: `settings.py`  用于配置日志, 启动的爬虫, 启用的代理IP检验类等
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3.代理池的项目结构

-- IPProxyPool
    -- db
      -- __init__.py
      -- mongo_pool.py
    -- proxy_validate
        -- __init__.py
        -- httpbin_validator.py
    -- proxy_spider
        -- __init__.py
        -- base_spider.py
        -- proxy_spiders.py
        -- run_spiders.py
    -- utils
        -- __init__.py
        -- http.py
        -- log.py
    -- proxy_test.py
    -- proxy_api.py
    -- main.py
    -- domain.py
    -- settings.py
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

4.定义代理池ip的数据模型类

用于封装代理信息
步骤:

- 定义一个类, 继承object
- 实现__init__方法, 负责初始化, 包含如下字段:
  - ip: 代理的IP地址
  - port: 代理IP的端口号
  - protocol: 代理IP支持的协议类型,http是0, https是1, https和http都支持是2
  - nick_type: 代理IP的匿名程度, 高匿:0, 匿名: 1, 透明:0
  - speed: 代理IP的响应速度, 单位s
  - area: 代理IP所在地区
  - score: 代理IP的评分, 默认分值可以通过配置文件进行配置. 在进行代理可用性检查的时候, 每遇到一次请求失败就减1份, 减到0的时候从池中删除. 如果检查代理可用, 就恢复默认分值
  - disable_domains: 不可用域名列表, 有些代理IP在某些域名下不可用, 但是在其他域名下可用
- 创建配置文件: settings.py; 定义MAX_SCORE = 50, 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

代码实现:

# 代理模型类, 用于封装代理相关信息
class Proxy(object):
    def __init__(self, ip, port, protocol=-1, nick_type=-1,speed=-1, area=None, score=50, disable_domains=[]):
        self.ip=ip  #ip
        self.port=port  #端口号
        self.protocol=protocol #代理IP支持协议类型,HTTP是0,HTTP是1,https和http是支持2
        self.nick_type=nick_type #匿名程度:高匿0 匿名1  透明0
        self.area=area #所在地区
        self.speed=speed #速度  单位s
        self.score=score #代理ip评分  在进行代理可用性检查的时候, 每遇到一次请求失败就减1份, 减到0的时候从池中删除. 如果检查代理可用, 就恢复默认分值
        self.disable_domains=disable_domains

    def __str__(self):
        #返回数字字符串
        return  str(self.__dict__)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

5.代理池工具模块

5.1 日志模块

为什么要实现日志模块?
  • 能够方便对程序进行调试
  • 能够记录程序的运行状态
  • 记录错误信息
日志的实现?
步骤:
- 拷贝笔记日志代码到项目中
- 把日志相关配置信息 放到配置文件中
- 修改日志代码, 使用配置文件中的配置信息
  • 1
  • 2
  • 3
  • 4

代码:

import sys
import logging

# 默认的配置
LOG_LEVEL = logging.INFO    # 默认等级
LOG_FMT = '%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s: %(message)s'   # 默认日志格式
LOG_DATEFMT = '%Y-%m-%d %H:%M:%S'  # 默认时间格式
LOG_FILENAME = 'log.log'    # 默认日志文件名称

class Logger(object):
    def __init__(self):
        #1.获取一个logger对象
        self._logger=logging.getLogger()
        #2.设置formater对象
        self.formatter=logging.Formatter(fmt=LOG_FMT,datefmt=LOG_DATEFMT)
        #3.设置日志输出
        #3.1 设置文件日志模式

        self._logger.addHandler(self._get_file_handler(LOG_FILENAME))
        #3.2 设置终端日志模式
        self._logger.addHandler(self._get_console_handler())
        #4.设置日志等级
        self._logger.setLevel(LOG_LEVEL)

    def _get_file_handler(self,filename):
        '''返回一个文件日志handler'''
        # 1. 获取一个文件日志handler
        filehandler=logging.FileHandler(filename=filename,encoding="utf-8")
        #2.设置日志格式
        filehandler.setFormatter(self.formatter)
        #3.返回
        return filehandler

    def _get_console_handler(self):
        '''返回一个输出到终端日志handler'''
        # 1. 获取一个输出到终端日志handler
        console_handler=logging.StreamHandler(sys.stdout)
        #2.设置日志格式
        console_handler.setFormatter(self.formatter)
        #3.返回handler
        return  console_handler

    @property
    def  logger(self):
        return self._logger
# 初始化并配一个logger对象,达到单例的
# 使用时,直接导入logger就可以使用

logger=Logger().logger

if __name__ == '__main__':
    logger.debug("调试信息")
    logger.info("状态信息")
    logger.warning("警告信息")
    logger.error("错误信息")

2022-12-17 19:52:41 日志.py [line:53] INFO: 状态信息
2022-12-17 19:52:41 日志.py [line:54] WARNING: 警告信息
2022-12-17 19:52:41 日志.py [line:55] ERROR: 错误信息
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

5.2 Http模块

我在从代理IP网站上抓取代理IP检验代理IP时候, 为了不容易不服务器识别为是一个爬虫, 我们最好提供随机的User-Agent请求头.

获取随机User-Agent的请求头
步骤:
- 1. 准备User-Agent的列表
  2. 实现一个方法, 获取随机User-Agent的请求头
  • 1
  • 2
  • 3
  • 4

代码:

import random

user_agent=[
    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)",
    "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
    "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)",
    "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
    "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
    "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
    "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
    "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
    "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
    "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
    "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5",
    "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.20 (KHTML, like Gecko) Chrome/19.0.1036.7 Safari/535.20",
    "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.11 TaoBrowser/2.0 Safari/536.11",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.71 Safari/537.1 LBBROWSER",
    "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; LBBROWSER)",
    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E; LBBROWSER)",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.84 Safari/535.11 LBBROWSER",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)",
    "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; QQBrowser/7.0.3698.400)",
    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SV1; QQDownload 732; .NET4.0C; .NET4.0E; 360SE)",
    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; QQDownload 732; .NET4.0C; .NET4.0E)",
    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)",
    "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1",
    "Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; zh-cn) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5",
    "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:2.0b13pre) Gecko/20110307 Firefox/4.0b13pre",
    "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:16.0) Gecko/20100101 Firefox/16.0",
    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11",
    "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10"
]

def get_request_header():
    return {
        "User-Agent":random.choice(user_agent),
        "Connection":"keep-alive",
        "Cache-Control":"max-age=0",
        "Upgrade-Insecure-Requests":"1",
        "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "Accept-Encoding":"gzip,deflate",
        "Accept-Language":'zh-CN,zh;q=0.9,en;q=0.8,en-US;q=0.7',
    }

if __name__ == '__main__':
    print(get_request_header())
    print(get_request_header())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

6.代理IP的校验模块

检查代理IP的速度,支持协议类型,以及匿名程度

匿名程度检查: 

- 对 `http://httpbin.org/get``https://httpbin.org/get` 发送请求
- 如果 `origin` 中有','分割的两个IP就是透明代理IP
- 如果 `headers` 中包含 `Proxy-Connection` 说明是匿名代理IP 
- 否则就是高匿代理IP

检查代理IP协议类型
如果 `http://httpbin.org/get` 发送请求可以成功, 说明支持http协议
如果 `https://httpbin.org/get` 发送请求可以成功, 说明支持https协议 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
import requests
import time
import json
from utils import http
import settings
from domain import Proxy
from utils.log import logger

def check_proxy(proxy):
    '''
    检测代理协议类型, 匿名程度
    :param
    :return:(协议: http和https:2,https:1,http:0, 匿名程度:高匿:0,匿名: 1, 透明:0 , 速度, 单位s )
    '''

    # 根据proxy对象构造, 请求使用的代理
    proxies = {
        'http': "http://{}:{}".format(proxy.ip, proxy.port),
        'https':"https://{}:{}".format(proxy.ip, proxy.port),
    }

    http, nick_type, http_speed = _check_http_proxy(proxies)
    https, nick_type, https_speed = _check_http_proxy(proxies, False)
    if http and https:
        # 如果http 和 https 都可以请求成功, 说明支持http也支持https, 协议类型为2
        proxy.protocol = 2
        proxy.nick_type = nick_type
        proxy.speed = http_speed
    elif http:
        # 如果只有http可以请求成功, 说明支持http协议, 协议类型为 0
        proxy.protocol = 0
        proxy.nick_type = nick_type
        proxy.speed = http_speed
    elif https:
        # # 如果只有https可以请求成功, 说明支持https协议, 协议类型为 1
        proxy.protocol = 1
        proxy.nick_type = nick_type
        proxy.speed = https_speed
    else:
        proxy.protocol = -1
        proxy.nick_type = -1
        proxy.speed = -1

    logger.debug(proxy)
    return proxy


def _check_http_proxy(proxies, isHttp=True):
    nick_type = -1 # 匿名程度
    speed = -1 # 响应速度
    if isHttp:
        test_url = 'http://httpbin.org/get'
    else:
        test_url = 'https://httpbin.org/get'
    try:
        start = time.time()
        r = requests.get(url=test_url, headers=http.get_request_header(), timeout=settings.TIMEOUT, proxies=proxies)
        if r.ok:
            # 计算响应速度, 保留两位小数
            speed = round(time.time() - start, 2)
            # 把响应内容转换为字典
            content = json.loads(r.text)
            # 获取请求头
            headers = content['headers']
            # 获取origin, 请求来源的IP地址
            ip = content['origin']
            # 获取请求头中 `Proxy-Connection` 如果有, 说明匿名代理
            proxy_connection = headers.get('Proxy-Connection', None)

            if ',' in ip:
                # 如果 `origin` 中有','分割的两个IP就是透明代理IP
                nick_type = 2 # 透明
            elif proxy_connection:
                # 如果 `headers` 中包含 `Proxy-Connection` 说明是匿名代理IP
                nick_type = 1 # 匿名
            else:
                #  否则就是高匿代理IP
                nick_type = 0 # 高匿
            return True, nick_type, speed
        else:
            return False, nick_type, speed
    except Exception as e:
        logger.exception(e)
        return False, nick_type, speed

if __name__ == '__main__':
    proxy = Proxy('118.190.95.35', '9001')
    # proxy = Proxy('150.107.143.33', '9797')
    rs = check_proxy(proxy)
    print(proxy.protocol)
    print(rs)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91

7.代理池数据库模块

用于对proxies集合进行数据库的相关操作,实现对数据库增删改查相关操作

步骤:
- 1. 定义MongoPool类, 继承object
  2. 实现初始化方法, 建立数据连接, 获取要操作的集合
  3. 实现插入功能
  4. 实现修改该功能
  5. 实现保存功能, 如果不存在插入, 如果存在了就更新
  6. 实现查询功能: 根据条件进行查询, 可以指定查询数量, 先分数降序, 速度升序排, 保证优质的代理IP在上面. 
  7. 实现删除代理: 根据代理的IP删除代理
  8. 实现根据协议类型 和 要访问网站的域名, 获取代理IP列表
  9. 实现根据协议类型 和 要访问完整的域名, 随机获取一个代理IP
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
import pymongo
import random

from settings import MONGO_URL, DEFAULT_SCORE
from domain import Proxy
from utils.log import logger

class MongoPool(object):
    def __init__(self):
        """初始化"""
        self.client = pymongo.MongoClient(MONGO_URL)
        # 获取要操作的集合
        self.proxies = self.client['proxy_pool']['proxies']

    def insert(self, proxy=None):
        """保存代理IP到数据库中"""
        if proxy:
            # 把Proxy对象转换为转换为字典
            dic = proxy.__dict__
            # 设置_id字段, 为代理IP的IP地址
            dic['_id'] =  proxy.ip
            # 向集合中插入代理IP
            self.proxies.insert_one(dic)
            # 记录日志
            logger.info("插入新代理IP:{}".format(dic))
        else:
            logger.error("没有传入要插入的proxy")


    def update(self, proxy=None):
        """更新代理"""
        if proxy:
            self.proxies.update_one({'_id':proxy.ip}, {"$set": proxy.__dict__})
            logger.info("更新代理: {}".format(proxy))
        else:
            logger.error("请求传入要更新的代理")

    def save(self, proxy):
        """ 保存代理信息: 如果代理IP不存在就插入, 存在就更新"""
        # 1. 根据IP查询代理IP数量, 如果数量为0 , 说明该代理IP是新的, 否则该代理IP已经存在
        count = self.proxies.count_documents({'_id': proxy.ip})
        # 如果如果代理IP不存在就插入, 否则, 更新原来的代理IP信息
        if count == 0:
            self.insert(proxy)
        else:
            self.update(proxy)

    def find(self, conditions=None, count=0):
        """
        根据条件查询代理IP
        :param conditions: # 字典形式的查询条件
        :param count: 查询多少条数据
        :return: 返回先按分数降序, 后按响应速度升序排列前count条数据, 如果count==0, 就查询所有的,
        """
        # 如果没有conditions, 将conditions设置为{}
        if conditions is None:
            conditions = {}

        # 获取查询的游标地下
        cursor = self.proxies.find(conditions, limit=count).sort(
             [("score", pymongo.DESCENDING), ("speed", pymongo.ASCENDING)])
        # 创建一个list, 用于存储Proxy
        results = []
        # 变量游标, 获取代理IP
        for item in cursor:
            # 创建Proxy对象
            proxy = Proxy(item['ip'], item['port'],
                           score=item['score'], protocol=item['protocol'],
                           nick_type=item['nick_type'], speed=item['speed'],
                           disable_domains=item['disable_domains'])
            # 把Proxy对象添加到结果集
            results.append(proxy)
        # 返回查询的结果
        return results

    def delete(self, proxy=None):
        """根据条件删除代理IP"""
        if proxy:
            self.proxies.delete_one({'_id': proxy.ip})
            logger.info('删除代理: {}'.format(proxy))
        else:
            logger.error("请传入要删除的代理")

    
    def get_proxies(self, protocol=None, domain=None, count=0, nick_type=0):
        """
        根据协议类型, 获取代理IP, 默认查询都是高匿的
        :param protocol: 协议: http 或 https
        :param domain: 要访问网站的域名
        :param count: 代理IP的数量, 默认全部
        :param nick_type: 匿名程度, 默认为高匿

        :return:
        """

        conditions = {'nick_type': nick_type}
        if domain:
            # 如果有域名, 就获取不可用域名中, 没有该域名的代理
            conditions['disable_domains'] = {'$nin':[domain]}

        if protocol is None:
            # 如果没有协议, 就获取及支持http 又支持https的协议
            conditions['protocol'] = 2
        elif protocol.lower() == 'http':
            # 如果是HTTP的请求, 使用支持http 和 支持http/https均可以
            conditions['protocol'] = {'$in': [2, 0]}
        elif protocol.lower() == 'https':
            # 如果是HTTP的请求, 使用支持https 和 支持http/https均可以
            conditions["protocol"] = {'$in': [2, 1]}

        return self.find(conditions, count=count)

    def random(self, protocol=None, domain=None, count=0):
        """
        从指定数量代理IP中, 随机获取一个
        :param protocol: 协议: http 或 https
        :param domain: 要访问网站的域名
        :param count: 代理IP的数量
        :return: 一个随机获取代理IP
        """
        proxy_list = self.get_proxies(protocol, domain=domain, count=count)
        return random.choice(proxy_list)

# 创建MongoPool的单例对象
mongo = MongoPool()

if __name__ == '__main__':
    # 1. 保存代理IP
    # proxy = Proxy('124.89.97.43', '80', protocol=1, nick_type=0, speed=0.36, area='陕西省商洛市商州区')
    # proxy = Proxy('124.89.97.43', '80', protocol=2, nick_type=0, speed=0.36, area='陕西省商洛市商州区')
    # proxy = Proxy('124.89.97.44', '80', protocol=1, nick_type=0, speed=0.36, area='陕西省商洛市商州区')
    # proxy = Proxy('124.89.97.45', '80', protocol=0, nick_type=0, speed=0.36, area='陕西省商洛市商州区')
    # proxy = Proxy('124.89.97.46', '80', protocol=0, nick_type=2, speed=0.36, area='陕西省商洛市商州区')
    # mongo.save(proxy)

    # 3. 测试减少代理分值
    # mongo.decrease_score(proxy)
    # 4. 恢复
    # proxy = Proxy('124.89.97.43', '80', protocol=2, nick_type=0, speed=0.36, area='陕西省商洛市商州区', score=1)
    # mongo.resume_score(proxy)
    # 5. 获取大理IP列表
    # proxies = mongo.get_proxies('http')
    # proxies = mongo.get_proxies('https')
    # 随机获取一个代理IP
    # proxy = mongo.random('http')
    # proxy = mongo.random('https')
    # print(proxy)
    # 删除代理IP
    proxy = Proxy('124.89.97.46', '80', protocol=0, nick_type=2, speed=0.36, area='陕西省商洛市商州区')
    mongo.delete(proxy)

    # 2. 查询高匿代理IP
    proxies = mongo.find({'nick_type': 0})
    for proxy in proxies:
        print(proxy)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号