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

Scrapy插入SQLite遇NameError,如何将字典数据写入SQLite?

解决Scrapy爬虫写入SQLite时的NameError问题

问题描述

我尝试用Scrapy把字典数据写入SQLite数据库,但执行失败,报错:

NameError: name 'url' is not defined

触发错误的代码行是:

cursor.execute('INSERT INTO posts(url, First_and_Last_Name) VALUES("%s", "%s")' % (url, First_and_Last_Name))

我的完整爬虫代码如下:

from scrapy.crawler import CrawlerProcess
import scrapy
import sqlite3

class Wellness(scrapy.Spider):
    name = "wellness"
    start_urls = ['https://www.wellness.com/dir/6022571/acupuncturist/ri/east-greenwich/hwasook-lee-phoenix-fertility-center-dac']

    def parse(self, response):
        item = {
            'url' : response.request.url,
            'First_and_Last_Name' : response.css('h1::text').get(),
        }
        directions_link = response.css('#directions_tab a::attr(href)').get()
        yield scrapy.Request(response.urljoin(directions_link), callback=self.parse_directions, meta={'item': item})

    def parse_directions(self, response):
        item = response.meta['item']
        item['Phone'] = response.css('.tel::text').get()
        yield item

db = sqlite3.connect('posts.db')
db.execute('''CREATE TABLE IF NOT EXISTS posts(id INTEGER PRIMARY KEY AUTOINCREMENT,url TEXT, First_and_Last_Name TEXT);''')
db.commit()
cursor = db.cursor()
cursor.execute('INSERT INTO posts(url, First_and_Last_Name) VALUES("%s", "%s")' % (url, First_and_Last_Name))
db.commit()
db.close()

if __name__ == '__main__':
    process = CrawlerProcess()
    process.crawl(Wellness)
    process.start()

请问我哪里操作错误?恳请各位提供帮助,谢谢!


问题根源分析

你遇到的NameError本质上是两个问题导致的:

  1. 作用域错误:你把SQL插入代码写在了全局作用域里,这部分代码会在爬虫启动前就执行,但此时爬虫还没开始爬取,url和First_and_Last_Name这两个变量根本不存在——它们是爬虫在parse方法里生成的Item字段,只有爬虫运行时才会产生。
  2. SQL注入风险:直接用%s字符串拼接构造SQL语句是不安全的,不仅可能引发语法错误,还会带来SQL注入隐患。

正确解决方案:用Scrapy Item Pipeline处理数据库存储

Scrapy专门设计了Pipeline组件来处理爬取到的Item数据,这是存储数据的标准且规范的方式。以下是修改后的完整代码:

1. 调整爬虫代码(可选:定义Item类,让数据结构更清晰)

from scrapy.crawler import CrawlerProcess
import scrapy
import sqlite3
from scrapy.item import Item, Field

# 定义Item类(可选,但推荐用这种方式规范数据结构)
class WellnessItem(Item):
    url = Field()
    First_and_Last_Name = Field()
    Phone = Field()

class Wellness(scrapy.Spider):
    name = "wellness"
    start_urls = ['https://www.wellness.com/dir/6022571/acupuncturist/ri/east-greenwich/hwasook-lee-phoenix-fertility-center-dac']

    def parse(self, response):
        item = WellnessItem()
        item['url'] = response.request.url
        item['First_and_Last_Name'] = response.css('h1::text').get()
        directions_link = response.css('#directions_tab a::attr(href)').get()
        yield scrapy.Request(response.urljoin(directions_link), callback=self.parse_directions, meta={'item': item})

    def parse_directions(self, response):
        item = response.meta['item']
        item['Phone'] = response.css('.tel::text').get()
        yield item

2. 编写数据库Pipeline

class SQLitePipeline:
    def open_spider(self, spider):
        # 爬虫启动时初始化数据库连接
        self.conn = sqlite3.connect('posts.db')
        self.cursor = self.conn.cursor()
        # 创建表(如果不存在),新增Phone字段适配你的Item
        self.cursor.execute('''CREATE TABLE IF NOT EXISTS posts(
                            id INTEGER PRIMARY KEY AUTOINCREMENT,
                            url TEXT, 
                            First_and_Last_Name TEXT,
                            Phone TEXT);''')
        self.conn.commit()

    def close_spider(self, spider):
        # 爬虫关闭时关闭数据库连接,避免资源泄漏
        self.conn.close()

    def process_item(self, item, spider):
        # 使用参数化查询插入数据,彻底避免SQL注入和字符串转义问题
        self.cursor.execute('''INSERT INTO posts(url, First_and_Last_Name, Phone)
                            VALUES(?, ?, ?)''', 
                            (item['url'], item['First_and_Last_Name'], item['Phone']))
        self.conn.commit()
        return item

3. 配置并启动爬虫

if __name__ == '__main__':
    process = CrawlerProcess(settings={
        'ITEM_PIPELINES': {
            # 启用我们编写的Pipeline,优先级数字越小越先执行
            '__main__.SQLitePipeline': 300,
        }
    })
    process.crawl(Wellness)
    process.start()

关键改进点

  • 数据流向正确:只有当爬虫真正爬取到数据并生成Item时,Pipeline的process_item方法才会执行插入操作,确保能获取到有效的字段值。
  • 安全的SQL操作:用?作为占位符的参数化查询,既避免了SQL注入,也解决了特殊字符串(比如含引号的内容)的转义问题。
  • 资源管理规范:通过open_spider和close_spider统一管理数据库连接的生命周期,避免不必要的资源浪费。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 19:08:12