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

使用Scrapy+SQLAlchemy导出数据到SQLite时遇类型绑定错误

解决Scrapy爬虫导出SQLite时的sqlalchemy.exc.InterfaceError错误

问题原因

你遇到的错误根源是数据类型不匹配:从报错参数可以看到,每个待插入的值都是列表类型(比如['ROKT']),但你的SQLAlchemy模型字段定义的是Text/String类型,SQLite无法将列表直接存储为文本,因此触发"不支持的类型"错误。

这是因为Scrapy的ItemLoader默认会把通过add_css/add_xpath收集到的结果存储为列表——哪怕只有一个匹配值,也会被包装进列表里。

解决方案

有两种常用方法可以解决这个问题,选择适合你的方式即可:

方法一:在爬虫阶段处理列表转字符串

直接在ItemLoader加载时获取单个值,或者加载后将列表转为字符串:

for etf in etfs:
    loader = ItemLoader(item=BrandetfsItem(), selector=etf)
    loader.add_css('ticker', 'a.linkTickerName::text')
    loader.add_css('name', 'td.col_2::text')
    loader.add_css('issuer', 'td.col_3::text')
    loader.add_css('aum', 'td.col_4::text')
    loader.add_css('expense_ratio', 'td.col_5::text')
    loader.add_css('tr', 'td.col_6::text')
    loader.add_css('segment', 'td.col_7::text')

    item = loader.load_item()
    # 遍历字段,将列表转为单个字符串,同时处理空值
    for field in ['ticker', 'name', 'issuer', 'aum', 'expense_ratio', 'tr', 'segment']:
        if item.get(field):
            item[field] = item[field][0].strip()
        else:
            item[field] = ''
    yield item

方法二:在Pipeline阶段处理列表转字符串

如果不想修改爬虫逻辑,也可以在存储前处理数据:

class BrandetfsPipeline(object):
    def __init__(self):
        engine = db_connect()
        create_table(engine)
        self.Session = sessionmaker(bind=engine)

    def process_item(self, item, spider):
        session = self.Session()
        etf = ETF()
        # 取列表第一个元素,为空则设默认值,避免索引越界
        etf.ticker = item["ticker"][0].strip() if item["ticker"] else ''
        etf.name = item["name"][0].strip() if item["name"] else ''
        etf.issuer = item["issuer"][0].strip() if item["issuer"] else ''
        etf.aum = item["aum"][0].strip() if item["aum"] else ''
        etf.expense_ratio = item["expense_ratio"][0].strip() if item["expense_ratio"] else ''
        etf.tr = item["tr"][0].strip() if item["tr"] else ''
        etf.segment = item["segment"][0].strip() if item["segment"] else ''

        try:
            session.add(etf)
            session.commit()
        except:
            session.rollback()
            raise
        finally:
            session.close()

        return item

注意事项

  • 推荐使用方法一,让数据清洗和数据存储职责分离,代码结构更清晰。
  • 一定要处理空值判断:如果某个字段抓取失败,对应的列表会是空的,直接取[0]会触发索引越界错误,所以要先判断列表是否非空。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 08:36:22