scrapy 执行 shell 命令 - 并行
我想利用 scrapy 的 parse 执行不同的 bash 命令,这个命令是并行的
在 Scrapy 中,parse
方法是用来解析网页内容的,通常不直接用于执行外部命令。如果你想在 Scrapy 中执行并行的 bash 命令,可以考虑以下几种方法:
方法 1: 使用 Python 的 subprocess
模块
你可以在 parse
方法中使用 Python 的 subprocess
模块来执行 bash 命令。为了实现并行执行,可以使用 concurrent.futures
模块中的 ThreadPoolExecutor
或 ProcessPoolExecutor
。
import scrapy
import subprocess
from concurrent.futures import ThreadPoolExecutor
class MySpider(scrapy.Spider):
name = 'my_spider'
start_urls = ['http://example.com']
def parse(self, response):
commands = [
'echo Command 1',
'echo Command 2',
'echo Command 3',
]
with ThreadPoolExecutor(max_workers=5) as executor:
futures = [executor.submit(self.run_command, cmd) for cmd in commands]
for future in futures:
future.result() # 等待所有命令执行完成
def run_command(self, command):
result = subprocess.run(command, shell=True, capture_output=True, text=True)
self.logger.info(f"Command: {command}, Output: {result.stdout}")
方法 2: 使用 Scrapy 的 Item Pipeline
和 Twisted
的异步特性
Scrapy 是基于 Twisted 的异步框架,你可以利用 Twisted 的异步特性来执行并行的 bash 命令。
import scrapy
from twisted.internet import reactor, defer
from twisted.internet.threads import deferToThread
import subprocess
class MySpider(scrapy.Spider):
name = 'my_spider'
start_urls = ['http://example.com']
def parse(self, response):
commands = [
'echo Command 1',
'echo Command 2',
'echo Command 3',
]
deferreds = [self.run_command(cmd) for cmd in commands]
dl = defer.DeferredList(deferreds)
dl.addCallback(self.all_commands_done)
return dl
def run_command(self, command):
return deferToThread(subprocess.run, command, shell=True, capture_output=True, text=True)
def all_commands_done(self, results):
for success, result in results:
if success:
self.logger.info(f"Command: {result.args}, Output: {result.stdout}")
方法 3: 使用 Scrapy 的 Item Pipeline
和 asyncio
如果你使用的是 Python 3.7+,你可以使用 asyncio
来执行并行的 bash 命令。
import scrapy
import asyncio
import subprocess
class MySpider(scrapy.Spider):
name = 'my_spider'
start_urls = ['http://example.com']
async def parse(self, response):
commands = [
'echo Command 1',
'echo Command 2',
'echo Command 3',
]
tasks = [self.run_command(cmd) for cmd in commands]
await asyncio.gather(*tasks)
async def run_command(self, command):
process = await asyncio.create_subprocess_shell(
command,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await process.communicate()
self.logger.info(f"Command: {command}, Output: {stdout.decode().strip()}")
总结
- 方法 1 使用
ThreadPoolExecutor
来并行执行命令,适合简单的并行任务。 - 方法 2 利用 Scrapy 的异步特性,适合在 Scrapy 的异步环境中执行并行任务。
- 方法 3 使用
asyncio
,适合 Python 3.7+ 的环境,并且可以更好地与 Scrapy 的异步框架集成。
根据你的需求和环境选择合适的方案。