
在 scrapy 爬虫中,若需提取整个页面共有的非重复字段(如赛程距离),应避免在循环内重复定位,而应在解析函数顶层一次性提取后注入每条记录。
在 scrapy 爬虫中,若需提取整个页面共有的非重复字段(如赛程距离),应避免在循环内重复定位,而应在解析函数顶层一次性提取后注入每条记录。
在爬取赛狗赛事页面(例如 https://www.php.cn/link/0910e6e5e6ebebf9a19cd0df422b6b36)时,常遇到一个典型问题:距离(如 ✅ 正确做法是:将页面级元信息(如 distance、race_name、track_condition 等)在循环外统一提取,再作为常量赋值给每条子记录。 这不仅提升稳定性,也显著提高性能(避免重复 DOM 查找)。 以下为优化后的关键代码示例(基于 Scrapy 2.11+ 推荐写法,兼容异步解析): ⚠️ 注意事项: 总结:Scrapy 中的“页面级字段”应遵循 “一次提取、处处复用” 原则。这既是 selector 使用的基本逻辑,也是构建健壮、可维护爬虫的关键实践。520m)对整场赛事是全局固定的,但错误地将其置于 for div in divs: 循环内部并使用相对 XPath(如 .//div[@class='race-header__info__grade']/a/text())会导致提取失败——因为该元素实际不在每个 行内,而是位于页面顶部的赛事标题区域。 import scrapy
class TheDogsSpider(scrapy.Spider):
name = "thedogs"
start_urls = [
"https://www.php.cn/link/0910e6e5e6ebebf9a19cd0df422b6b36"
]
def parse(self, response):
# ✅ 在循环外提取全局字段:距离(文本含“OPEN 520m”,可后续清洗)
distance = response.css(".race-header__info__grade::text").get(default="").strip()
# 或用XPath等价写法:
# distance = response.xpath('//div[@class="race-header__info__grade"]/text()').get(default="").strip()
# 提取所有参赛犬只行
runner_rows = response.xpath('//tr[@class="accordion__anchor race-runner"]')
for row in runner_rows:
yield {
'distance': distance, # ← 统一注入,非循环内查找
'grade': row.xpath(".//td[@class='race-runners__grade']/text()").getall(),
'greyhound': row.xpath('./td[3]/div[1]/a/text()').get(),
'position': row.xpath('./td[1]/text()').get(),
'trainer': row.xpath(".//div[@class='race-runners__name__trainer']/a/text()").get(),
'weight': row.xpath(".//td[@class='race-runners__weight']/text()").get(),
'first_sec': row.xpath(".//td[@class='race-runners__sectional']/text()").get(),
'second_sec': row.xpath(".//td[@class='race-runners__sectional'][2]/text()").get(),
'time': row.xpath(".//td[@class='race-runners__time']/text()").get(),
'margin': row.xpath(".//td[@class='race-runners__margin']/text()").get(),
'starting_price': row.xpath(".//td[@class='race-runners__starting-price']/text()").get(),
'date': response.url.split('/')[-3],
'track': response.url.split('/')[-4],
'rug': row.xpath('.//td[@class="table__cell--tight race-runners__box"]/sprite-svg/@name').get()
}
.//div[...] 是相对路径,若写在 row.xpath() 内,只会搜索该 节点下的子树;而距离信息在 或独立 response.xpath() 或 response.css() 全局提取。.get(default="") 或 .getall() 配合 default 参数,避免因元素缺失导致 None 传播或异常中断。520),可在 pipeline 中正则提取:re.search(r'(\d+)m', distance).group(1) if distance else None。.race-header__info__grade::text 更简洁、可读性高,且与前端开发语义一致,利于后期维护。










