1. 项目背景与核心需求
招聘信息采集是数据分析、市场调研和人才战略中不可或缺的一环。但传统爬虫方案存在两个致命缺陷:一是每次全量抓取既浪费带宽又增加被封风险;二是重复数据导致存储冗余和分析偏差。这正是我们需要构建支持增量更新与Hash去重的智能采集器的根本原因。
我在为某猎头公司搭建数据中台时,曾遇到一个典型案例:他们的爬虫每天抓取10万条招聘信息,但实际新增数据不足5%,95%的重复请求不仅拖慢系统,还频繁触发反爬机制。改用增量方案后,服务器负载降低83%,数据质量提升显著。
2. 技术架构设计
2.1 系统流程图解
plaintext复制[起始URL列表] → [爬取页面] → [内容解析] → [Hash计算]
↑ ↓
[URL去重库] ← [数据比对] → [CSV/SQLite存储]
2.2 核心组件选型
- 爬虫框架:选用Requests+BeautifulSoup组合而非Scrapy,更轻量且适合中小规模抓取
- 去重算法:MD5哈希(32位)与SimHash(64位)双校验机制
- 持久化方案:SQLite作为主存储,CSV作为中间交换格式
关键决策:放弃MySQL选择SQLite的原因在于,单文件数据库更适配爬虫项目的可移植性需求,且避免了数据库服务依赖。
3. 增量更新实现细节
3.1 时间窗口策略
python复制def need_update(last_time, current_time):
"""基于岗位更新时间判断是否需要采集"""
time_format = "%Y-%m-%d %H:%M:%S"
delta = datetime.strptime(current_time, time_format) - last_time
return delta.total_seconds() > 3600 # 1小时更新阈值
3.2 内容变更检测
采用分层哈希策略:
- 整体内容MD5校验(快速过滤完全相同的页面)
- 关键字段SimHash比对(识别部分修改)
python复制def calc_simhash(text):
"""计算关键字段的SimHash值"""
tokens = jieba.cut(text)
vec = [0] * 64
for token in tokens:
h = hashlib.md5(token.encode()).hexdigest()
h = int(h, 16)
for i in range(64):
vec[i] += 1 if h & (1 << i) else -1
return sum(1 << i for i in range(64) if vec[i] > 0)
4. 数据存储方案
4.1 SQLite优化技巧
python复制# 建表时启用WAL模式提升并发性能
conn.execute("PRAGMA journal_mode=WAL")
conn.execute("""
CREATE TABLE IF NOT EXISTS jobs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
url TEXT UNIQUE,
title TEXT,
company TEXT,
content_hash TEXT,
update_time TIMESTAMP,
raw_text TEXT
)""")
4.2 CSV导出注意事项
python复制def export_to_csv(data, filename):
"""处理中文编码和特殊字符问题"""
with open(filename, 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=data[0].keys())
writer.writeheader()
for row in data:
# 清洗换行符等特殊字符
cleaned = {k: v.replace('\n', ' ') if isinstance(v, str) else v
for k, v in row.items()}
writer.writerow(cleaned)
5. 反爬对抗实践
5.1 请求头伪装方案
python复制headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Referer': 'https://www.zhipin.com/',
'X-Forwarded-For': socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff)))
}
5.2 智能限流算法
python复制class RateLimiter:
def __init__(self, max_calls=30, period=60):
self.calls = deque(maxlen=max_calls)
self.period = period
def wait(self):
now = time.time()
if len(self.calls) >= self.calls.maxlen:
elapsed = now - self.calls[0]
if elapsed < self.period:
time.sleep(self.period - elapsed)
self.calls.append(now)
6. 实战踩坑记录
6.1 动态加载陷阱
某招聘网站采用异步加载技术,初始HTML中只有框架代码。解决方案:
python复制from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--headless")
driver = webdriver.Chrome(options=options)
driver.get(url)
time.sleep(2) # 等待动态加载
html = driver.page_source
6.2 哈希冲突处理
曾遇到不同公司同职位MD5相同的情况,改进方案:
- 增加公司名称作为哈希盐值
- 对薪资范围单独校验
python复制def safe_hash(text, salt=""):
return hashlib.md5((salt + text).encode()).hexdigest()
7. 性能优化指标
测试环境(4核8G服务器)下的基准数据:
| 指标 | 全量爬取 | 增量方案 | 提升幅度 |
|---|---|---|---|
| 日均请求量 | 12,000 | 1,800 | 85%↓ |
| 数据存储量(日) | 1.2GB | 150MB | 87.5%↓ |
| 去重准确率 | - | 99.3% | - |
| 反爬触发次数 | 23次/天 | 2次/天 | 91.3%↓ |
8. 扩展应用场景
本方案稍作改造即可适用于:
- 电商价格监控(自动识别价格变动)
- 新闻舆情追踪(发现内容更新)
- 房产信息聚合(过滤重复房源)
我曾将类似架构应用于二手房数据采集,通过设置"标题+面积+总价"联合哈希,成功将重复房源识别率从72%提升至98%。
