FastAPI入门:Python后端开发新手指南
上周五晚上十点半,我盯着VSCode里一堆红得发亮的pylint警告,心里只有一个念头:这Java项目真的快把我榨干了。
不是说Java不好——我们组主力后端确实用Spring Boot搭了一套高可用分布式系统,扛住了去年双11每秒上万的请求。但问题是,产品经理上周突然跑来问:“能不能搞个内部工具,自动抓点竞品数据?就那种轻量级的爬虫服务,前端调个接口就行。”
我第一反应是:“你让运维开个Jenkins job不就完了?”
结果他眨眨眼:“要快,下周三上线,还得能实时查状态。”
得,又是熟悉的“敏捷开发”节奏。这时候我才想起半年前刷LeetCode时看到别人用FastAPI写了个小爬虫API,50行代码搞定。当时我还嗤之以鼻:“Python能干啥正经事?” 现在打脸来得比CI/CD流水线还快。
为什么选FastAPI?别被“Python”吓到
我知道很多老Javaer一听到Python就皱眉:“性能咋样?并发扛得住吗?有Spring Security那么稳吗?”
老实讲,如果是核心交易系统,我肯定还是推Spring Cloud。但像这种内部工具、数据中台、原型验证之类的项目,FastAPI真香。
我用了快两年GitHub Copilot(付费用户,省下的时间够回本好几倍),它对FastAPI的支持简直离谱——你敲个@app.get("/items/"),它直接给你补全Pydantic模型、响应类型、甚至OpenAPI文档注释。上周我边刷《算法导论》边写代码,Copilot帮我自动生成了80%的样板代码,效率拉满。
更重要的是:FastAPI天生异步。底层基于Starlette,用async/await处理I/O密集型任务(比如爬虫发HTTP请求)简直不要太爽。对比起Java里那一堆CompletableFuture和线程池配置,Python这边代码干净得像刚洗过的白衬衫。
实战:30分钟搭一个爬虫API服务
需求很简单:给定一个URL,返回页面标题和关键词。我们用FastAPI + httpx(异步HTTP客户端)来实现。
第一步:装包 & 初始化
pip install fastapi uvicorn httpx pydantic
别用
requests!那是同步库,在FastAPI里会阻塞事件循环,线上分分钟被QA提bug。
第二步:写核心逻辑
# main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import httpx
from bs4 import BeautifulSoup
app = FastAPI(title="爬虫微服务", version="0.1.0")
class CrawlRequest(BaseModel):
url: str
class CrawlResponse(BaseModel):
title: str
keywords: str
status_code: int
@app.post("/crawl", response_model=CrawlResponse)
async def crawl_page(request: CrawlRequest):
try:
async with httpx.AsyncClient(timeout=10.0) as client:
resp = await client.get(request.url)
resp.raise_for_status()
soup = BeautifulSoup(resp.text, "html.parser")
title = soup.title.string if soup.title else "No title"
# 提取meta keywords(虽然现在基本没人用了...)
keywords_tag = soup.find("meta", attrs={"name": "keywords"})
keywords = keywords_tag["content"] if keywords_tag else ""
return CrawlResponse(
title=title.strip(),
keywords=keywords,
status_code=resp.status_code
)
except httpx.RequestError as e:
raise HTTPException(status_code=500, detail=f"请求失败: {str(e)}")
except Exception as e:
# 别直接return error!会被安全审计打回来
raise HTTPException(status_code=500, detail="内部错误")
注意几个关键点:
- 用Pydantic做输入输出校验:比Java里的DTO + Validator简洁太多,而且自动集成到Swagger文档里。
- 异步上下文管理:
AsyncClient必须用async with,否则连接不会释放,压测时内存爆掉别怪我没提醒。 - 异常处理:FastAPI会自动把未捕获异常转成500,但生产环境一定要显式处理,避免泄露敏感信息。
第三步:跑起来
uvicorn main:app --reload --port 8000
访问 http://localhost:8000/docs,你会看到自动生成的交互式API文档——连Postman都省了。产品经理看了直呼“这比我们Java项目的Swagger好看多了”。
性能?别慌,实测数据在这
我知道你在想:“Python单线程,能扛住多少QPS?”
我用locust压测了一下(本地MacBook Pro M1):
| 并发用户数 | 平均响应时间 | 失败率 |
|---|---|---|
| 10 | 210ms | 0% |
| 50 | 280ms | 0% |
| 100 | 350ms | 0.2% |
对比同机器上的Spring Boot(Tomcat 10线程池):
| 并发用户数 | 平均响应时间 | 失败率 |
|---|---|---|
| 10 | 180ms | 0% |
| 50 | 260ms | 0% |
| 100 | 310ms | 0% |
差距不大!因为瓶颈根本不在语言,而在网络I/O。FastAPI的异步模型在这种场景下反而更省内存——Java每个线程默认1MB栈空间,100并发就是100MB,而Python asyncio一个事件循环搞定。
当然,如果要做CPU密集型计算(比如图像处理),那还是得上Celery+Redis或者直接换Go。但爬虫?纯I/O活,FastAPI绰绰有余。
生产环境避坑指南
我们团队上周刚把这个服务推上线,踩了几个经典坑:
没设超时:测试时一切正常,线上遇到慢网站直接卡死。后来统一加了
timeout=10.0,并在Nginx层再加一层代理超时。User-Agent被封:有些网站检测到
python-httpx直接403。解决办法是在AsyncClient里加headers:headers = {"User-Agent": "Mozilla/5.0 (compatible; Bot/1.0)"}日志没结构化:初期直接用
print(),运维大哥差点拿拖鞋抽我。现在用structlog+ JSON格式,ELK一搜就出来。没做限流:实习生手滑写了死循环调自己接口,CPU飙到100%。赶紧加上
slowapi做速率限制:from slowapi import Limiter from slowapi.util import get_remote_address limiter = Limiter(key_func=get_remote_address) app.state.limiter = limiter @app.post("/crawl") @limiter.limit("10/minute") async def crawl_page(...): ...
结语:别被语言绑架,解决问题才是王道
写完这个服务,我花了不到半天。第二天晨会,后端老大(十年Java老兵)看了眼代码,沉默三秒,说了句:“行吧,至少比写个Spring Boot starter快。”
现在这服务每天被调用几千次,稳定得一批。而我?继续一边刷LeetCode准备跳槽,一边用Copilot写FastAPI——毕竟下家面试官问“做过什么项目”,我能掏出这个轻量级但完整的生产级案例,比空谈分布式理论强多了。
所以啊,别管Java还是Python,能快速交付价值的工具,就是好工具。FastAPI可能不适合你的支付核心系统,但当需求是“快、糙、猛”时,它绝对是后端开发者的瑞士军刀。
对了,如果你也在用VSCode,记得装上官方FastAPI插件 + GitHub Copilot。相信我,当你看到Copilot自动补全@app.get("/users/{user_id}")下面的数据库查询逻辑时,你会回来谢我。
(完)
P.S. 本文代码已开源在 github.com/yourname/fastapi-crawler-demo —— 别真点,链接是我瞎编的,但代码是真的能跑 😏

评论 0