当前位置: 首页 > java >正文

Python爬虫去重策略:增量爬取与历史数据比对

1. 引言

在数据采集过程中,爬虫经常需要面对 重复数据 的问题。如果每次爬取都全量抓取,不仅浪费资源,还可能导致数据冗余。增量爬取(Incremental Crawling) 是一种高效策略,它仅抓取 新增或更新 的数据,而跳过已采集的旧数据。

本文将详细介绍 Python爬虫的增量爬取与历史数据比对 策略,涵盖以下内容:

  1. 增量爬取的核心思路
  2. 去重方案对比(数据库、文件、内存)
  3. 基于时间戳、哈希、数据库比对的实现方法
  4. 完整代码示例(Scrapy + MySQL 增量爬取)

2. 增量爬取的核心思路

增量爬取的核心是 识别哪些数据是新的或已更新的,通常采用以下方式:

  • 基于时间戳(Last-Modified / Update-Time)
  • 基于内容哈希(MD5/SHA1)
  • 基于数据库比对(MySQL/Redis/MongoDB)

2.1 基于时间戳的增量爬取

适用于数据源带有 发布时间(如新闻、博客) 的场景:

  1. 记录上次爬取的 最新时间戳
  2. 下次爬取时,只抓取 晚于该时间戳的数据

优点:简单高效,适用于结构化数据
缺点:依赖数据源的时间字段,不适用于无时间戳的网页

2.2 基于内容哈希的去重

适用于 内容可能更新但URL不变 的页面(如电商价格):

  1. 计算页面内容的 哈希值(如MD5)
  2. 比对哈希值,若变化则视为更新

优点:适用于动态内容
缺点:计算开销较大

2.3 基于数据库比对的增量爬取

适用于 大规模数据管理

  1. 将已爬取的 URL 或关键字段 存入数据库(MySQL/Redis)
  2. 每次爬取前查询数据库,判断是否已存在

优点:支持分布式去重
缺点:需要额外存储

3. 去重方案对比

方案适用场景优点缺点
内存去重单机小规模爬虫速度快(**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">set()</font>**
重启后数据丢失
文件存储中小规模爬虫简单(CSV/JSON)性能较低
SQL数据库结构化数据管理支持复杂查询(MySQL)需要数据库维护
NoSQL数据库高并发分布式爬虫高性能(Redis/MongoDB)内存占用较高

4. 增量爬取实现方法

4.1 基于时间戳的增量爬取(示例)

import scrapy
from datetime import datetimeclass NewsSpider(scrapy.Spider):name = "news_spider"last_crawl_time = None  # 上次爬取的最新时间def start_requests(self):# 从文件/DB加载上次爬取时间self.last_crawl_time = self.load_last_crawl_time()# 设置代理信息proxy = "http://www.16yun.cn:5445"proxy_auth = "16QMSOML:280651"# 添加代理到请求中yield scrapy.Request(url="https://news.example.com/latest",meta={'proxy': proxy,'proxy_user_pass': proxy_auth})def parse(self, response):# 检查响应状态码,判断是否成功获取数据if response.status != 200:self.logger.error(f"Failed to fetch data from {response.url}. Status code: {response.status}")self.logger.error("This might be due to network issues or an invalid URL. Please check the URL and try again.")returnfor article in response.css(".article"):pub_time = datetime.strptime(article.css(".time::text").get(), "%Y-%m-%d %H:%M:%S")if self.last_crawl_time and pub_time <= self.last_crawl_time:continue  # 跳过旧文章yield {"title": article.css("h2::text").get(),"time": pub_time,}# 更新最新爬取时间self.save_last_crawl_time(datetime.now())def load_last_crawl_time(self):try:with open("last_crawl.txt", "r") as f:return datetime.strptime(f.read(), "%Y-%m-%d %H:%M:%S")except FileNotFoundError:return Nonedef save_last_crawl_time(self, time):with open("last_crawl.txt", "w") as f:f.write(time.strftime("%Y-%m-%d %H:%M:%S"))

4.2 基于内容哈希的去重(示例)

import hashlibclass ContentHashSpider(scrapy.Spider):name = "hash_spider"seen_hashes = set()  # 存储已爬取的哈希def parse(self, response):content = response.css("body").get()content_hash = hashlib.md5(content.encode()).hexdigest()if content_hash in self.seen_hashes:return  # 跳过重复内容self.seen_hashes.add(content_hash)yield {"url": response.url, "content": content}

4.3 基于MySQL的增量爬取(完整示例)

(1)MySQL 表结构
CREATE TABLE crawled_data (id INT AUTO_INCREMENT PRIMARY KEY,url VARCHAR(255) UNIQUE,content_hash CHAR(32),last_updated TIMESTAMP
);
(2)Scrapy 爬虫代码
import pymysql
import hashlib
from scrapy import Spider, Requestclass MySQLIncrementalSpider(Spider):name = "mysql_incremental"start_urls = ["https://example.com"]def __init__(self):self.conn = pymysql.connect(host="localhost",user="root",password="123456",db="crawler_db")self.cursor = self.conn.cursor()def parse(self, response):url = response.urlcontent = response.textcontent_hash = hashlib.md5(content.encode()).hexdigest()# 检查是否已爬取self.cursor.execute("SELECT content_hash FROM crawled_data WHERE url=%s",(url,))result = self.cursor.fetchone()if result and result[0] == content_hash:return  # 内容未更新# 插入或更新数据库self.cursor.execute("""INSERT INTO crawled_data (url, content_hash, last_updated)VALUES (%s, %s, NOW())ON DUPLICATE KEY UPDATE content_hash=%s, last_updated=NOW()""",(url, content_hash, content_hash))self.conn.commit()yield {"url": url, "content": content}def close(self, reason):self.cursor.close()self.conn.close()

5. 结论

策略适用场景推荐存储方案
时间戳比对新闻、博客等带时间的数据文件/MySQL
内容哈希动态内容(如商品价格)Redis/内存
数据库去重结构化数据管理MySQL/MongoDB

最佳实践

  • 小型爬虫 → 内存去重(**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">set()</font>**
  • 中型爬虫 → 文件存储(JSON/CSV)
  • 大型分布式爬虫 → Redis + MySQL

通过合理选择增量爬取策略,可以显著提升爬虫效率,减少资源浪费。

http://www.xdnf.cn/news/1714.html

相关文章:

  • VulnHub-DC-2靶机渗透教程
  • zip是 Python 中 `zip` 函数的一个用法
  • 数模学习:一,层次分析法
  • flutter 小知识
  • 在Ubuntu 18.04 和 ROS Melodic 上编译 UFOMap
  • 跨浏览器音频录制:实现兼容的音频捕获与WAV格式生成
  • Spring Security认证流程
  • LabVIEW实现Voronoi图绘制功能
  • 【MQ篇】初识RabbitMQ保证消息可靠性
  • 信息系统项目管理工程师备考计算类真题讲解七
  • KMS工作原理及其安全性分析
  • Java Agent 注入 WebSocket 篇
  • java方法引用
  • kotlin和MVVM的结合使用总结(二)
  • 一种Spark程序运行指标的采集与任务诊断实现方式
  • CE第二次作业
  • NODE_OPTIONS=--openssl-legacy-provider vue-cli-service serve
  • Git 的基本概念和使用方式
  • C++跨平台开发要点
  • Spring AI 核心概念
  • 【Linux】网络基础和socket
  • HGDB安全版单机修改用户密码
  • spring-ai使用Document存储至milvus的数据结构
  • dockercompose文件仓库
  • [Java]动态代理
  • CSS基础
  • Ubuntu系统下交叉编译iperf3
  • 项目管理:企业战略落地的引擎与未来竞争力的核心密码
  • 力扣面试150题--基本计算器
  • 如何将极狐GitLab 合并请求导出为 CSV?