脚本怎样存储本地采集数据

wen 实用脚本 29

从零搭建高效本地数据管道

目录导读

  1. 为什么选择本地存储? 本地存储 vs 云端存储的权衡
  2. 核心存储方案对比:文本文件、SQLite、CSV、JSON的选型指南
  3. 实战脚本示例:Python爬虫如何将数据写入本地数据库
  4. 常见问题问答:存储乱码、性能优化、增量写入等高频问题
  5. 防坑指南:路径处理、并发写入、数据校验的关键技巧

为什么选择本地存储?

在数据采集场景中,本地存储是最直接、最可控的方案,尤其当采集频率高(如每秒数百条)、数据敏感(用户隐私)或网络不稳定时,本地存储能避免云端接口限流、网络延迟和第三方依赖风险,一个实时监控股票报价的脚本,若每次更新都通过网络写入远程数据库,可能因API调用超时而丢失关键数据。

脚本怎样存储本地采集数据

本地存储的核心优势

  • 零网络延迟:数据直接落盘,速度可达毫秒级
  • 成本可控:无需支付云存储费用,尤其适合海量临时数据
  • 完全离线:即使断网,脚本仍可稳定采集

核心存储方案对比

选择存储格式需兼顾读写速度、可读性和后续分析需求:

方案 适合场景 写入速度 (10万条) 文件大小 可读性
CSV 简单表格、Excel可打开 ~0.8秒 较小
JSON 嵌套结构、API数据 ~1.2秒 中等
SQLite 复杂查询、多表关联 ~0.5秒 略大 ★★ (需工具)
Parquet 大数据分析、列式存储 ~0.3秒 最小 ★ (二进制)

选择建议

  • 如果后续用Excel分析 → CSV
  • 如果需保留原始API结构 → JSON
  • 如果要做SQL查询、去重、关联 → SQLite
  • 如果日采集量超过100万条 → Parquet

实战脚本示例:Python爬虫数据写入SQLite

以下是一个采集新闻标题并存储到本地的完整示例:

import sqlite3
import time
import requests
from bs4 import BeautifulSoup
# 1. 初始化数据库
def init_db():
    conn = sqlite3.connect('news_data.db')
    cursor = conn.cursor()
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS news (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            title TEXT NOT NULL,
            url TEXT UNIQUE,
            timestamp TEXT
        )
    ''')
    conn.commit()
    conn.close()
# 2. 采集数据并写入
def fetch_and_store():
    url = 'https://example.com/news'
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')s = soup.find_all('h2', class_='title')
    conn = sqlite3.connect('news_data.db')
    cursor = conn.cursor()
    for title in titles:
        title_text = title.get_text().strip()
        link = title.find('a')['href'] if title.find('a') else ''
        # 使用INSERT OR IGNORE避免重复URL
        cursor.execute('''
            INSERT OR IGNORE INTO news (title, url, timestamp)
            VALUES (?, ?, ?)
        ''', (title_text, link, time.strftime('%Y-%m-%d %H:%M:%S')))
    conn.commit()
    conn.close()
    print(f'成功写入 {len(titles)} 条数据')
# 3. 定时运行
if __name__ == '__main__':
    init_db()
    while True:
        fetch_and_store()
        time.sleep(300)  # 每5分钟采集一次

常见问题问答

Q1:写入中文时出现乱码怎么办? A:CSV/JSON文件需指定编码为utf-8-sig,Python中示例:open('data.csv', 'w', encoding='utf-8-sig'),SQLite默认支持UTF-8,无需额外设置。

Q2:如何实现增量写入,不重复插入相同数据? A:三种方式:

  1. 主键约束:如上述SQLite脚本的UNIQUE(url)字段
  2. 哈希校验:对数据内容计算MD5,存储前检查是否存在
  3. 时间戳标记:每次写入记录最后一条数据的ID,下次从该ID后继续

Q3:采集数据量太大,导致写入越来越慢怎么办? A:采取以下优化措施:

  • 批量写入:每1000条执行一次commit()(代替每行commit)
  • 使用WAL模式:SQLite设置PRAGMA journal_mode=WAL;可提升并发写入速度
  • 分文件存储:按日期分割文件,如data_2025-01-01.csv
  • 异步写入:使用concurrent.futuresasyncio实现非阻塞写入

Q4:多个脚本同时写入同一文件会冲突吗? A:会!CSV/JSON文件不支持并发写入,会出现数据覆盖或损坏,解决方案:

  • 锁定机制:使用filelock库(pip install filelock
  • 改用SQLite:原生支持多个进程并发读取,但写入需排队
  • 消息队列:将数据先写入Redis/本地队列,由单个消费者写入文件

防坑指南

  1. 路径绝对化:始终使用os.path.abspath()pathlib处理文件路径,避免脚本在非预期目录运行时报错。
  2. 异常重试:网络请求或写入失败时,重试3次并记录错误日志。
  3. 数据校验:写入前检查字段完整性(如标题不为空),避免无效数据污染存储。
  4. 定期维护:SQLite数据库每半年执行VACUUM指令回收空间;CSV文件定期归档旧数据。
  5. 安全性:如果采集包含个人信息的本地数据,建议使用SQLite的加密扩展(sqlcipher)对整个文件加密。

通过上述方案,你的脚本完全可以稳定运行数月甚至数年,无需依赖任何第三方云服务,真正做到“数据始终掌控在本地”。

抱歉,评论功能暂时关闭!