在當(dāng)今的數(shù)字時(shí)代,擁有一個(gè)屬于自己的網(wǎng)站已經(jīng)成為展示個(gè)人風(fēng)采和技術(shù)能力的重要方式。而通過(guò)Python搭建個(gè)人網(wǎng)站不僅可以快速實(shí)現(xiàn)這一目標(biāo),還能讓你更深入地了解Web開(kāi)發(fā)的過(guò)程和原理。本文將介紹如何使用Python來(lái)搭建一個(gè)簡(jiǎn)單的個(gè)人網(wǎng)站,并給出一些進(jìn)階建議。

準(zhǔn)備工作

在開(kāi)始搭建個(gè)人網(wǎng)站之前,你需要確保已經(jīng)安裝了以下工具和庫(kù):

  1. Python
  2. Flask:一個(gè)輕量級(jí)的Web框架
  3. Jinja2:用于模板渲染
  4. Markdown:用于編寫(xiě)內(nèi)容
  5. Pygments:為代碼高亮提供支持

你可以通過(guò)以下命令安裝這些庫(kù):

pip install flask jinja2 pygments

基本結(jié)構(gòu)

我們的目標(biāo)是創(chuàng)建一個(gè)能夠顯示博客文章的個(gè)人網(wǎng)站,因此需要以下幾個(gè)文件:

  • app.py:主程序文件
  • templates/:存放HTML模板的目錄
  • static/:存放靜態(tài)資源的目錄
  • posts/:存放博客文章的目錄

創(chuàng)建項(xiàng)目目錄

創(chuàng)建一個(gè)項(xiàng)目目錄并在其中初始化文件結(jié)構(gòu):

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

編寫(xiě)主程序

app.py文件中,編寫(xiě)Flask應(yīng)用的基本結(jié)構(gòu):

from flask import Flask, render_template, request, send_from_directory, abort
import os
import markdown
from pygments import highlight, lexers, formatters

# 初始化Flask應(yīng)用
app = Flask(__name__)

# 配置
app.config['TEMPLATES_AUTO_RELOAD'] = True
app.config['DEBUG'] = True
# 配置靜態(tài)文件路徑
app.config['UPLOAD_FOLDER'] = 'static'
# 配置文件上傳類(lèi)型限制
app.config['ALLOWED_EXTENSIONS'] = set(['png', 'jpg', 'jpeg', 'gif'])

# 路由與視圖函數(shù)
@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()

加載文章數(shù)據(jù)

我們需要從posts文件夾中加載文章數(shù)據(jù)。新建一個(gè)util.py文件來(lái)處理這一邏輯:

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  # 默認(rèn)標(biāo)題為文件名,不含后綴
template = None
try:
template = renderer(title)  # 嘗試獲取自定義模板,如果不存在則使用默認(rèn)模板
except TemplateNotFound:
template = renderer('post.html')  # 使用默認(rèn)模板
posts.append({'slug': slug, 'title': title, 'content': rendered, 'date': date, 'template': template})
return posts

def load_post_by_slug(slug):
"""根據(jù)文章的slug加載文章"""
for post in load_posts():
if post['slug'] == slug:
return post
return None

在上述代碼中,我們定義了兩個(gè)函數(shù):load_posts()用于加載所有文章,load_post_by_slug(slug)根據(jù)給定的slug加載特定文章。我們還使用了pygments來(lái)實(shí)現(xiàn)代碼高亮。

編寫(xiě)模板文件

templates文件夾中創(chuàng)建兩個(gè)模板文件: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>

這兩個(gè)模板分別用于主頁(yè)的文章列表展示和單篇文章的詳細(xì)展示。注意我們?cè)?code>post.html中使用了safe過(guò)濾器來(lái)確保Markdown解析后的內(nèi)容被正確顯示。

樣式文件與腳本文件

我們可以添加一些簡(jiǎn)單的樣式來(lái)美化我們的網(wǎng)站。在static目錄下創(chuàng)建一個(gè)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