12、用类写出更可控、更易扩展的爬虫框架🕷

写爬虫不是 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 ""

💡 拓展挑战

  1. 添加代理池支持
  2. 解析具体内容如:知乎热榜、掘金推荐文章列表
  3. 写一个通用 save() 方法导出为 Markdown 或 JSON

🧠 总结

面向对象不只是 OOP 理论,它是你写出真正工程化爬虫系统的第一步。

相关推荐
海绵宝宝转agent7 小时前
learn-claude-code第1-5章开源学习笔记分享
人工智能·笔记·python·学习
小奇不哭7 小时前
ROS2 单节点,RGB-D 深度相机局部路径提取 + B 样条平滑路径 + YOLOv8 障碍物检测 + 深度测距,用于移动机器人视觉局部循迹。
python·yolov8·ros2·cv2·路径探索循迹
小小龙学IT7 小时前
Python scikit-learn 机器学习库深度解析
python·机器学习·scikit-learn
2601_962071578 小时前
类变量和全局变量的查找路径有什么区别?
开发语言·python
卷无止境9 小时前
独立开发者的"富矿地带":哪些垂直领域值得你押注一辈子?
后端·python
Java后端的Ai之路9 小时前
Python进阶探索29_eval内置函数
开发语言·python·探索·eval·内置函数
计算机毕业编程指导师9 小时前
计算机毕设选题推荐:基于Hadoop与Spark的Steam游戏数据分析系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习 深度学习
大数据·hadoop·python·计算机·spark·毕业设计·steam游戏
计算机毕业编程指导师9 小时前
【计算机毕设选题推荐】基于Hadoop+Spark的白鹿抖音评论大数据分析与可视化系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习 深度学习
大数据·hadoop·python·计算机·spark·毕业设计·抖音评论
Zootopia6269 小时前
飞行力学知识梳理1|飞行性能与稳定性
人工智能·python·算法·机器学习·无人机·学习方法·信息与通信
Y3815326629 小时前
搜索 API 延迟优化:并发数、超时与超时的真实代价
python·搜索引擎