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

从单机到分布式:Python 爬虫架构演进

目录

第 一 章:单机爬虫起点与局限

1. 目标与读者

2. 环境准备

3. 最小可用爬虫(MVP)

4. 抗脆弱:重试、超时、随机 UA、礼貌抓取

5. 三种解析方式:CSS / XPath / 正则

6. 持久化:CSV / SQLite / MongoDB(示例:CSV)

7. 单机并发入门:ThreadPoolExecutor + 限速

8. 合规与风控清单(单机阶段必须养成的习惯)

9. 小结

10. 练习与思考题

第 二 章:框架化爬虫——Scrapy 提升工程化能力

1. 为什么需要框架?

2. Scrapy 的核心架构

3. Scrapy 快速上手

4. 编写第一个 Spider

5. Item Pipeline:数据清洗与存储

6. Middleware:请求增强

7. Scrapy 的优势与不足

8. 小结

第 三 章:异步与高并发——打破 I/O 瓶颈

1. Python 异步生态

2. 为什么异步适合爬虫?

3. aiohttp 爬虫示例

4. 异步爬虫的优缺点

5. 应用场景

第 四 章:分布式爬虫——从单机到集群的飞跃

1. 分布式爬虫的核心挑战

2. 基于消息队列的分布式方案

3. Scrapy-Redis:工程化分布式改造

4. Funboost:通用分布式任务调度

5. 分布式爬虫的存储与扩展

6. 适用场景

第 五 章:反爬对抗与智能化——攻守之间的演进

1. 常见反爬手段

2. 常见应对策略

3. 智能化与自动化趋势

4. 示例:破解字体反爬的 Python 逻辑

5. 适用场景与演进趋势

总结


第 一 章:单机爬虫起点与局限

1. 目标与读者

  • 目标:写出稳定、可维护的单机爬虫;建立“工程化”的基础(日志、重试、限速、持久化)。

  • 适合谁:已会 Python 基础语法,想把“脚本”升级为“靠谱工具”的同学。

2. 环境准备

  • Python ≥ 3.9

  • 推荐库:requests, beautifulsoup4, lxml, tenacity(重试), loguru(日志,可选)

pip install requests beautifulsoup4 lxml tenacity loguru

3. 最小可用爬虫(MVP)

import requests
from bs4 import BeautifulSoupresp = requests.get("https://example.com", timeout=10)
resp.raise_for_status()
soup = BeautifulSoup(resp.text, "lxml")
print(soup.title.get_text(strip=True))

要点:务必设置 timeout;用 raise_for_status() 让异常显式暴露。

4. 抗脆弱:重试、超时、随机 UA、礼貌抓取

import random, time
import requests
from tenacity import retry, stop_after_attempt, wait_exponentialUAS = ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/118 Safari/537.36","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Version/15.5 Safari/605.1.15",
]@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=8))
def fetch(url: str) -> str:headers = {"User-Agent": random.choice(UAS)}r = requests.get(url, headers=headers, timeout=10)r.raise_for_status()# 礼貌:简单限速,避免打爆网站time.sleep(random.uniform(0.5, 1.5))return r.text

要点:指数退避(wait_exponential)对临时性错误(429/5xx)更友好;加入随机延迟随机 UA

5. 三种解析方式:CSS / XPath / 正则

from bs4 import BeautifulSoup
from lxml import etree
import rehtml = fetch("https://example.com")# 1) CSS(BS4)
soup = BeautifulSoup(html, "lxml")
title_css = soup.select_one("title").get_text(strip=True)# 2) XPath(lxml)
dom = etree.HTML(html)
title_xpath = dom.xpath("string(//title)")# 3) 正则(兜底方案,不推荐首选)
match = re.search(r"<title>(.*?)</title>", html, flags=re.I|re.S)
title_re = match.group(1).strip() if match else Noneprint(title_css, title_xpath, title_re)

建议:优先 CSS/XPath;正则仅作兜底或局部抽取。

6. 持久化:CSV / SQLite / MongoDB(示例:CSV)

import csv, pathlib
from datetime import datetimeOUTPUT = pathlib.Path("data.csv")def save_csv(rows):exists = OUTPUT.exists()with OUTPUT.open("a", newline="", encoding="utf-8") as f:w = csv.DictWriter(f, fieldnames=["url", "title", "ts"])if not exists:w.writeheader()for r in rows:w.writerow(r)rows = [{"url": "https://example.com","title": title_css,"ts": datetime.utcnow().isoformat(),
}]
save_csv(rows)

要点:统一字段;保存 UTC 时间;文件追加写入并自动建表头。

7. 单机并发入门:ThreadPoolExecutor + 限速

from concurrent.futures import ThreadPoolExecutor, as_completed
from urllib.parse import urljoinBASE = "https://example.com/"
PATHS = ["/", "#", "/?page=2", "/about"]  # 示例路径
URLS = [urljoin(BASE, p) for p in PATHS]def parse_title(url: str) -> dict:html = fetch(url)soup = BeautifulSoup(html, "lxml")return {"url": url, "title": soup.title.get_text(strip=True)}results = []
with ThreadPoolExecutor(max_workers=8) as pool:futs = [pool.submit(parse_title, u) for u in URLS]for fut in as_completed(futs):try:data = fut.result()results.append({**data, "ts": datetime.utcnow().isoformat()})except Exception as e:print("error:", e)save_csv(results)

建议

  • 网络 IO 密集任务,ThreadPoolExecutor 在单机就能显著加速。

  • 结合 重试 + 随机延迟 + 最大并发控制,平衡速度与合规。

8. 合规与风控清单(单机阶段必须养成的习惯)

  • 尊重 robots.txt 与站点 ToS;必要时联系站点管理员取得授权。

  • 限速与并发:设定全局 QPS/并发阈值;避免在敏感时段突发大量请求。

  • 指纹收敛

    • 合理的 User-AgentAccept-Language

    • 避免固定 ORDER 的请求序列与固定延时;

  • 隐私与合规:避免采集个人敏感信息;遵循本地与目标站点司法辖区法律法规。

  • 缓存策略:能缓存就缓存,减少对目标站点的重复压力。

9. 小结

  • 单机阶段的关键是 稳定性与可维护性:日志、重试、限速、持久化。

  • 先把“一个站点、一个功能”打磨到,再考虑堆并发、上分布式。

  • 下一篇将进入 Scrapy:用框架把这些“好习惯”收敛为可复用的工程化能力。

10. 练习与思考题

  1. 将示例扩展为“抓取多页文章列表 + 详情页解析 + 写入 CSV”。

  2. fetch() 增加 HTTP 代理会话级 Cookie 支持。

  3. 设计一个速率限制器:同一域名每秒最多 2 个请求,并记录被 429/503 拒绝时的退避策略。

  4. 把 CSV 改为 SQLite,比较两者在增量更新时的优劣。

http://www.dtcms.com/a/357903.html

相关文章:

  • kmp 算法
  • 【MLLM】多模态理解Ovis2.5模型架构和训练流程
  • 模式组合应用-组合模式
  • 加速智能经济发展:如何助力“人工智能+”战略在实时视频领域的落地
  • 时间轴组件开发:实现灵活的时间范围选择
  • More Effective C++ 条款17: 考虑使用缓式评估(Consider Using Lazy Evaluation)
  • centos7.9的openssh漏洞修复脚本
  • 软考 系统架构设计师系列知识点之杂项集萃(137)
  • 响应式编程框架Reactor【5】
  • PostgreSQL表空间(Tablespace)作用(管理数据库对象的存储位置)(pg_default、pg_global)
  • STL库——list(类模拟实现)
  • 将LLM模型“钉”在电路板上:用电阻矩阵实现物理推理引擎
  • Nacos-3.0.3 适配PostgreSQL数据库
  • openGauss笔记
  • rabbitMQ延时队列实现,怎么保证消息的幂等
  • HTML 核心元素实战:超链接、iframe 框架与 form 表单全面解析
  • 【WDG协议栈】AUTOSAR架构下WDG模块软硬件功能详解
  • 基于单片机指纹考勤系统/智能考勤
  • ⸢ 叁 ⸥ ⤳ 默认安全:概述与建设思路
  • 【Day 33】Linux-MySQL 备份与恢复详解
  • 从分子工具到技术革新:链霉亲和素 - 生物素系统与 M13 噬菌体展示的交叉应用解析
  • 针对 “TCP 数据传输机制” 的攻击
  • vue2下拉菜单
  • 服务器托管多少钱一年?服务器托管收费标准
  • C++day2作业
  • TuringComplete游戏攻略(2.2存储器)
  • 【C++】类和对象(终章)
  • 数值分析——误差的来源与分类、误差的基本概念(绝对误差、相对误差、有效数字)
  • 世界模型的典型框架与分类
  • react性能优化有哪些