You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用Scrapy将爬取数据正确存储至两台服务器?

这问题我碰到过!命令行里重复设置FEED_URI确实会被覆盖,因为Scrapy只会读取最后一个相同的配置项。要实现同时导出到两台FTP服务器,有几个靠谱的方案,我给你拆解下:

方案一:用Scrapy 2.0+的FEEDS配置(最推荐)

从Scrapy 2.0开始,官方支持通过FEEDS字典来配置多个输出目标,这比重复设置FEED_URI靠谱多了。你只需要在项目的settings.py里添加如下配置:

FEEDS = {
    'ftp://usr:pass@host:port/path/to/folder-ftp/allITems.csv': {
        'format': 'csv',
        'encoding': 'utf-8',
        'overwrite': True  # 如果需要覆盖已有文件的话
    },
    'ftp://usr2:pas2s@host2:port2/path/to/folder-ftp/allITems.csv': {
        'format': 'csv',
        'encoding': 'utf-8',
        'overwrite': True
    }
}

配置好之后,直接运行scrapy crawl spiderName就行,Scrapy会自动把数据同时导出到这两个FTP地址。这个方法最省心,完全不用改爬虫代码,官方原生支持,稳定性也有保障。

方案二:自定义FTP上传Pipeline(更灵活)

如果你的需求更复杂(比如要对不同服务器做不同的数据处理、或者需要自定义上传逻辑),可以自己写一个Pipeline来处理多服务器上传。

比如,写一个这样的Pipeline(注意Scrapy基于Twisted,最好用异步的FTP客户端):

from scrapy.exceptions import DropItem
from twisted.protocols.ftp import FTPClient
from twisted.internet import reactor, defer

class MultiFTPPipeline:
    def __init__(self):
        self.ftp_connections = []
        # 定义两台服务器的配置
        self.servers = [
            {'host': 'host', 'port': port, 'user': 'usr', 'passwd': 'pass', 'path': '/path/to/folder-ftp/allITems.csv'},
            {'host': 'host2', 'port': port2, 'user': 'usr2', 'passwd': 'pas2s', 'path': '/path/to/folder-ftp/allITems.csv'}
        ]
        # 提前连接所有FTP服务器
        self.connect_all_servers()

    def connect_all_servers(self):
        for server in self.servers:
            client = FTPClient()
            d = client.connect(server['host'], server['port'])
            d.addCallback(lambda _, c, s: c.login(s['user'], s['passwd']), client, server)
            self.ftp_connections.append((client, server))

    @defer.inlineCallbacks
    def process_item(self, item, spider):
        # 将item转为CSV格式的行(这里需要根据你的Item结构调整)
        item_line = ','.join([str(value) for value in item.values()]) + '\n'
        for client, server in self.ftp_connections:
            # 上传数据到FTP服务器(这里假设是追加模式,你也可以改成覆盖)
            yield client.appendFile(server['path'], item_line.encode('utf-8'))
        return item

    def close_spider(self, spider):
        # 关闭所有FTP连接
        for client, _ in self.ftp_connections:
            client.quit()
        reactor.stop()

然后在settings.py里启用这个Pipeline:

ITEM_PIPELINES = {
    'your_project_name.pipelines.MultiFTPPipeline': 300,
}

这个方法的好处是你可以完全控制上传逻辑,比如过滤某些数据再上传到特定服务器,或者处理不同的文件格式。不过需要你对Twisted的异步编程有一点了解。

方案三:本地导出后同步(快速临时方案)

如果不想改任何Scrapy配置或代码,也可以先把数据导出到本地文件,然后用脚本同步到两台FTP服务器。

比如先运行:

scrapy crawl spiderName -s FEED_URI=./local_all_items.csv

然后写一个简单的shell脚本(比如sync_to_ftp.sh):

#!/bin/bash
# 同步到第一台服务器
lftp -e "put ./local_all_items.csv -o /path/to/folder-ftp/allITems.csv; quit" -u usr,pass host:port
# 同步到第二台服务器
lftp -e "put ./local_all_items.csv -o /path/to/folder-ftp/allITems.csv; quit" -u usr2,pas2s host2:port2

给脚本加执行权限:chmod +x sync_to_ftp.sh,然后爬完之后运行脚本就行。这个方法适合临时应急,但缺点是需要额外的步骤,而且如果数据量很大的话,本地存储可能会占用空间。

总结一下:优先用方案一,官方原生支持最省心;如果有特殊需求就用方案二;临时快速解决用方案三。

内容的提问来源于stack exchange,提问作者parik

火山引擎 最新活动