
在 scrapy 爬虫中,局部变量无法跨回调函数访问;若需将 parse() 中生成的日期(如 scrapedate)传递至深层解析函数(如 parse_race()),应通过 spider 实例属性(self.scrapedate)实现状态共享。
Scrapy 的请求-响应流程是异步且基于回调的:parse() 生成的 Request 对象在后续被调度执行时,会调用指定的回调函数(如 parse_date),但此时原始 parse() 的局部作用域已销毁,其中定义的变量(如 scrapedate)不可访问。因此,直接在 parse_race() 中引用 scrapedate 会导致 NameError: name 'scrapedate' is not defined。
正确做法是将该值提升为 Spider 实例的属性(即 self.scrapedate),使其在整个爬虫生命周期内可被任意回调方法读取。注意:由于 Scrapy 可能并发处理多个请求,不能简单地将 self.scrapedate 作为全局共享变量使用——必须确保每个请求链携带其对应的上下文。更健壮、推荐的方式是使用 cb_kwargs(Scrapy 1.7+ 支持),将参数显式传递给回调函数:
import scrapy
from datetime import datetime, timedelta
from dogscraper.items import DogItem
racedate = '2024-01-25'
days = 2
realdate = datetime.strptime(racedate, '%Y-%m-%d').date()
scrape_list = [(realdate - timedelta(days=x)).strftime('%Y-%m-%d') for x in range(days)]
class DogspiderSpider(scrapy.Spider):
name = "dogspider"
allowed_domains = ["www.thedogs.com.au"]
start_urls = ["https://www.thedogs.com.au/racing/" + racedate]
def parse(self, response):
for scrapedate in scrape_list:
next_dateurl = 'https://www.thedogs.com.au/racing/' + scrapedate
# ✅ 推荐:使用 cb_kwargs 安全传递上下文
yield scrapy.Request(
url=next_dateurl,
callback=self.parse_date,
cb_kwargs={'scrapedate': scrapedate}
)
def parse_date(self, response, scrapedate): # ← 参数自动注入
nswmeetings = response.css('table.meeting-grid')[0].css('td.meetings-venues__name')
for meeting in nswmeetings:
meeting_url = meeting.css('a::attr(href)').get()
if meeting_url:
nextmeeting = 'https://www.thedogs.com.au' + meeting_url
yield scrapy.Request(
url=nextmeeting,
callback=self.parse_meeting,
cb_kwargs={'scrapedate': scrapedate} # 向下透传
)
def parse_meeting(self, response, scrapedate):
races = response.css('a.race-box.race-box--result')
for race in races:
race_url = race.css('::attr(href)').get()
if race_url:
nextrace = 'https://www.thedogs.com.au' + race_url
yield scrapy.Request(
url=nextrace,
callback=self.parse_race,
cb_kwargs={'scrapedate': scrapedate} # 持续透传
)
def parse_race(self, response, scrapedate): # ← 最终接收
dogs = response.css('tr.accordion__anchor.race-runner')
for dog in dogs:
dog_item = DogItem()
dog_item['date'] = scrapedate # ✅ 安全赋值
# ... 其他字段提取逻辑
yield dog_item✅ 优势说明:
- cb_kwargs 是 Scrapy 原生支持的线程安全机制,避免多请求间属性覆盖风险;
- 语义清晰,显式声明依赖,便于调试与维护;
- 符合函数式回调设计原则,不依赖隐式状态。
⚠️ 注意事项:
- 若仍选择 self.scrapedate = ... 方式,请确保无并发请求冲突(例如禁用并发:custom_settings = {'CONCURRENT_REQUESTS': 1}),否则将导致数据错乱;
- 所有 cb_kwargs 传入的参数必须在对应回调函数签名中声明,否则抛出 TypeError;
- 始终校验 CSS 选择器结果(如 .get() 返回 None 时需跳过),避免 IndexError 或 AttributeError。
综上,优先使用 cb_kwargs 传递上下文变量,这是 Scrapy 官方推荐、高可靠、易扩展的最佳实践。










