Мне нужно запускать парсеры в цикле, но если в пауке возникают определенные ошибки, я хотел бы иметь возможность вызвать CloseSpiderи для этого отфильтровать функцию цикла и остановить цикл.< /p>
Вот мой код, который отлично работает с полностью функционирующим пауком, но я создал небольшой MRE для проверки варианта использования CloseSpider.
from __future__ import print_function
import multiprocessing as mp
import traceback
from time import sleep
from typing import Type
from scrapy import Spider
from scrapy.crawler import CrawlerProcess
from scrapy.exceptions import CloseSpider
class MyTestSpider(Spider):
name = "my_test_spider"
def __init__(self) -> None:
raise CloseSpider
class Process(mp.Process):
def __init__(self, target: callable, *args, **kwargs):
mp.Process.__init__(self, target=target, *args, **kwargs)
self._pconn, self._cconn = mp.Pipe()
self._exception = None
def run(self):
try:
mp.Process.run(self)
self._cconn.send(None)
except Exception as e:
tb = traceback.format_exc()
self._cconn.send(tb)
@property
def exception(self):
if self._pconn.poll():
self._exception = self._pconn.recv()
return self._exception
def run_crawler_loop(
spider: Type[Spider],
loop_wait_secs: int,
**kwargs,
) -> None:
while True:
run_crawler_reactor_safe(spider=spider, **kwargs)
sleep(loop_wait_secs)
def run_crawler_reactor_safe(spider: Type[Spider], **kwargs) -> None:
process = Process(target=run_crawler, kwargs={"spider": spider} | kwargs)
process.start()
process.join()
if process.exception:
error, traceback = process.exception
# send an email here
raise error # close the loop
def run_crawler(spider: Type[Spider], **kwargs) -> None:
process = CrawlerProcess()
crawler = process.create_crawler(spider)
process.crawl(crawler_or_spidercls=crawler, **kwargs)
process.start()
# how would I tell here if the spider was closed due to raising a CloseSpider exception?
# I'd like to raise that exception here so I can stop the loop by raising an error in run_crawler_reactor_safe
if __name__ == "__main__":
run_crawler_loop(spider=MyTestSpider, loop_wait_secs=0)
При выполнении этой команды создаются две записи журнала в скрученном виде:
Unhandled error in Deferred:
2024-10-09 09:39:01 [twisted] CRITICAL: Unhandled error in Deferred:
Traceback (most recent call last):
File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/crawler.py", line 265, in crawl
return self._crawl(crawler, *args, **kwargs)
File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/crawler.py", line 269, in _crawl
d = crawler.crawl(*args, **kwargs)
File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/twisted/internet/defer.py", line 2260, in unwindGenerator
return _cancellableInlineCallbacks(gen)
File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/twisted/internet/defer.py", line 2172, in _cancellableInlineCallbacks
_inlineCallbacks(None, gen, status, _copy_context())
--- ---
File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/twisted/internet/defer.py", line 2003, in _inlineCallbacks
result = context.run(gen.send, result)
File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/crawler.py", line 155, in crawl
self.spider = self._create_spider(*args, **kwargs)
File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/crawler.py", line 169, in _create_spider
return self.spidercls.from_crawler(self, *args, **kwargs)
File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/spiders/__init__.py", line 62, in from_crawler
spider = cls(*args, **kwargs)
File "/Users/myusername/GitHub/polgara_v2/so__capture_SpiderClose.py", line 17, in __init__
raise CloseSpider
scrapy.exceptions.CloseSpider:
2024-10-09 09:39:01 [twisted] CRITICAL:
Traceback (most recent call last):
File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/twisted/internet/defer.py", line 2003, in _inlineCallbacks
result = context.run(gen.send, result)
File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/crawler.py", line 155, in crawl
self.spider = self._create_spider(*args, **kwargs)
File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/crawler.py", line 169, in _create_spider
return self.spidercls.from_crawler(self, *args, **kwargs)
File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/spiders/__init__.py", line 62, in from_crawler
spider = cls(*args, **kwargs)
File "/Users/myusername/GitHub/polgara_v2/so__capture_SpiderClose.py", line 17, in __init__
raise CloseSpider
scrapy.exceptions.CloseSpider
Однако эти ошибки, похоже, обрабатываются здесь и фактически не возникают снова каким-либо образом, который можно было бы отследить дальше. Я просмотрел экземпляры искателя и процесса, когда процесс.start() завершается в run_crawler(), но не могу найти никаких признаков того, что паук позволяет только сообщение об ошибке.
Я также пытался просмотреть пакет Twisted и сообщение о SO (остановка Twisted от проглатывания исключений), но быстро заблудился...< /p>
Есть идеи, как мне добиться того, чего я хочу?
Мне нужно запускать парсеры в цикле, но если в пауке возникают определенные ошибки, я хотел бы иметь возможность вызвать CloseSpiderи для этого отфильтровать функцию цикла и остановить цикл.< /p> Вот мой код, который отлично работает с полностью функционирующим пауком, но я создал небольшой MRE для проверки варианта использования CloseSpider. [code]from __future__ import print_function
import multiprocessing as mp import traceback from time import sleep from typing import Type
from scrapy import Spider from scrapy.crawler import CrawlerProcess from scrapy.exceptions import CloseSpider
class MyTestSpider(Spider): name = "my_test_spider"
# how would I tell here if the spider was closed due to raising a CloseSpider exception? # I'd like to raise that exception here so I can stop the loop by raising an error in run_crawler_reactor_safe
if __name__ == "__main__": run_crawler_loop(spider=MyTestSpider, loop_wait_secs=0) [/code] При выполнении этой команды создаются две записи журнала в скрученном виде: [code]Unhandled error in Deferred: 2024-10-09 09:39:01 [twisted] CRITICAL: Unhandled error in Deferred:
Traceback (most recent call last): File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/crawler.py", line 265, in crawl return self._crawl(crawler, *args, **kwargs) File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/crawler.py", line 269, in _crawl d = crawler.crawl(*args, **kwargs) File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/twisted/internet/defer.py", line 2260, in unwindGenerator return _cancellableInlineCallbacks(gen) File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/twisted/internet/defer.py", line 2172, in _cancellableInlineCallbacks _inlineCallbacks(None, gen, status, _copy_context()) --- --- File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/twisted/internet/defer.py", line 2003, in _inlineCallbacks result = context.run(gen.send, result) File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/crawler.py", line 155, in crawl self.spider = self._create_spider(*args, **kwargs) File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/crawler.py", line 169, in _create_spider return self.spidercls.from_crawler(self, *args, **kwargs) File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/spiders/__init__.py", line 62, in from_crawler spider = cls(*args, **kwargs) File "/Users/myusername/GitHub/polgara_v2/so__capture_SpiderClose.py", line 17, in __init__ raise CloseSpider scrapy.exceptions.CloseSpider:
2024-10-09 09:39:01 [twisted] CRITICAL: Traceback (most recent call last): File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/twisted/internet/defer.py", line 2003, in _inlineCallbacks result = context.run(gen.send, result) File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/crawler.py", line 155, in crawl self.spider = self._create_spider(*args, **kwargs) File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/crawler.py", line 169, in _create_spider return self.spidercls.from_crawler(self, *args, **kwargs) File "/Users/myusername/opt/miniconda3/envs/myenv/lib/python3.11/site-packages/scrapy/spiders/__init__.py", line 62, in from_crawler spider = cls(*args, **kwargs) File "/Users/myusername/GitHub/polgara_v2/so__capture_SpiderClose.py", line 17, in __init__ raise CloseSpider scrapy.exceptions.CloseSpider [/code] Однако эти ошибки, похоже, обрабатываются здесь и фактически не возникают снова каким-либо образом, который можно было бы отследить дальше. Я просмотрел экземпляры искателя и процесса, когда процесс.start() завершается в run_crawler(), но не могу найти никаких признаков того, что паук позволяет только сообщение об ошибке. Я также пытался просмотреть пакет Twisted и сообщение о SO (остановка Twisted от проглатывания исключений), но быстро заблудился...< /p> Есть идеи, как мне добиться того, чего я хочу?