【Python】Flask

Flask Web开发实战:从入门到API集成

1. 最简单的Flask应用

python 复制代码
"""
Flask基础应用示例
功能:创建一个最简单的Hello World Flask应用
"""
from flask import Flask

# 创建Flask应用实例
app = Flask(__name__)

# 定义路由和处理函数
@app.route("/", methods=["GET"])
def hello():
    return "hello CS 41"

# 启动开发服务器
if __name__ == "__main__":
    app.run(debug=True, port=5000)

运行方式:

bash 复制代码
python app.py

2. 动态路由与API响应

python 复制代码
"""
猜数字游戏API
功能:实现一个猜数字的RESTful API
"""
from flask import Flask

app = Flask(__name__)

# 游戏配置
SECRET_NUMBER = 41

@app.route("/", methods=["GET"])
def hello():
    return "hello CS 41"

@app.route("/<guess>", methods=["GET"])
def guess_check(guess):
    """
    猜数字API接口
    参数: guess - 用户猜测的数字
    返回: JSON格式的响应
    """
    try:
        # 类型转换和安全检查
        guess = int(guess)
    except ValueError:
        return {"error": "Hey! Thats not a number"}
    
    # 构建响应数据
    output = {'correct': guess == SECRET_NUMBER}
    
    if guess < SECRET_NUMBER:
        output["message"] = "too low!"
    elif guess > SECRET_NUMBER:
        output["message"] = "too high"
    else:
        output["message"] = "congrats!!"
    
    return output

if __name__ == "__main__":
    app.run(debug=True, port=5000)

API使用示例:

bash 复制代码
# 访问正确的数字
curl http://localhost:5000/41

# 访问错误的数字
curl http://localhost:5000/30

# 访问非数字
curl http://localhost:5000/abc

3. 处理POST请求与模板渲染

3.1 服务器端代码(app.py

python 复制代码
"""
待办事项列表应用
功能:支持GET和POST请求,使用模板渲染HTML
"""
from flask import Flask, request, render_template

app = Flask(__name__)

# 全局存储(实际项目中应使用数据库)
items = []

@app.route("/", methods=["GET", "POST"])
def hello():
    """
    处理待办事项列表
    GET: 显示所有待办项
    POST: 添加新的待办项
    """
    if request.method == "POST":
        # 获取POST请求中的JSON数据
        data = request.get_json()
        
        # 验证数据格式
        if "to_add" in data:
            items.append(data["to_add"])
            return {"status": "success", "message": "Item added"}
        else:
            return {"error": "Missing 'to_add' field"}, 400
    
    # GET请求:渲染模板
    return render_template("list.html", items=items)

if __name__ == "__main__":
    app.run(debug=True, port=4000)

3.2 HTML模板(templates/list.html)

html 复制代码
<!--
待办事项列表页面
功能:显示所有待办项,支持动态更新
-->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>待办事项列表</title>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            max-width: 600px;
            margin: 50px auto;
            padding: 20px;
            background-color: #f5f5f5;
        }
        .container {
            background-color: white;
            border-radius: 10px;
            padding: 30px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        h1 {
            color: #333;
            border-bottom: 2px solid #4CAF50;
            padding-bottom: 10px;
        }
        ul {
            list-style-type: none;
            padding: 0;
        }
        li {
            background-color: #f8f9fa;
            margin: 10px 0;
            padding: 15px;
            border-radius: 5px;
            border-left: 5px solid #4CAF50;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .empty-state {
            text-align: center;
            color: #666;
            padding: 40px 20px;
        }
        .empty-state i {
            font-size: 48px;
            color: #ccc;
            margin-bottom: 20px;
        }
        .item-count {
            background-color: #4CAF50;
            color: white;
            padding: 5px 10px;
            border-radius: 20px;
            font-size: 0.9em;
        }
        .footer {
            margin-top: 30px;
            text-align: center;
            color: #888;
            font-size: 0.9em;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>待办事项列表 
            <span class="item-count">{{ items|length }} 项</span>
        </h1>
        
        {% if items %}
            <ul>
                {% for item in items %}
                    <li>
                        <span>{{ loop.index }}. {{ item }}</span>
                        <span>🕒 {{ now().strftime('%H:%M') }}</span>
                    </li>
                {% endfor %}
            </ul>
        {% else %}
            <div class="empty-state">
                <div>📝</div>
                <h3>暂无待办事项</h3>
                <p>使用客户端脚本添加你的第一个待办项</p>
            </div>
        {% endif %}
        
        <div class="footer">
            <p>使用Python客户端或Postman添加新项目</p>
            <p>POST请求格式: {"to_add": "任务内容"}</p>
        </div>
    </div>
    
    <script>
        // 自动刷新页面(每30秒)
        setTimeout(function() {
            location.reload();
        }, 30000);
    </script>
</body>
</html>

4. 客户端交互脚本

python 复制代码
"""
Flask应用客户端
功能:通过requests库与Flask服务器交互
"""
import requests
import json

class FlaskClient:
    def __init__(self, base_url="http://127.0.0.1:4000"):
        """
        初始化Flask客户端
        :param base_url: Flask服务器地址
        """
        self.base_url = base_url
    
    def add_item(self, item):
        """
        添加待办项到服务器
        :param item: 待办项内容
        :return: 服务器响应
        """
        try:
            response = requests.post(
                self.base_url,
                json={"to_add": item},
                headers={"Content-Type": "application/json"}
            )
            
            if response.status_code == 200:
                print(f"✅ 成功添加: {item}")
                return response.json()
            else:
                print(f"❌ 添加失败: {response.status_code}")
                print(f"响应: {response.text}")
                return None
                
        except requests.exceptions.ConnectionError:
            print("❌ 连接失败,请确保Flask服务器正在运行")
            return None
    
    def get_items(self):
        """
        获取所有待办项
        :return: HTML页面内容
        """
        try:
            response = requests.get(self.base_url)
            if response.status_code == 200:
                return response.text
            else:
                print(f"获取失败: {response.status_code}")
                return None
        except requests.exceptions.ConnectionError:
            print("❌ 连接失败")
            return None
    
    def interactive_mode(self):
        """交互式模式:持续添加待办项"""
        print("=" * 50)
        print("Flask待办事项客户端")
        print("=" * 50)
        print("输入待办事项内容(输入'quit'退出,输入'list'查看)")
        print("-" * 50)
        
        while True:
            user_input = input("📝 输入待办项: ").strip()
            
            if user_input.lower() == 'quit':
                print("👋 退出客户端")
                break
            elif user_input.lower() == 'list':
                html = self.get_items()
                if html:
                    print("📄 服务器返回的HTML(前500字符):")
                    print(html[:500])
            elif user_input:
                self.add_item(user_input)
            else:
                print("⚠️ 输入不能为空")

def main():
    """主函数:运行客户端"""
    # 创建客户端实例
    client = FlaskClient()
    
    # 测试单个添加
    print("测试单个添加...")
    client.add_item("学习Flask框架")
    
    # 进入交互模式
    client.interactive_mode()

if __name__ == "__main__":
    main()

5. 集成外部API:维基百科词云生成器

5.1 服务器端代码

python 复制代码
"""
维基百科词云生成器
功能:调用维基百科API获取内容,生成词云图片
"""
from flask import Flask, render_template
import requests 
from wordcloud import WordCloud
import io
import base64

app = Flask(__name__)

# 配置词云生成器
wc = WordCloud(
    background_color="white", 
    max_words=100, 
    colormap='plasma',
    width=1000,
    height=800,
    font_path="simhei.ttf"  # 中文字体
)

def get_wikipedia_content(topic):
    """
    获取维基百科页面内容
    :param topic: 主题关键词
    :return: 页面内容或错误信息
    """
    try:
        # 构建API请求URL
        api_url = "https://en.wikipedia.org/w/api.php"
        params = {
            "action": "query",
            "format": "json",
            "titles": topic,
            "prop": "extracts",
            "explaintext": True,
            "exintro": True  # 只获取引言部分
        }
        
        # 发送API请求
        response = requests.get(api_url, params=params, timeout=10)
        response.raise_for_status()
        
        # 解析响应数据
        data = response.json()
        pages = data.get("query", {}).get("pages", {})
        
        if not pages:
            return None, "未找到相关页面"
        
        # 获取第一个页面
        page_id, page_data = list(pages.items())[0]
        
        if page_id == -1:
            return None, "页面不存在"
        
        extract = page_data.get("extract", "")
        if not extract:
            return None, "页面内容为空"
        
        return extract, None
        
    except requests.exceptions.RequestException as e:
        return None, f"API请求失败: {str(e)}"
    except Exception as e:
        return None, f"处理失败: {str(e)}"

def generate_wordcloud_svg(text):
    """
    生成词云SVG图像
    :param text: 文本内容
    :return: SVG字符串
    """
    try:
        # 生成词云
        wordcloud = wc.generate(text)
        
        # 转换为SVG格式
        svg_bytes = wordcloud.to_svg()
        
        # 编码为base64(可选,更安全)
        # svg_base64 = base64.b64encode(svg_bytes).decode('utf-8')
        # return f'<img src="data:image/svg+xml;base64,{svg_base64}" alt="WordCloud">'
        
        return svg_bytes.decode('utf-8')
        
    except Exception as e:
        return f'<div style="color: red; padding: 20px;">生成词云失败: {str(e)}</div>'

@app.route("/")
def index():
    """首页:显示使用说明"""
    return """
    <!DOCTYPE html>
    <html>
    <head>
        <title>维基百科词云生成器</title>
        <style>
            body { font-family: Arial; max-width: 800px; margin: 50px auto; padding: 20px; }
            .container { background: #f8f9fa; padding: 30px; border-radius: 10px; }
            input { padding: 10px; width: 70%; margin-right: 10px; }
            button { padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; }
            .example { margin-top: 20px; color: #666; }
        </style>
    </head>
    <body>
        <div class="container">
            <h1>🌍 维基百科词云生成器</h1>
            <p>输入任何维基百科词条名称,生成对应的词云</p>
            <form action="/generate" method="GET">
                <input type="text" name="topic" placeholder="例如:Python, Machine Learning, Artificial Intelligence..." required>
                <button type="submit">生成词云</button>
            </form>
            <div class="example">
                <p>示例:</p>
                <a href="/Python">Python</a> | 
                <a href="/Artificial_intelligence">人工智能</a> | 
                <a href="/Machine_learning">机器学习</a>
            </div>
        </div>
    </body>
    </html>
    """

@app.route("/generate", methods=["GET"])
def generate_from_form():
    """从表单接收参数的词云生成"""
    topic = request.args.get("topic", "").strip()
    if not topic:
        return redirect("/")
    return redirect(f"/{topic}")

@app.route("/<wiki_slug>", methods=["GET"])
def generate_wordcloud(wiki_slug):
    """
    生成词云的主函数
    :param wiki_slug: 维基百科词条名称
    """
    # 获取维基百科内容
    content, error = get_wikipedia_content(wiki_slug)
    
    if error:
        return f"""
        <div style="padding: 50px; text-align: center;">
            <h2>😕 生成失败</h2>
            <p>{error}</p>
            <p><a href="/">返回首页</a></p>
        </div>
        """
    
    # 生成词云SVG
    svg_content = generate_wordcloud_svg(content)
    
    # 渲染模板
    return render_template("wordcloud.html", 
                         title=wiki_slug,
                         svg_content=svg_content,
                         content_preview=content[:500] + "...")

if __name__ == "__main__":
    app.run(debug=True, port=5000)

5.2 词云展示模板

html 复制代码
<!-- templates/wordcloud.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>词云生成结果 - {{ title }}</title>
    <style>
        body {
            font-family: 'Arial', sans-serif;
            margin: 0;
            padding: 20px;
            background-color: #f0f2f5;
        }
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background-color: white;
            border-radius: 10px;
            padding: 30px;
            box-shadow: 0 2px 20px rgba(0,0,0,0.1);
        }
        .header {
            text-align: center;
            margin-bottom: 30px;
            padding-bottom: 20px;
            border-bottom: 2px solid #eaeaea;
        }
        .header h1 {
            color: #333;
            margin-bottom: 10px;
        }
        .header .topic {
            font-size: 1.2em;
            color: #007bff;
            background-color: #e7f3ff;
            padding: 5px 15px;
            border-radius: 20px;
            display: inline-block;
        }
        .wordcloud-container {
            text-align: center;
            margin: 30px 0;
            padding: 20px;
            background-color: #f8f9fa;
            border-radius: 8px;
        }
        .content-preview {
            margin-top: 30px;
            padding: 20px;
            background-color: #f8f9fa;
            border-radius: 8px;
            line-height: 1.6;
        }
        .content-preview h3 {
            color: #555;
            margin-bottom: 15px;
        }
        .actions {
            text-align: center;
            margin-top: 30px;
            padding-top: 20px;
            border-top: 1px solid #eee;
        }
        .btn {
            display: inline-block;
            padding: 10px 25px;
            margin: 0 10px;
            background-color: #007bff;
            color: white;
            text-decoration: none;
            border-radius: 5px;
            transition: background-color 0.3s;
        }
        .btn:hover {
            background-color: #0056b3;
        }
        .btn-secondary {
            background-color: #6c757d;
        }
        .btn-secondary:hover {
            background-color: #545b62;
        }
        .stats {
            display: flex;
            justify-content: space-around;
            margin: 20px 0;
            padding: 15px;
            background-color: #f8f9fa;
            border-radius: 8px;
        }
        .stat-item {
            text-align: center;
        }
        .stat-value {
            font-size: 1.5em;
            font-weight: bold;
            color: #007bff;
        }
        .stat-label {
            font-size: 0.9em;
            color: #666;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>📊 词云生成结果</h1>
            <div class="topic">{{ title }}</div>
        </div>
        
        <div class="stats">
            <div class="stat-item">
                <div class="stat-value">{{ content_preview|length }}</div>
                <div class="stat-label">文本长度</div>
            </div>
            <div class="stat-item">
                <div class="stat-value">{{ content_preview.split()|length }}</div>
                <div class="stat-label">单词数量</div>
            </div>
            <div class="stat-item">
                <div class="stat-value">100</div>
                <div class="stat-label">显示词数</div>
            </div>
        </div>
        
        <div class="wordcloud-container">
            <h2>词云可视化</h2>
            <div style="display: inline-block; margin: 20px;">
                {{ svg_content|safe }}
            </div>
            <p style="color: #666; margin-top: 15px;">
                词云中词语的大小表示其在文本中出现的频率
            </p>
        </div>
        
        <div class="content-preview">
            <h3>📝 内容预览</h3>
            <p>{{ content_preview }}</p>
            <p style="color: #888; font-style: italic;">
                (以上内容来自维基百科,已截断显示前500字符)
            </p>
        </div>
        
        <div class="actions">
            <a href="/" class="btn">🏠 返回首页</a>
            <a href="https://en.wikipedia.org/wiki/{{ title }}" 
               target="_blank" 
               class="btn btn-secondary">
                🌐 查看完整维基百科页面
            </a>
            <button onclick="location.reload()" class="btn">🔄 重新生成</button>
        </div>
    </div>
</body>
</html>

6. 完整项目结构

复制代码
flask-demo-project/
├── app.py                    # 主Flask应用
├── client.py                 # 客户端脚本
├── requirements.txt          # 依赖包列表
├── README.md                 # 项目说明
├── templates/                # HTML模板目录
│   ├── list.html            # 待办事项列表页
│   ├── wordcloud.html       # 词云展示页
│   └── base.html            # 基础模板
├── static/                   # 静态文件
│   ├── css/
│   ├── js/
│   └── images/
└── docs/                    # 文档
    └── api.md               # API文档

requirements.txt

txt 复制代码
Flask==2.3.3
requests==2.31.0
wordcloud==1.9.2
matplotlib==3.7.2
numpy==1.24.3

README.md

markdown 复制代码
# Flask Web开发实战项目

## 项目简介
本示例项目展示了Flask Web开发的完整流程,涵盖以下功能:
1. 基础Flask应用
2. RESTful API设计
3. 模板渲染
4. 外部API集成
5. 客户端交互

## 快速开始

### 安装依赖
```bash
pip install -r requirements.txt

运行服务器

bash 复制代码
python app.py

运行客户端

bash 复制代码
python client.py

API文档

猜数字游戏

  • GET /<guess> - 猜测数字

待办事项

  • GET / - 查看所有待办项
  • POST / - 添加待办项

词云生成器

  • GET /<topic> - 生成维基百科词云


    7. 部署到生产环境

    python 复制代码
    """
    生产环境配置示例
    """
    from flask import Flask
    import os
    from dotenv import load_dotenv
    
    # 加载环境变量
    load_dotenv()
    
    app = Flask(__name__)
    
    # 生产环境配置
    class Config:
        SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-key-here')
        DEBUG = False
        HOST = '0.0.0.0'
        PORT = int(os.environ.get('PORT', 5000))
    
    app.config.from_object(Config)
    
    @app.route("/health")
    def health_check():
        """健康检查端点(用于生产环境监控)"""
        return {"status": "healthy", "service": "Flask Web App"}
    
    if __name__ == "__main__":
        # 生产环境使用Waitress或Gunicorn
        # pip install waitress
        from waitress import serve
        serve(app, host=app.config['HOST'], port=app.config['PORT'])
相关推荐
古城小栈16 小时前
Rust 并发、异步,碾碎它们
开发语言·后端·rust
Evand J16 小时前
【MATLAB代码介绍】【空地协同】UAV辅助的UGV协同定位,无人机辅助地面无人车定位,带滤波,MATLAB
开发语言·matlab·无人机·协同·路径·多机器人
sa1002716 小时前
基于Python的京东评论爬虫
开发语言·爬虫·python
foundbug99916 小时前
STFT在图像配准中的MATLAB实现
开发语言·matlab
ii_best16 小时前
安卓/ios脚本开发辅助工具按键精灵横纵坐标转换教程
android·开发语言·ios·安卓
Cigaretter716 小时前
Day 38 早停策略和模型权重的保存
python·深度学习·机器学习
a31582380616 小时前
Android 大图显示策略优化显示(二)
android·java·开发语言·javascript·kotlin·glide·图片加载
月明长歌16 小时前
Java多线程线程池ThreadPoolExecutor理解总结:6 个核心参数 + 4 种拒绝策略(附完整示例)
java·开发语言
sunywz16 小时前
【JVM】(2)java类加载机制
java·jvm·python