爬虫的断点续传功能,核心在于如何准确记录已抓取的URL,避免重复劳动。用SQLite来实现,比用文件记录的方式稳定得多,这背后涉及事务、并发控制和状态管理,并非简单的存储问题。下面拆解几个关键操作点,希望对你有帮助。

为什么直接用文件记录URL续传容易出错

用纯文本或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是上一次中断前插入的。

每次请求前必须先标记为 pending

不能“先请求再入库”,否则程序崩在中间,这个URL就永远卡在“未记录”状态,下次启动直接重抓。正确顺序是:

立即学习“Python免费学习笔记(深入)”;

注意:UPDATE必须带WHERE url = ?且用参数化查询,否则可能误标其他URL;updated_at每次更新都要重置,方便按时间排查卡住的任务。

重启时如何安全跳过已抓取内容

别用SELECT * FROM crawl_queue WHERE status != 'done'当待抓队列——如果某URL状态是'error',你可能还想重试,但直接过滤掉就丢了。更稳妥的做法是:

很多人忽略updated_at的时间条件,导致网络超时的错误任务被无限重试,压垮目标站点。

实际跑起来后,最麻烦的不是SQL怎么写,而是网络IO和数据库写入速度不匹配——加个time.sleep(0.1)比优化SQL更能防止被封,而SQLite的WAL模式开启与否,直接影响并发读写时的锁等待时间。

本文转载于:https://www.php.cn/faq/2324031.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。