🐸 青蛙编程网
首页 / Python / 爬虫 / 6. feapder

6. feapder

这是什么:feapder(读作 "F-eapder",feapder = fast · easy · async · practical · durable · redis)是国产开源爬虫框架,最大卖点是分布式开箱即用:单机版不需要任何中间件,接上 Redis 就变成分布式集群——同一套代码,从笔记本平滑搬到多台服务器。

为什么学它:Scrapy 想做分布式要额外拼 scrapy-redis、自己管队列;feapder 把「分布式」做成了换一个类名的事,还内置了任务去重、失败重试、监控告警(对接钉钉/飞书/企业微信),国内业务型爬虫团队用得很多。

如何用:认识四种爬虫模板 → 用 AirSpider 跑通单机版 → 理解它和 Scrapy 的分工。

装包

pip install feapder

四种爬虫模板:按规模选

模板 类 依赖 适用场景
轻量 Air 爬虫 feapder.AirSpider 无(单机) 中小规模,学习和单机项目首选
分布式爬虫 feapder.Spider Redis 大规模、多机、需要断点续爬
批次爬虫 feapder.BatchSpider Redis 按天/按批次的周期采集(增量更新)
任务爬虫 feapder.TaskSpider Redis 任务由外部下发(如从数据库取待抓列表)

一句话:学习和小项目用 AirSpider,量大上 Spider,周期任务上 BatchSpider。模板间代码结构几乎一致,升级只换继承的类。

AirSpider 跑通第一个爬虫

存成 feapder_demo.py 运行:

import feapder


class QuoteSpider(feapder.AirSpider):
    def start_requests(self):
        # 起点:yield 几个 Request,就爬几个页面
        yield feapder.Request("https://quotes.toscrape.com/")


    def parse(self, request, response):
        for quote in response.css("div.quote"):
            text = quote.css("span.text::text").get_first()
            author = quote.css("small.author::text").get_first()
            print(f"{author}:{text[:40]}...")
        print(f"完成:{request.url}")


if __name__ == "__main__":
    QuoteSpider().start()

你会看到:多线程并发抓取的日志刷屏,页面数据打印出来——feapder 默认开多线程,这是它和 Scrapy(默认 twisted 异步)气质不同的地方:直观、好调试。

代码结构和 Scrapy 神似:

Scrapy feapder 说明
start_urls 列表 start_requests() 里 yield feapder.Request 起点入口,逻辑可以更灵活
parse(self, response) parse(self, request, response) 多了个 request,可回读请求参数
response.css(...).get() response.css(...).get_first() 同一套选择器语法,方法名不同
框架命令行跑 类自己 .start() 就是个普通 Python 程序,右键运行/断点调试都行

翻页同样是「解析里再 yield 新 Request」:

def parse(self, request, response):
    next_page = response.css("li.next a::attr(href)").get_first()
    if next_page:
        yield feapder.Request(request.urljoin(next_page), callback=self.parse)

数据落库:yield Item 进管道

和 Scrapy 的 Item/Pipeline 思路一样,feapder 里把数据 yield feapder.Item(...),由框架统一送进存储管道;配置好数据库后还能自动建表入库(MySQL / MongoDB / ES 均支持)。入门阶段先用最朴素的方式接住数据——在 parse 里直接写文件:

def parse(self, request, response):
    rows = []
    for quote in response.css("div.quote"):
        rows.append({
            "text": quote.css("span.text::text").get_first(),
            "author": quote.css("small.author::text").get_first(),
        })
    import json
    with open("feapder_quotes.json", "a", encoding="utf-8") as f:
        f.write(json.dumps(rows, ensure_ascii=False) + "\n")

正式项目再把存储搬进 Item 管道,业务代码保持干净。

上 Redis:单机变分布式

这是 feapder 的招牌时刻——把 AirSpider 改成 Spider,配一个 Redis 地址,任务队列就从「本机内存」搬进「Redis」:

import feapder


class QuoteSpider(feapder.Spider):
    # 分布式配置(本机起了 Redis 就能体验多进程协作)
    __custom_setting__ = {
        "REDISDB_IP_PORTS": "127.0.0.1:6379",
        "REDISDB_USER_PASS": "",
        "REDISDB_DB": 0,
    }


    def start_requests(self):
        yield feapder.Request("https://quotes.toscrape.com/")


    def parse(self, request, response):
        print(f"{request.url} 抓完了")

之后多台机器跑同一个类,任务自动分片、互不重复、谁挂了任务自动回收——你不需要写一行分布式代码。去重(防重复抓取)和断点续爬也随 Redis 队列自动获得。

常见翻车现场

症状 原因 修复
get() 取不到值报错 feapder 的取值方法是 get_first() / get_all() 别混用 parsel 的 get()/getall()
Spider 启动连不上 Redis Spider 模板必须配 Redis 没装 Redis 就先用 AirSpider
日志太多看不清数据 feapder 日志默认详细 按官方文档调低日志级别
Windows 下多线程卡住 终端与编码/防火墙偶发问题 加 if __name__ == "__main__" 入口(本来就该加)

动手改

  1. 给 start_requests 一次性 yield 第 1~10 页的 URL(提示:循环 1 到 10),和翻页写法对比
  2. 把 QuoteSpider(feapder.AirSpider) 改成 feapder.Spider 并装个 Redis 体验分布式配置(没有 Redis 就跳过,读懂区别即可)
  3. 在 parse 里统计每个标签(a.tag)出现次数,跑完打印 Top 5

上一章:Scrapy · 下一章:Crawlee 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。