发布于2026-07-20 阅读(0)
扫一扫,手机访问
爬虫的断点续传功能,核心在于如何准确记录已抓取的URL,避免重复劳动。用SQLite来实现,比用文件记录的方式稳定得多,这背后涉及事务、并发控制和状态管理,并非简单的存储问题。下面拆解几个关键操作点,希望对你有帮助。
用纯文本或JSON存已抓取URL,乍一看确实简单,但并发写入时很容易出问题:丢数据、重复抓取,甚至文件损坏。SQLite自带事务和行级锁,INSERT OR IGNORE能天然防重,SELECT COUNT(*)查进度也快——这可不是过度设计,而是爬虫跑一两天后不崩溃的底线。
只存URL不够。断点续传依赖三个关键状态字段:url(主键)、status('pending'/'done'/'error')、updated_at(时间戳)。示例:
CREATE TABLE IF NOT EXISTS crawl_queue ( url TEXT PRIMARY KEY, status TEXT NOT NULL DEFAULT 'pending', updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
要是漏掉PRIMARY KEY,重复插入就直接失败;没DEFAULT 'pending',新URL状态为空,后续WHERE status = 'pending'查不到;时间戳不设默认值,就无法判断哪批URL是上一次中断前插入的。
不能“先请求再入库”,否则程序崩在中间,这个URL就永远卡在“未记录”状态,下次启动直接重抓。正确顺序是:
立即学习“Python免费学习笔记(深入)”;
status = 'pending'的URLUPDATE crawl_queue SET status = 'pending', updated_at = CURRENT_TIMESTAMP WHERE url = ?抢占式标记(避免多进程抢同一URL)UPDATE ... SET status = 'done',失败则SET status = 'error'注意:UPDATE必须带WHERE url = ?且用参数化查询,否则可能误标其他URL;updated_at每次更新都要重置,方便按时间排查卡住的任务。
别用SELECT * FROM crawl_queue WHERE status != 'done'当待抓队列——如果某URL状态是'error',你可能还想重试,但直接过滤掉就丢了。更稳妥的做法是:
UPDATE crawl_queue SET status = 'pending' WHERE status = 'error' AND updated_at < datetime('now', '-1 hour')(给错误项1小时冷却)status = 'pending'的URLif row['status'] == 'done': continue,而不是靠SQL过滤很多人忽略updated_at的时间条件,导致网络超时的错误任务被无限重试,压垮目标站点。
实际跑起来后,最麻烦的不是SQL怎么写,而是网络IO和数据库写入速度不匹配——加个time.sleep(0.1)比优化SQL更能防止被封,而SQLite的WAL模式开启与否,直接影响并发读写时的锁等待时间。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8