使用Python-Scrapy在Scrapinghub中正确读写文件的方法是什么?
问题
我在使用Python-Scrapy配合Scrapinghub开发爬虫时,遇到了文件读写的问题。本地服务器运行正常的代码,在Scrapinghub上无法完成文件读写操作,相关代码如下:
import os import sqlite3 data_directory = 'tmp' csv_magasin = data_directory+"/"+current_script+"_"+current_date+"-shop_url.csv" if not os.path.exists(data_directory): os.makedirs(data_directory) try: os.remove('products.db') except: pass f = open('products.db', 'w') f.write(t.content) f.close con = sqlite3.connect("products.db") c = con.cursor()
查阅官方文档没找到正确方法,想请教在Scrapinghub中正确写入文件的方式。
解决方案
其实Scrapinghub的运行环境和本地完全不一样,它采用容器化部署,对文件系统有严格的权限和生命周期限制,直接用本地的文件读写逻辑肯定行不通。我给你几个针对性的解决方案:
1. 改用Scrapinghub的临时存储目录
Scrapinghub的爬虫容器里提供了专门的临时存储目录,你可以通过环境变量SCRAPY_TEMPDIR获取,或者直接使用/tmp目录(这个目录是容器默认的临时存储区,注意爬虫任务结束后会被自动清理)。修改后的代码如下:
import os import sqlite3 # 获取Scrapinghub的临时目录, fallback到/tmp data_directory = os.environ.get('SCRAPY_TEMPDIR', '/tmp') # 用os.path.join拼接路径更安全,避免路径分隔符问题 csv_magasin = os.path.join(data_directory, f"{current_script}_{current_date}-shop_url.csv") # 处理SQLite文件 db_path = os.path.join(data_directory, 'products.db') try: os.remove(db_path) except FileNotFoundError: pass # 用with语句自动管理文件句柄,避免手动close的遗漏问题 with open(db_path, 'w') as f: f.write(t.content) con = sqlite3.connect(db_path) c = con.cursor()
另外要注意,你之前的代码里f.close少了括号,应该是f.close(),用with语句可以彻底避免这类问题。
2. 放弃本地SQLite,用Scrapinghub原生数据存储
如果你的核心需求是存储爬取的数据,其实完全没必要自己维护SQLite文件。Scrapinghub本身就提供了完善的Item存储和导出功能:
- 把爬取的数据封装成Scrapy的
Item对象,通过默认的Pipeline自动提交到Scrapinghub的存储系统 - 之后可以在Scrapinghub后台直接导出CSV、JSON等格式的文件,或者通过官方API批量获取数据
这种方式既不用处理文件读写的权限问题,也更符合Scrapinghub的设计逻辑,数据还能持久化保存。
3. 用Scrapy Files Pipeline处理文件存储
如果你的需求是下载并存储特定文件(比如页面源码、图片、附件等),可以用Scrapy自带的Files Pipeline配合Scrapinghub的存储:
在settings.py里添加配置:
ITEM_PIPELINES = { 'scrapy.pipelines.files.FilesPipeline': 1, } # 指定存储到临时目录 FILES_STORE = os.environ.get('SCRAPY_TEMPDIR', '/tmp')
然后在你的Item类里定义file_urls和files字段:
import scrapy class ProductItem(scrapy.Item): file_urls = scrapy.Field() files = scrapy.Field()
之后爬虫会自动下载指定URL的文件并存储到配置的目录,这些文件可以在Scrapinghub的任务详情页面中找到。
最后要提醒一句:Scrapinghub的容器环境里,除了临时目录,其他目录基本都是只读的;而且临时目录的内容会在任务结束后被清理,如果需要持久化存储,一定要用Scrapinghub的原生存储服务或者把数据导出到外部系统。
内容的提问来源于stack exchange,提问作者parik

