爬虫入门第7课:实现代理池的数据库模块

Posted 黑马程序员官方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了爬虫入门第7课:实现代理池的数据库模块相关的知识,希望对你有一定的参考价值。

爬虫学习知识点及案例篇(汇总):

爬虫入门第1课:代理池概述及开发环境

爬虫入门第2课:代理池的设计

爬虫入门第3课:实现代理池思路

爬虫入门第4课:定义代理IP的数据模型类

爬虫入门第5课:实现代理池工具模块

爬虫入门第6课:实现代理池的校验模块

本阶段带大家从代理池的设计开始,学习Python爬虫及项目实战,详情关注上方专栏 ↑↑↑


  • 作用: 用于对proxies集合进行数据库的相关操作
  • 目标: 实现对数据库增删改查相关操作
  • 步骤:
    1. init中, 建立数据连接, 获取要操作的集合, 在 del 方法中关闭数据库连接
    2. 提供基础的增删改查功能
      1. 实现插入功能
      2. 实现修改该功能
      3. 实现删除代理: 根据代理的IP删除代理
      4. 查询所有代理IP的功能
    3. 提供代理API模块使用的功能
      1. 实现查询功能: 根据条件进行查询, 可以指定查询数量, 先分数降序, 速度升序排, 保证优质的代理IP在上面.
      2. 实现根据协议类型 和 要访问网站的域名, 获取代理IP列表
      3. 实现根据协议类型 和 要访问网站的域名, 随机获取一个代理IP
      4. 实现把指定域名添加到指定IP的disable_domain列表中.

完整代码

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 __del__(self):
        # 关闭数据库连接
        self.client.close()

   def insert(self, proxy=None):
        """保存代理IP到数据库中"""
        if proxy:
            # 查询代理ip数量,
            count = self.proxies.count_documents('_id': proxy.ip)
            # 如果值不为0, 说明该代理IP, 已经存在了, 直接返回
            if count != 0:
                # 表示代理IP已经存在, 直接返回
                return

            # 把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 find_all(self):
        # 获取查询所有代理IP的cursor对象
        cursor = self.proxies.find()
        # 变量游标, 获取代理IP
        for item in cursor:
            # 删除_id键
            item.pop('_id')
            # 创建Proxy对象
            proxy = Proxy(**item)
            # 返回代理IP
            yield proxy

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

      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对象
             # 删除_id键
            item.pop('_id')
            # 创建Proxy对象
            proxy = Proxy(**item)
            # 把Proxy对象添加到结果集
            results.append(proxy)
        # 返回查询的结果
        return results

    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)

    def disable_domain(self, ip, domain):
        # 如果该IP下没有这个域名才更新
        if self.proxies.count_documents('_id':ip,'disable_domains':domain) == 0:
            # 向指定IP的不可用域名中添加域名
            self.proxies.update_one('_id': ip, '$push': 'disable_domains': domain)

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.insert(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. init中, 建立数据连接, 获取要操作的集合, 在 del 方法中关闭数据库连接
    2. 提供基础的增删改查功能
    3. 提供代理API模块使用的功能

以上是关于爬虫入门第7课:实现代理池的数据库模块的主要内容,如果未能解决你的问题,请参考以下文章

爬虫入门第9课:实现代理池的检测模块

爬虫入门第10课:实现代理池的API模块

爬虫入门第11课:实现代理池的启动入口

爬虫入门第6课:实现代理池的校验模块

爬虫入门第2课:代理池的设计

爬虫入门第3课:实现代理池思路