多爬虫实现之三 -- 多爬虫文件

目标

  • 优化现有的爬虫结构,实现同时开始执行多个爬虫

1 为什么需要优化现有的爬虫结构

当爬虫比较少的时候,我们的项目结构相对合理,但是当要抓取的网站比较多的时候,可以借鉴scrapy的方法,把不同网站的爬虫分别在不同的py文件中编写,之后放在一个目录下;同时,我们很多时候还希望能够有同时启动项目中的所有的爬虫

2 将多个爬虫类分离为多个爬虫文件爬虫文件

为了解耦合,应将每个站点的爬虫写为单独一个py文件,因此更改一下放置爬虫的模块,结构如下:

- 项目文件夹
  -- main.py
  -- spiders
     -- __init__.py
     -- baidu.py
     -- douban.py
  -- settings.py

其中baidu.pydouban.py分别是抓取百度和豆瓣的爬虫文件

  • baidu.py:
# project_dir/spiders/baidu.py
from scrapy_plus.core.spider import Spider

# 继承框架的爬虫基类
class BaiduSpider(Spider):

    start_urls = ['http://www.baidu.com']    # 设置初始请求url
  • douban.py: 抓取豆瓣电影top250的列表页信息
# project_dir/spiders/douban.py
from scrapy_plus.core.spider import Spider
from scrapy_plus.http.request import Request
from scrapy_plus.item import Item


class DoubanSpider(Spider):

    start_urls = []  # 重写start_requests方法后,这个属性就没有设置的必要了

    def start_requests(self):
        # 重写start_requests方法,返回多个请求
        base_url = 'http://movie.douban.com/top250?start='
        for i in range(0, 250, 25):    # 逐个返回第1-10页的请求属相
            url = base_url + str(i)
            yield Request(url)

    def parse(self, response):
        '''解析豆瓣电影top250列表页'''
        title_list = []    # 存储所有的
        for li in response.xpath("//ol[@class='grid_view']/li"):    # 遍历每一个li标签
            # title = li.xpath(".//span[@class='title'][1]/text()")    # 提取该li标下的 标题
            # title_list.append(title[0])
            detail_url = li.xpath(".//div[@class='info']/div[@class='hd']/a/@href")[0]
            yield Request(detail_url, parse="parse_detail")    # 发起详情页的请求,并指定解析函数是parse_detail方法
        # yield Item(title_list)    # 返回标题

    def parse_detail(self, response):
        '''解析详情页'''
        print('详情页url:', response.url)    # 打印一下响应的url
        return []    # 由于必须返回一个容器,这里返回一个空列表
  • 对main.py进行相应修改,测试新增的douban爬虫

      from scrapy_plus.core.engine import Engine    # 导入引擎
    
      from spiders.baidu import BaiduSpider
      from spiders.douban import DoubanSpider
    
      if __name__ == '__main__':
          # spider = BaiduSpider()    # 实例化爬虫对象
          douban_spider = DoubanSpider()    # 实例化爬虫对象
          engine = Engine(douban_spider)    # 传入爬虫对象
          engine.start()    # 启动引擎
    

3 同时执行多个不同的爬虫

如把豆瓣爬虫和百度爬虫一起启动并执行

传入形式:并用字典的形式传入多个爬虫:

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

from spiders.baidu import BaiduSpider
from spiders.douban import DoubanSpider

if __name__ == '__main__':
    baidu_spider = BaiduSpider()    # 实例化爬虫对象
    douban_spider = DoubanSpider()    # 实例化爬虫对象
    spiders = {'baidu':baidu_spider, 'douban':douban_spider}
    engine = Engine(spiders)    # 传入爬虫对象
    engine.start()    # 启动引擎

在引擎中用到爬虫对象的地方都要做相应的修改

  • engine.py
'''引擎
a. 对外提供整个的程序的入口
b. 依次调用其他组件对外提供的接口,实现整个框架的运作(驱动)
'''
......
class Engine(object):

    def __init__(self, spiders):    # 接收外部传入的多个爬虫对象
        self.spiders = spiders    # 爬虫对象

        ......

    ......

    def _start_requests(self):
        '''向调度器添加初始请求'''
        # 1. 爬虫模块发出初始请求
        for spider_name, spider in self.spiders.items():
            for start_request in spider.start_requests():
                # 2. 把初始请求添加给调度器
                # 利用爬虫中间件预处理请求对象
                start_request = self.spider_mid.process_request(start_request)
                start_request.spider_name = spider_name    #为请求对象绑定它所属的爬虫的名称
                self.scheduler.add_request(start_request)

    def _execute_request_response_item(self):
        '''根据请求、发起请求获取响应、解析响应、处理响应结果'''

        ......

        spider = self.spiders[request.spider_name]  # 根据请求的spider_name属性,获取对应的爬虫对象

        # 5. 利用爬虫的解析响应的方法,处理响应,得到结果
        parse = getattr(spider, request.parse)    # 获取对应的解析函数
        results = parse(response)    # parse函数的返回值是一个容器,如列表或者生成器对象
        for result in results:
           # 6. 判断结果对象
           # 6.1 如果是请求对象,那么就再交给调度器
           if isinstance(result, Request):
               # 利用爬虫中间件预处理请求对象
               result = self.spider_mid.process_request(result)
               result.spider_name = request.spider_name  # 为请求对象绑定它所属的爬虫的名称
               self.scheduler.add_request(result)
           # 6.2 否则,就交给管道处理
           ......
    ......

安装代码,并运行main.py,直到调试成功

4 再次改进,将每个爬虫的名称直接设置为爬虫类的一个属性

参考:

class BaiduSpider(Spider):
    name = 'baidu'    # 为爬虫命名
    start_urls = ['http://www.baidu.com']    # 设置初始请求url

'''那么main.py就可以按照这样的方式设定key值'''
spiders = {BaiduSpider.name: baidu_spider, DoubanSpider.name: douban_spider}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值