在当今的数字时代,拥有一个属于自己的网站已经成为展示个人风采和技术能力的重要方式。而通过Python搭建个人网站不仅可以快速实现这一目标,还能让你更深入地了解Web开发的过程和原理。本文将介绍如何使用Python来搭建一个简单的个人网站,并给出一些进阶建议。

准备工作

在开始搭建个人网站之前,你需要确保已经安装了以下工具和库:

  1. Python
  2. Flask:一个轻量级的Web框架
  3. Jinja2:用于模板渲染
  4. Markdown:用于编写内容
  5. Pygments:为代码高亮提供支持

你可以通过以下命令安装这些库:

pip install flask jinja2 pygments  

基本结构

我们的目标是创建一个能够显示博客文章的个人网站,因此需要以下几个文件:

  • app.py:主程序文件
  • templates/:存放HTML模板的目录
  • static/:存放静态资源的目录
  • posts/:存放博客文章的目录

创建项目目录

创建一个项目目录并在其中初始化文件结构:

mkdir mywebsite  
cd mywebsite  
touch app.py  
mkdir templates static posts  

编写主程序

app.py文件中,编写Flask应用的基本结构:

from flask import Flask, render_template, request, send_from_directory, abort  
import os  
import markdown  
from pygments import highlight, lexers, formatters  
  
# 初始化Flask应用  
app = Flask(__name__)  
  
# 配置  
app.config['TEMPLATES_AUTO_RELOAD'] = True  
app.config['DEBUG'] = True  
# 配置静态文件路径  
app.config['UPLOAD_FOLDER'] = 'static'  
# 配置文件上传类型限制  
app.config['ALLOWED_EXTENSIONS'] = set(['png', 'jpg', 'jpeg', 'gif'])  
  
# 路由与视图函数  
@app.route('/')  
def index():  
posts = load_posts()  
return render_template('index.html', posts=posts)  
  
@app.route('/post/<slug>')  
def post(slug):  
post = load_post_by_slug(slug)  
if not post:  
abort(404)  
post['content'] = markdown.markdown(post['content'])  
return render_template('post.html', post=post)  
  
@app.route('/upload', methods=['POST'])  
def upload_file():  
file = request.files['file']  
if file and allowed_file(file.filename):  
filename = secure_filename(file.filename)  
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)  
file.save(filepath)  
return 'File uploaded successfully'  
else:  
return 'Invalid file or no file provided'  
  
@app.route('/static/<path:filename>')  
def get_static_file(filename):  
try:  
return send_from_directory(app.config['UPLOAD_FOLDER'], filename)  
except FileNotFoundError:  
abort(404)  
  
if __name__ == '__main__':  
app.run()  

加载文章数据

我们需要从posts文件夹中加载文章数据。新建一个util.py文件来处理这一逻辑:

import os  
from datetime import datetime  
import yaml  
from markdown import markdown as md_renderer  # 引入markdown模块的markdown方法  
from pygments import highlight, lexers, formatters  # 引入Pygments模块的highlight方法、lexers(词法分析器)和formatters(格式化器)  
from jinja2 import TemplateNotFound  
  
def load_posts(folder='posts'):  
"""加载所有文章"""  
posts = []  
for filename in sorted(os.listdir(folder), reverse=True):  
if filename.endswith('.md'):  
with open(os.path.join(folder, filename), encoding='utf-8') as f:  
content = f.read()  
rendered = md_renderer(content, extensions=['markdown.extensions.codehilite'])  
date = datetime.now()  
slug = filename[:-3]  # 去掉后缀".md"  
title = filename  # 默认标题为文件名,不含后缀  
template = None  
try:  
template = renderer(title)  # 尝试获取自定义模板,如果不存在则使用默认模板  
except TemplateNotFound:  
template = renderer('post.html')  # 使用默认模板  
posts.append({'slug': slug, 'title': title, 'content': rendered, 'date': date, 'template': template})  
return posts  
  
def load_post_by_slug(slug):  
"""根据文章的slug加载文章"""  
for post in load_posts():  
if post['slug'] == slug:  
return post  
return None  

在上述代码中,我们定义了两个函数:load_posts()用于加载所有文章,load_post_by_slug(slug)根据给定的slug加载特定文章。我们还使用了pygments来实现代码高亮。

编写模板文件

templates文件夹中创建两个模板文件:index.htmlpost.html

index.html

<!DOCTYPE html>  
<html lang="en">  
<head>  
<meta charset="UTF-8">  
<meta name="viewport" content="width=device-width, initial-scale=1.0">  
<title>My Blog</title>  
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">  
</head>  
<body>  
<header>  
<h1>My Blog</h1>  
</header>  
<main>  
{% for post in posts %}  
<article>  
<h2><a href="{{ url_for('post', slug=post.slug) }}">{{ post.title }}</a></h2>  
<p>{{ post.content|truncate(200) }}</p>  
<a href="{{ url_for('post', slug=post.slug) }}">Read More...</a>  
</article>  
{% endfor %}  
</main>  
</body>  
</html>  

post.html

<!DOCTYPE html>  
<html lang="en">  
<head>  
<meta charset="UTF-8">  
<meta name="viewport" content="width=device-width, initial-scale=1.0">  
<title>{{ post.title }} - My Blog</title>  
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">  
</head>  
<body>  
<header>  
<h1>{{ post.title }}</h1>  
</header>  
<div class="post">{{ post.content | safe }}</div>  
</body>  
</html>  

这两个模板分别用于主页的文章列表展示和单篇文章的详细展示。注意我们在post.html中使用了safe过滤器来确保Markdown解析后的内容被正确显示。

样式文件与脚本文件

我们可以添加一些简单的样式来美化我们的网站。在static目录下创建一个style.css文件:
”`css
body {
font-family: Arial, sans-serif;
line-height: 1.6;
margin: 0;
padding: 0;
background: #f4f4f4;
}
header {
background: #333;
color: white;
padding: 10px 0;
text-align: center;
}
main {
padding: 20px;
}
article {
margin-bottom: 20px;
background: white;
padding: 20px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
a {
color: #333;
text-decoration: none;} a:hover {color:#56a7e8; text-decoration : underline;} .post {word-wrap: break-word;} header{background:linear-gradient(to right,#4facfe 0%,#06466b 100