在线程里运行scrapy的方法的代码

把写内容过程中经常用到的一些内容片段记录起来,下边内容内容是关于在线程里运行scrapy的方法的内容。

When you run the Scrapy crawler from a program, the code blocks until the Scrapy crawler is finished. This is due to how Twisted (the underlying asynchronous network library) works. This prevents using the Scrapy crawler from scripts or other code.

To circumvent this issue you can run the Scrapy crawler in a thread with this code.

Keep in mind that this code is mainly for illustrative purposes and far from production ready.

Also the code was only tested with Scrapy 0.8, and will probably need some adjustments for newer versions (since the core API isn’t stable yet), but you get the idea.

“”"
Code to run Scrapy crawler in a thread - works on Scrapy 0.8
“”"

import threading, Queue

from twisted.internet import reactor

from scrapy.xlib.pydispatch import dispatcher
from scrapy.core.manager import scrapymanager
from scrapy.core.engine import scrapyengine
from scrapy.core import signals

class CrawlerThread(threading.Thread):

def __init__(self): 
    threading.Thread.__init__(self)
    self.running = False

def run(self):
    self.running = True
    scrapymanager.configure(control_reactor=False)
    scrapymanager.start()
    reactor.run(installSignalHandlers=False)

    if not self.running:
        raise RuntimeError("CrawlerThread not running")
    self._call_and_block_until_signal(signals.spider_closed, 

def stop(self):
    reactor.callFromThread(scrapyengine.stop)

    q = Queue.Queue()
    def unblock():
        q.put(None)
    dispatcher.connect(unblock, signal=signal)
    q.get()

Usage example below:

import os
os.environ.setdefault(‘SCRAPY_SETTINGS_MODULE’, ‘myproject.settings’)

from scrapy.xlib.pydispatch import dispatcher
from scrapy.core import signals
from scrapy.conf import settings
from scrapy.crawler import CrawlerThread

settings.overrides[‘LOG_ENABLED’] = False # avoid log noise

def item_passed(item):
print “Just scraped item:”, item

dispatcher.connect(item_passed, signal=signals.item_passed)

crawler = CrawlerThread()
print “Starting crawler thread…”
crawler.start()
print “Crawling somedomain.com…”
crawler.crawl('somedomain.com) # blocking call
print “Crawling anotherdomain.com…”
crawler.crawl(‘anotherdomain.com’) # blocking call
print “Stopping crawler thread…”
crawler.stop()

### Scrapy框架底层源码分析 Scrapy 是一个功能强大的爬虫框架,其设计基于异步事件循环机制,核心组件包括 Spider、Downloader Middleware、Scheduler 和 Downloader 等。以下是对其底层源码实现的关键部分进行解析。 #### 1. **入口函数** Scrapy 的启动流程由 `scrapy.cmdline` 模块中的 `execute()` 函数控制[^4]。该函数会解析命令行参数并初始化项目环境变量。随后调用 `CrawlerProcess` 或 `CrawlerRunner` 来管理多个爬虫实例的生命周期。具体来说: - 当执行 `scrapy crawl my_spider` 命令时,实际进入点是 `scrapy/__main__.py` 文件。 - 这一过程中,通过 `settings.py` 配置文件加载全局设置,并创建 Crawler 对象。 ```python from scrapy.crawler import CrawlerProcess from scrapy.utils.project import get_project_settings settings = get_project_settings() process = CrawlerProcess(settings) process.crawl(MySpider) process.start() ``` #### 2. **调度器 (Scheduler) 实现** Scrapy 使用 Scheduler 组件来管理和分发请求队列。默认情况下,Scheduler 将未处理的 Request 存储到内存或磁盘中,以便后续下载器可以逐步消费这些请求[^3]。 在 `_enqueue_request` 方法中可以看到如何向 Download Slot 添加新的请求对象[^5]: ```python def _enqueue_request(self, request, spider): key, slot = self._get_slot(request, spider) request.meta[self.DOWNLOAD_SLOT] = key slot.active.add(request) ... slot.queue.append((request, deferred)) ``` 这里的核心逻辑在于维护两个集合:一个是当前活动的请求 (`slot.active`);另一个则是等待被发送出去的任务列表 (`slot.queue`)。 #### 3. **中间件链路** Middleware 负责拦截和修改进出的数据流,分为两大部分 —— 请求级与响应级中间件[^2]。它们按照优先级顺序依次被执行,在整个数据传递路径上形成了一条完整的链条。 例如,默认安装了一些内置插件如 HttpProxyMiddleware、RetryMiddleware 等,用来支持代理切换或者失败重试等功能。开发者也可以编写自己的扩展模块来自定义行为模式。 #### 4. **下载器工作原理** Downloader 主要负责发起网络连接以及接收服务器返回的内容片段[^5]。每当有一个新任务到达时都会触发信号通知监听者们关于此事件的发生情况(`signals.request_reached_downloader`) 。之后再把结果封装成 Deferred 对象交给回调函数进一步加工处理。 #### 5. **Twisted 异步编程模型** 由于采用了 Twisted 库作为基础架构的一部分,因此所有的 I/O 操作均是非阻塞式的。这意味着即使某个耗时较长的操作正在进行当中也不会影响其他线程继续运行下去直到完成为止[^4]。 --- ### 示例代码展示 以下是从零构建最简单的 Scrapy 工程结构及其对应的主要方法调用关系图解说明: ```python import scrapy class ExampleSpider(scrapy.Spider): name = "example" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def start_requests(self): urls = ["https://www.example.com"] for url in urls: yield scrapy.Request(url=url, callback=self.parse) def parse(self, response): page_title = response.xpath("//title/text()").extract_first() yield {"page_title": page_title} ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值