爬虫工作量由小到大的思维转变---<第七章 Scrapy超越控制台===代码运行scrapy+多线程爬取+数据交互>

前言:

 针对留言的问题:
        scrapy谁告诉你只能在控制台启动的?你是抖和BILI看多了吧!!
            -    ---,;

正文:

传统方式 vs 脚本方式

在Scrapy框架中,传统方式一般是指通过终端(或命令行)启动Scrapy项目,而脚本方式是指在Python环境中直接运行一个或多个Scrapy爬虫。
传统方式:
  1. 命令行启动: 通过运行scrapy crawl spidername在终端或命令提示符中启动爬虫。
  2. 配置分散: 命令行参数和项目的settings.py文件分散配置。
  3. 单一进程: 一次通常只能运行一个爬虫,且运行多个爬虫需要多个终端窗口。
  4. 输出受限: 数据通常输出到预设位置,改变输出需修改设置或使用指令参数。

脚本方式:
  1. Python脚本启动: 通过创建一个Python脚本,使用Scrapy API来配置和运行爬虫。
  2. 集中配置: 脚本中统一设置,包括爬虫参数和自定义设置。
  3. 并发运行: 同一个脚本中可以配置和运行多个爬虫实例,实现并行爬取。
  4. 灵活输出: 数据可以在脚本中按需处理,并动态指定输出位置。

案例:

# Python脚本内部运行Scrapy
from scrapy.crawler import CrawlerProcess
from myproject.spiders.spider_one import SpiderOne
from myproject.spiders.spider_two import SpiderTwo

process = CrawlerProcess(get_project_settings())

# 定时运行不同的爬虫
process.crawl(SpiderOne)
process.crawl(SpiderTwo)

# 开始爬取
process.start()  # 脚本会在这里阻塞直到所有爬虫执行完毕

# 爬取完成后,例如,发送邮件通知或生成报告
send_email_notification()
generate_report()

在此案例中,两个爬虫SpiderOne和SpiderTwo会并发执行,它们各自独立工作,不共享数据或状态。


实现多线程/多实例爬虫


     Scrapy框架提供了良好的支持,但对于大规模数据采集任务,引入多线程和多实例运行可以显著提升数据爬取效率
虽然CrawlerProcess在单个进程中管理多个爬虫,使用Python的多线程或多进程库可以实现更高级别的并发。这允许每个爬虫在自己的进程或线程中运行,有利于CPU密集型或I/O密集型的任务。
多线程案例:
from threading import Thread
from scrapy.crawler import CrawlerRunner
from scrapy.utils.project import get_project_settings

settings = get_project_settings()
runner = CrawlerRunner(settings)

def run_spider(spider):
    runner.crawl(spider)
    runner.join()

# 启动线程以运行爬虫
thread1 = Thread(target=run_spider, args=(SpiderOne,))
thread2 = Thread(target=run_spider, args=(SpiderTwo,))

thread1.start()
thread2.start()

thread1.join()
thread2.join()
多进程案例:
from multiprocessing import Process
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings

def run_spider(spider):
    process = CrawlerProcess(get_project_settings())
    process.crawl(spider)
    process.start()

# 创建并启动进程
process1 = Process(target=run_spider, args=(SpiderOne,))
process2 = Process(target=run_spider, args=(SpiderTwo,))

process1.start()
process2.start()

process1.join()
process2.join()
在讨论多线程和多进程时,应注意Python的全局解释器锁(GIL)限制,它使得真正的并行只能在多进程中实现,而非多线程。对于CPU密集型任务,应优先选择多进程来提高效率。然而,Scrapy以I/O操作为主,因此通常情况下,使用多线程或CrawlerProcess就已经足够

小总结:

通过结合Scrapy的CrawlerProcess和Python的多线程/多进程技术,开发者可以为他们的应用构建一个强大的爬虫集群,实现高效的数据采集。在数据采集的世界中,这种能力是无价的,可以显著减少采集时间,同时提取大量信息。


交互性扩展

  为了提升Scrapy爬虫的适用性和灵活性,有时需要在运行时传递参数,或者处理爬虫返回的数据!Scrapy支持在启动爬虫时传递参数,这对于需要根据不同条件抓取页面的情况非常有用。

案例:

假设我们有一个爬虫需要根据用户输入的关键词搜索数据:

from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from myproject.spiders import MySpider

process = CrawlerProcess(get_project_settings())

# 运行爬虫,并将关键词作为参数传递
keyword = 'python'
process.crawl(MySpider, keyword=keyword)
process.start()

在上面的脚本示例中,我们通过crawl方法传递了一个关键字参数到爬虫。在爬虫中,你可以通过__init__方法访问这个参数。

import scrapy

class MySpider(scrapy.Spider):
    name = 'myspider'
    
    def __init__(self, keyword=None, *args, **kwargs):
        super(MySpider, self).__init__(*args, **kwargs)
        self.keyword = keyword  # 使用传递的关键词

    def start_requests(self):
        url = f'http://search.example.com/?q={self.keyword}'
        yield scrapy.Request(url, self.parse)

    def parse(self, response):
        # 爬虫的解析逻辑
        pass
从爬虫获取并处理数据

Scrapy爬虫可以将抓取到的数据作为Items返回。然后,这些Items可以在Pipeline中进一步处理。如果需要在脚本中直接处理数据,可以在爬虫中捕获这些数据并将其返回。

import scrapy
from scrapy.crawler import CrawlerRunner
from scrapy import signals
from twisted.internet import reactor
from scrapy.utils.project import get_project_settings

class MySpider(scrapy.Spider):
    # ... 其他代码 ...

    def parse(self, response):
        # 解析逻辑,提取数据
        yield {'url': response.url}

def item_collected(item):
    print(item['url'])  # 打印或处理Item

runner = CrawlerRunner(get_project_settings())

def crawl_job():
    spider = MySpider(keyword='python')
    deferred = runner.crawl(spider)
    deferred.addBoth(lambda _: reactor.stop())  # 当爬虫结束时停止reactor
    runner.signals.connect(item_collected, signal=signals.item_scraped)
    reactor.run()  # 启动事件循环

crawl_job()
在crawl_job函数中,我们创建了一个爬虫实例并启动了爬虫,同时连接了一个信号处理函数item_collected到item_scraped信号。每当有Item被抓取时,该信号被触发,执行item_collected函数。

小总结:

通过Scrapy提供的接口和信号系统,我们可以灵活地在运行时传递参数给爬虫,以及在脚本中处理爬虫收集的数据。这两个特性极大地增强了Scrapy的交互性,使其不仅可以在终端运行,而且可以作为Python项目的一部分,与其他组件相集成。
这种增强的交互性特别适合构建复杂的爬取任务,如定时任务、条件抓取、数据后处理、实时分析等。

你可能感兴趣的:(15天玩转高级python,爬虫,scrapy)