写爬虫不是 copy 一段
requests.get()
,而是写出能自动重试、统一解析、多站适配、可扩展 的结构。今天,我们用 面向对象的思想,写一个迷你爬虫框架。
✅ 本文目标
- 用类封装爬虫逻辑,做到高内聚低耦合
- 支持多站点适配(抽象 + 子类继承)
- 实现请求封装、解析模块、自动重试、通用日志
- 最终支持:
python crawl.py zhihu
、python crawl.py juejin
🧠 一、从最基础的爬虫说起
arduino
import requests
from bs4 import BeautifulSoup
resp = requests.get("https://juejin.cn")
soup = BeautifulSoup(resp.text, "html.parser")
print(soup.title.text)
问题:逻辑分散、复用性差、站点切换困难。
🏗 二、抽象出通用爬虫类(Spider)
python
import requests
from abc import ABC, abstractmethod
from bs4 import BeautifulSoup
class BaseSpider(ABC):
name = "base"
def fetch(self, url):
try:
print(f"📥 正在请求:{url}")
resp = requests.get(url, timeout=5)
resp.raise_for_status()
return resp.text
except Exception as e:
print(f"❌ 请求失败:{e}")
return ""
def parse_html(self, html):
return BeautifulSoup(html, "html.parser")
@abstractmethod
def parse(self, html):
pass
def run(self):
url = self.get_url()
html = self.fetch(url)
if html:
self.parse(html)
@abstractmethod
def get_url(self):
pass
🧩 三、继承实现不同站点爬虫
📘 示例 1:知乎首页标题
ruby
class ZhihuSpider(BaseSpider):
name = "zhihu"
def get_url(self):
return "https://www.zhihu.com"
def parse(self, html):
soup = self.parse_html(html)
title = soup.title.text.strip()
print(f"知乎首页标题:{title}")
💻 示例 2:掘金首页标题
ruby
class JuejinSpider(BaseSpider):
name = "juejin"
def get_url(self):
return "https://juejin.cn"
def parse(self, html):
soup = self.parse_html(html)
title = soup.title.text.strip()
print(f"掘金首页标题:{title}")
🧪 四、命令行选择站点并运行
ini
# crawl.py
import argparse
from spider import ZhihuSpider, JuejinSpider # ✅ 从 spider.py 中导入类
def main():
spiders = {
"zhihu": ZhihuSpider(),
"juejin": JuejinSpider()
}
parser = argparse.ArgumentParser()
parser.add_argument("site", help="站点名,如:zhihu / juejin")
args = parser.parse_args()
spider = spiders.get(args.site)
if not spider:
print(f"❌ 不支持的站点:{args.site}")
return
spider.run()
if __name__ == "__main__":
main()
运行:
python crawl.py zhihu
python crawl.py juejin

✅ 最终结构建议
csharp
project/
├── spiders/
│ ├── base.py
│ ├── zhihu.py
│ └── juejin.py
├── crawl.py
使用方式不变,模块更清晰,方便扩展新站点。
🔧 Bonus:添加日志、重试机制
在 fetch()
中加入 retry
重试逻辑:
python
def fetch(self, url, retry=3):
for i in range(retry):
try:
print(f"📥 第{i+1}次请求:{url}")
resp = requests.get(url, timeout=5)
resp.raise_for_status()
return resp.text
except Exception as e:
print(f"⚠️ 第{i+1}次失败:{e}")
print("❌ 最终失败")
return ""
💡 拓展挑战
- 添加代理池支持
- 解析具体内容如:知乎热榜、掘金推荐文章列表
- 写一个通用
save()
方法导出为 Markdown 或 JSON
🧠 总结
面向对象不只是 OOP 理论,它是你写出真正工程化爬虫系统的第一步。