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

相关推荐
独泪了无痕43 分钟前
Spring Data Redis 快速上手
spring boot·redis·后端
wangchunyu1143 小时前
JAVA CompletableFuture异步编程实战
java·开发语言·python
2501_944521595 小时前
Immer 跨端三方库仓颉适配全流程
python·eclipse·django
信誓旦旦的程序猿5 小时前
【Python量化实战宝典 #26】止损与回撤控制手册:移动止损、最大回撤(Python 可跑)
python·1024程序员节·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
m0_639906945 小时前
Linux 操作系统入门:目录结构、服务排查常用命令、Shell 脚本基础
linux·运维·后端
2501_944521595 小时前
Deepmerge 跨端三方库仓颉适配全流程
java·python·eclipse·github
Patrick在香港5 小时前
同一行 strftime,两台机器跑出两种日期
python·datetime·时区·locale·日期处理
2601_967987375 小时前
用Python+OpenCV+YOLO写个游戏脚本:从自动瞄准到自动采集的保姆级教程
python·opencv·yolo·目标检测·游戏自动化
meiying88385 小时前
快递单号批量查询Python脚本:从手动到自动化的完整实现
开发语言·python·自动化
人工智能导论实践课5 小时前
【GUI桌面开发3】PyCharm配置外部工具
ide·python·pycharm