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

写爬虫不是 copy 一段 requests.get(),而是写出能自动重试、统一解析、多站适配、可扩展 的结构。今天,我们用 面向对象的思想,写一个迷你爬虫框架。


✅ 本文目标

  • 用类封装爬虫逻辑,做到高内聚低耦合
  • 支持多站点适配(抽象 + 子类继承)
  • 实现请求封装、解析模块、自动重试、通用日志
  • 最终支持:python crawl.py zhihupython 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 理论,它是你写出真正工程化爬虫系统的第一步。

相关推荐
Zane19941 分钟前
用了Optional,为什么NPE还是防不住?
java·后端
yunwei371 分钟前
eBPF 示例教程:实现 `scx_nest` 调度器
linux·后端·性能优化
薛定谔的算法7 分钟前
从 NestJS 到 Spring Boot:一次完整的 Node.js → Java 后端迁移实战
后端
Shinomiya7 分钟前
我最近在学 Linux 进程控制:fork、退出码与进程等待
后端
企业数字化笔记9 分钟前
固定资产Excel批量导入怎么防重复?资产编码、重复检查和错误回执
java·后端·excel
SamDeepThinking20 分钟前
Java 17内存屏障:为什么需要,怎么用
java·后端·面试
春涧草茶31 分钟前
慢就是快12-2三种访问权限|getter与setter|魔法方法
开发语言·python
夜雪一千1 小时前
如何使用Python做舆情分析
人工智能·python·数据分析
azhou的代码园1 小时前
景区游船预约服务系统
人工智能·spring boot·后端
小灰灰搞电子1 小时前
Rust Attribute(属性标记)完整整理
开发语言·后端·rust