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 理论,它是你写出真正工程化爬虫系统的第一步。

相关推荐
ai小鬼头11 分钟前
AIStarter最新版怎么卸载AI项目?一键删除操作指南(附路径设置技巧)
前端·后端·github
Touper.17 分钟前
SpringBoot -- 自动配置原理
java·spring boot·后端
思则变1 小时前
[Pytest] [Part 2]增加 log功能
开发语言·python·pytest
一只叫煤球的猫1 小时前
普通程序员,从开发到管理岗,为什么我越升职越痛苦?
前端·后端·全栈
一只鹿鹿鹿1 小时前
信息化项目验收,软件工程评审和检查表单
大数据·人工智能·后端·智慧城市·软件工程
漫谈网络1 小时前
WebSocket 在前后端的完整使用流程
javascript·python·websocket
专注VB编程开发20年1 小时前
开机自动后台运行,在Windows服务中托管ASP.NET Core
windows·后端·asp.net
程序员岳焱1 小时前
Java 与 MySQL 性能优化:MySQL全文检索查询优化实践
后端·mysql·性能优化
一只叫煤球的猫2 小时前
手撕@Transactional!别再问事务为什么失效了!Spring-tx源码全面解析!
后端·spring·面试
旷世奇才李先生2 小时前
Ruby 安装使用教程
开发语言·后端·ruby