You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scrapy爬虫解析仅获取每个表格首个元素的问题咨询

问题原因

你现在的代码逻辑有两层核心问题:

  1. 循环层级错误:外层你只遍历了每个table.acta-table表格节点,但进入单个表格后,直接调用css('a::text').get(),Scrapy中get()方法只会返回匹配规则的第一个元素,你没有继续遍历表格内部的每一行(<tr>标签),所以每个表格自然只能抓到第一条a标签的内容,剩下的行数据全被漏掉了。
  2. 未做表格类型区分:页面上多个acta-table分别对应主队首发、客队替补、红黄牌、进球记录等不同板块,你现在的写法没有区分表格归属,根本没法生成预期的嵌套结构JSON。
修复思路
  • 先提取固定字段:优先处理不需要循环的单对象内容,也就是比赛基本信息(DadesPartit)、场馆信息(Estadi),直接从页面对应节点取值即可。
  • 做表格映射关联:通过表格的专属class、表格前置标题文本定位不同功能板块的表格,和你预期JSON里的字段一一对应。
  • 逐行提取列表数据:对每个存列表的表格,先跳过表头行,遍历剩下的每一个<tr>行节点,在单行的作用域里提取姓名、链接、卡牌类型、进球分钟这些对应字段,每行生成一个字典存入对应板块的列表。
  • 不要用裸except:这种写法会吞掉所有真实报错,调试时根本定位不到问题,只需要捕获你预期的特定异常(比如属性不存在的KeyError)即可。
参考修改代码
import scrapy

class ActaSpider(scrapy.Spider):
    name = 'acta_spider'
    start_urls = ['https://www.fcf.cat/acta/2022/futbol-11/cadet-primera-divisio/grup-2/1c/la-salle-bonanova-ce-a/1c/lhospitalet-centre-esports-b']
    
    def parse(self, response):
        result = {}
        # 提取比赛基本信息,选择器需要根据页面实际DOM调整
        match_info = response.css('.match-data-block')
        result['DadesPartit'] = {
            'Temporada': match_info.css('.season::text').get('').strip(),
            'Categoria': match_info.css('.category::text').get('').strip(),
            'Divisio': match_info.css('.division::text').get('').strip(),
            'Grup': int(match_info.css('.group::text').get('0').strip()),
            'Jornada': int(match_info.css('.matchday::text').get('0').strip())
        }
        # 提取场馆信息
        stadium_info = response.css('.stadium-block')
        result['Estadi'] = {
            'Nom': stadium_info.css('.stadium-name::text').get('').strip(),
            'Direccio': stadium_info.css('.stadium-address::text').get('').strip()
        }
        # 列表类表格和JSON字段的映射关系
        table_config = [
            ('TitularsCasa', 'table.acta-table.home-starters'),
            ('SuplentsCasa', 'table.acta-table.home-bench'),
            ('CosTecnicCasa', 'table.acta-table.home-staff'),
            ('TargetesCasa', 'table.acta-table.home-cards'),
            ('Arbitres', 'table.acta-table.referees'),
            ('Gols', 'table.acta-table.goals'),
            ('TitularsFora', 'table.acta-table.away-starters'),
            ('SuplentsFora', 'table.acta-table.away-bench'),
            ('CosTecnicFora', 'table.acta-table.away-staff'),
            ('TargetesFora', 'table.acta-table.away-cards'),
        ]
        # 逐表格逐行提取数据
        for field_name, table_selector in table_config:
            table = response.css(table_selector)
            item_list = []
            # 跳过表头行遍历数据行
            for row in table.css('tr:not(:first-child)'):
                # 跳过空行
                if not row.css('a::text, td::text').get('').strip():
                    continue
                item = {}
                # 提取通用姓名字段,根据页面实际标签结构调整
                item['Nom'] = row.css('.player-firstname::text').get('').strip()
                item['Cognom'] = row.css('.player-lastname::text').get('').strip()
                # 提取球员链接,相对路径转绝对路径
                player_link = row.css('a::attr(href)').get()
                if player_link and 'Link' in [k for k in item.keys()]:
                    item['Link'] = response.urljoin(player_link)
                else:
                    item['Link'] = 'Link Error'
                # 按表格类型提取专属字段
                if 'Targetes' in field_name:
                    item['Tipus'] = row.css('.card-type::text').get('').strip()
                    item['Minut'] = int(row.css('.minute::text').get('0').strip())
                    item.pop('Link')
                if 'CosTecnic' in field_name:
                    item['Llicencia'] = row.css('.license::text').get('').strip()
                    item.pop('Link')
                if field_name == 'Arbitres':
                    item['Delegacio'] = row.css('.delegation::text').get('').strip()
                    item.pop('Link')
                if field_name == 'Gols':
                    item['Tipus'] = row.css('.goal-type::text').get('').strip()
                    item['Minut'] = int(row.css('.minute::text').get('0').strip())
                    item.pop('Link')
                item_list.append(item)
            result[field_name] = item_list
        yield result

*注意:代码里的CSS类名是通用示例,你需要打开浏览器开发者工具,对照目标页面的实际DOM结构调整选择器,核心逻辑不要改动——必须在表格内逐行遍历,不能直接在表格节点上调用get()取单个值。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 08:18:34