Scrapy如何编写自定义中间件自动从谷歌表格加载start_urls
实现方案
不需要在每个爬虫中单独编写URL读取逻辑,也不需要针对单个爬虫做适配,通过全局Spider中间件配合Scrapy内置的爬虫启动信号,即可实现一次配置、所有爬虫自动从谷歌表格读取链接填充start_urls,具体实现步骤如下:
1. 编写全局Spider中间件
打开项目目录下的middlewares.py文件,新增如下中间件类:
import gspread from oauth2client.service_account import ServiceAccountCredentials from scrapy import signals from scrapy.exceptions import NotConfigured class GoogleSheetStartUrlsMiddleware: def __init__(self, sheet_name, worksheet_index, url_column, creds_path): self.sheet_name = sheet_name self.worksheet_index = worksheet_index self.url_column = url_column # 初始化谷歌表格客户端,整个爬虫运行周期仅连接一次,避免重复鉴权 scope = [ 'https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive' ] creds = ServiceAccountCredentials.from_json_keyfile_name(creds_path, scope) self.client = gspread.authorize(creds) @classmethod def from_crawler(cls, crawler): # 读取全局开关,未开启时不加载该中间件 if not crawler.settings.getbool('ENABLE_GOOGLE_SHEET_START_URLS'): raise NotConfigured # 从配置文件读取表格参数,默认值与你现有代码保持一致 sheet_name = crawler.settings.get('GOOGLE_SHEET_NAME', 'Sheet_1') worksheet_index = crawler.settings.getint('GOOGLE_SHEET_WORKSHEET_INDEX', 0) url_column = crawler.settings.getint('GOOGLE_SHEET_URL_COLUMN', 2) creds_path = crawler.settings.get('GOOGLE_SHEET_CREDS_PATH', 'token.json') instance = cls(sheet_name, worksheet_index, url_column, creds_path) # 绑定爬虫启动信号,爬虫初始化完成后自动执行URL注入 crawler.signals.connect(instance.inject_start_urls, signal=signals.spider_opened) return instance def inject_start_urls(self, spider): # 支持单个爬虫跳过全局注入:在爬虫类中加属性 use_google_sheet_start_urls = False 即可 if getattr(spider, 'use_google_sheet_start_urls', True) is False: return # 读取指定列的所有链接 sheet = self.client.open(self.sheet_name) sheet_instance = sheet.get_worksheet(self.worksheet_index) raw_links = sheet_instance.col_values(col=self.url_column) # 过滤空值、去除首尾空格、去重,避免无效请求和重复抓取 valid_links = [] seen = set() for link in raw_links: link = link.strip() if link and link not in seen: valid_links.append(link) seen.add(link) # 注入链接到start_urls:默认追加到爬虫原有start_urls后做全局去重 if hasattr(spider, 'start_urls'): spider.start_urls.extend(valid_links) spider.start_urls = list(set(spider.start_urls)) else: spider.start_urls = valid_links
2. 注册中间件并添加配置
打开项目的settings.py文件,做两处配置:
- 将新增的中间件加入
SPIDER_MIDDLEWARES列表,优先级数值建议设为50(低于默认中间件优先级),保证在请求生成前完成URL注入:
SPIDER_MIDDLEWARES = { # 保留原有已配置的中间件,新增下面这行 '你的项目名.middlewares.GoogleSheetStartUrlsMiddleware': 50, }
注意将你的项目名替换为你本地Scrapy项目的实际目录名称
- 添加功能开关和表格参数配置,默认值与你现有代码完全匹配,可按需修改:
# 全局开关,设为False即可一键关闭所有爬虫的表格URL自动注入 ENABLE_GOOGLE_SHEET_START_URLS = True # 谷歌表格配置项 GOOGLE_SHEET_NAME = 'Sheet_1' GOOGLE_SHEET_WORKSHEET_INDEX = 0 GOOGLE_SHEET_URL_COLUMN = 2 GOOGLE_SHEET_CREDS_PATH = 'token.json'
使用说明
- 配置完成后,执行
scrapy crawl 爬虫名启动任意爬虫时,都会自动读取谷歌表格中的链接填充到start_urls,不需要在单个爬虫文件中编写任何读取逻辑 - 如果某个特殊爬虫不需要加载表格中的链接,只需要在对应爬虫类中添加一行属性即可跳过全局逻辑:
class SpecialSpider(scrapy.Spider): name = 'special_spider' use_google_sheet_start_urls = False # 加这行就不会注入表格链接 start_urls = ['https://example.com'] # 仅使用爬虫内定义的起始链接 - 如果你希望完全使用表格中的链接、忽略爬虫文件内手动写的
start_urls,只需要把inject_start_urls方法中的链接赋值逻辑替换为直接赋值即可:# 注释掉原来的if/else判断,直接给start_urls赋值 spider.start_urls = valid_links
不推荐用下载中间件实现该需求:下载中间件的作用是处理发起请求后的请求/响应逻辑,起始URL注入属于爬虫初始化阶段的操作,用Spider中间件配合
spider_opened信号实现,整个爬虫运行周期仅读取一次表格,性能最优。
内容的提问来源于stack exchange,提问作者m_sasha
相关产品推荐
相关产品推荐

