# 3.8. 框架完善--实现动态模块导入

# 目标

  • 掌握模块的动态导入的方法
  • 完成对现有代码的重构

# 1. 目前代码存在的问题

通过前面的代码编写,我们已经能够完成大部分的任务,但是在main.py 中的代码非常臃肿,对应的我们可以再settings.py 配置哪些爬虫,管道,中间件需要开启,能够让整个代码的逻辑更加清晰

# 2. 模块动态导入的方法

  • 利用importlib.import_modle能够传入模块的路径,即可即可实现根据模块的位置的字符串,导入该模块的功能

  • 在项目路径下新建test.py观察现象,插入如下代码观察现象

# 3. 在settings中设置SPIDER,MIDDLEWARES

  • 利用在配置文件中设置需要启用的爬虫类、管道类、中间件类,如下:

          # 项目中的settings.py
    
          ......
    
          # 增加以下信息:
          # 启用的爬虫类
          SPIDERS = [
              'spiders.baidu.BaiduSpider',
              'spiders.douban.DoubanSpider'
          ]
    
          # 启用的管道类
          PIPELINES = [
              'pipelines.BaiduPipeline',
              'pipelines.DoubanPipeline'
          ]
    
          # 启用的爬虫中间件类
          SPIDER_MIDDLEWARES = []
    
          # 启用的下载器中间件类
          DOWNLOADER_MIDDLEWARES = []
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
  • 利用importlib模块,在引擎中动态导入并实例化

      ....
      from scrapy_plus.conf.settings import SPIDERS, PIPELINES, \
          SPIDER_MIDDLEWARES,DOWNLOADER_MIDDLEWARES
    
      class Engine:
          '''完成对引擎模块的封装'''
    
          def __init__(self):
              '''
              实例化其他的组件,在引起中能够通过调用组件的方法实现功能
              '''
              self.spiders = self._auto_import_instances(SPIDERS,isspider=True)
              self.downloader = Downloader()
              self.scheduler = Scheduler()
    
              self.pipelines = self._auto_import_instances(PIPELINES)
              self.spider_mids = self._auto_import_instances(SPIDER_MIDDLEWARES)
              self.downloader_mids =self._auto_import_instances(DOWNLOADER_MIDDLEWARES)
              self.total_request_nums = 0
              self.total_response_nums = 0
    
          def _auto_import_instances(self,path=[],isspider=False):
              '''通过配置文件,动态导入类并实例化
              path: 表示配置文件中配置的导入类的路径
              isspider: 由于爬虫需要返回的是一个字典,因此对其做对应的判断和处理
              '''
              # 该方法不仅实例化动态导入爬虫,还有管道和中间件,而前者返回应是字典类型
              if isspider is True:
                  instances = {}
              else:
                  instances = []    # 存储对应类的实例对象
    
              for p in path:
                  module_name = p.rsplit(".",1)[0]    # 取出模块名称
                  cls_name = p.rsplit(".",1)[1]    # 取出类名称
                  ret = importlib.import_module(module_name)    # 动态导入爬虫模块
                  cls = getattr(ret, cls_name)    # 根据类名称获取类对象
                  if isspider is True:
                      instances[cls.name] = cls()
                  else:
                      instances.append(cls())    # 实例化类对象
              return instances    # 返回类对象
      ......
    
    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

# 4. 修改main.py

这样main.py就不用再导入并传入那么多对象了:

# project_dir/main.py
from scrapy_plus.core.engine import Engine    # 导入引擎

if __name__ == '__main__':
    engine = Engine()  # 创建引擎对象
    engine.start()    # 启动引擎
1
2
3
4
5
6

# 小结

  • 本小结重点
    • 掌握importlib.import_module方法使用
    • 完成代码的重构,实现通过配置文件导入模块
上次更新: 2020/10/21 下午5:54:02