本文目录导读:

我来教你写一个长链接转短链接的脚本,提供几种常见的实现方式:
基于数据库的自增ID方案
Python实现
import hashlib
import string
import sqlite3
from datetime import datetime
class ShortURLGenerator:
def __init__(self, db_path='short_urls.db'):
self.conn = sqlite3.connect(db_path)
self.cursor = self.conn.cursor()
self.init_db()
def init_db(self):
self.cursor.execute('''
CREATE TABLE IF NOT EXISTS urls (
id INTEGER PRIMARY KEY AUTOINCREMENT,
long_url TEXT NOT NULL,
short_code TEXT UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
self.conn.commit()
def encode(self, num):
"""将数字转换为短码(62进制)"""
chars = string.ascii_letters + string.digits # a-z, A-Z, 0-9
if num == 0:
return chars[0]
short_code = []
while num > 0:
num, remainder = divmod(num, 62)
short_code.append(chars[remainder])
return ''.join(reversed(short_code))
def shorten(self, long_url):
"""生成短链接"""
# 检查是否已存在
self.cursor.execute('SELECT short_code FROM urls WHERE long_url = ?', (long_url,))
result = self.cursor.fetchone()
if result:
return f"http://short.url/{result[0]}"
# 插入新记录
self.cursor.execute('INSERT INTO urls (long_url) VALUES (?)', (long_url,))
self.conn.commit()
# 获取自增ID并转换
last_id = self.cursor.lastrowid
short_code = self.encode(last_id)
# 更新短码
self.cursor.execute('UPDATE urls SET short_code = ? WHERE id = ?', (short_code, last_id))
self.conn.commit()
return f"http://short.url/{short_code}"
def expand(self, short_url):
"""还原长链接"""
short_code = short_url.split('/')[-1]
self.cursor.execute('SELECT long_url FROM urls WHERE short_code = ?', (short_code,))
result = self.cursor.fetchone()
return result[0] if result else None
def close(self):
self.conn.close()
# 使用示例
if __name__ == "__main__":
generator = ShortURLGenerator()
# 生成短链接
long_url = "https://www.example.com/very/long/url/that/needs/to/be/shortened"
short_url = generator.shorten(long_url)
print(f"长链接: {long_url}")
print(f"短链接: {short_url}")
# 还原长链接
original_url = generator.expand(short_url)
print(f"还原: {original_url}")
generator.close()
基于哈希的短链接生成
import hashlib
import base64
class HashShortURLGenerator:
def __init__(self, length=6):
self.length = length
self.url_map = {}
self.collision_map = {}
def generate_hash(self, long_url, salt=""):
"""生成短哈希码"""
# 使用MD5生成哈希
hash_input = long_url + salt
md5_hash = hashlib.md5(hash_input.encode()).hexdigest()
# 取前length位作为短码
short_code = md5_hash[:self.length]
return short_code
def shorten(self, long_url):
"""生成短链接"""
short_code = self.generate_hash(long_url)
# 处理冲突
counter = 0
while short_code in self.url_map and self.url_map[short_code] != long_url:
counter += 1
short_code = self.generate_hash(long_url, str(counter))
self.url_map[short_code] = long_url
return f"http://short.url/{short_code}"
def expand(self, short_url):
"""还原长链接"""
short_code = short_url.split('/')[-1]
return self.url_map.get(short_code)
# 使用示例
hash_generator = HashShortURLGenerator()
long_url = "https://www.example.com/very/long/url"
short_url = hash_generator.shorten(long_url)
print(f"哈希短链接: {short_url}")
print(f"还原: {hash_generator.expand(short_url)}")
简单的命令行脚本
#!/usr/bin/env python3
import sys
import hashlib
import json
import os
class SimpleShortURL:
def __init__(self, data_file='short_urls.json'):
self.data_file = data_file
self.urls = self.load_data()
def load_data(self):
if os.path.exists(self.data_file):
with open(self.data_file, 'r') as f:
return json.load(f)
return {}
def save_data(self):
with open(self.data_file, 'w') as f:
json.dump(self.urls, f, indent=2)
def generate_short_code(self):
"""生成8位随机短码"""
import random
import string
chars = string.ascii_letters + string.digits
return ''.join(random.choice(chars) for _ in range(8))
def shorten(self, long_url):
# 检查是否已存在
for code, url in self.urls.items():
if url == long_url:
return code
# 生成新短码
short_code = self.generate_short_code()
while short_code in self.urls:
short_code = self.generate_short_code()
self.urls[short_code] = long_url
self.save_data()
return short_code
def expand(self, short_code):
return self.urls.get(short_code)
def main():
shortener = SimpleShortURL()
if len(sys.argv) < 2:
print("使用方法:")
print(f" {sys.argv[0]} shorten <长链接> - 生成短链接")
print(f" {sys.argv[0]} expand <短码> - 还原长链接")
return
command = sys.argv[1]
if command == "shorten" and len(sys.argv) >= 3:
long_url = sys.argv[2]
short_code = shortener.shorten(long_url)
print(f"短链接: http://short.url/{short_code}")
elif command == "expand" and len(sys.argv) >= 3:
short_code = sys.argv[2]
long_url = shortener.expand(short_code)
if long_url:
print(f"长链接: {long_url}")
else:
print("未找到对应的长链接")
else:
print("无效命令")
if __name__ == "__main__":
main()
API版本的短链接服务
# Flask版本的短链接服务API
from flask import Flask, request, jsonify, redirect
import hashlib
import string
from datetime import datetime
app = Flask(__name__)
# 内存存储(实际应用中应使用数据库)
url_store = {}
def generate_short_code(long_url, length=6):
"""生成短码"""
hash_input = f"{long_url}{datetime.now().timestamp()}"
md5_hash = hashlib.md5(hash_input.encode()).hexdigest()
# 确保唯一性
short_code = md5_hash[:length]
while short_code in url_store:
hash_input += "1"
md5_hash = hashlib.md5(hash_input.encode()).hexdigest()
short_code = md5_hash[:length]
return short_code
@app.route('/shorten', methods=['POST'])
def shorten_url():
"""生成短链接API"""
data = request.get_json()
if not data or 'url' not in data:
return jsonify({'error': '请提供url参数'}), 400
long_url = data['url']
# 检查是否已存在
for code, url in url_store.items():
if url == long_url:
return jsonify({
'short_url': f'/s/{code}',
'long_url': long_url
})
# 生成新短链接
short_code = generate_short_code(long_url)
url_store[short_code] = {
'long_url': long_url,
'created_at': datetime.now().isoformat(),
'clicks': 0
}
return jsonify({
'short_url': f'/s/{short_code}',
'long_url': long_url
})
@app.route('/s/<short_code>')
def redirect_to_url(short_code):
"""短链接重定向"""
url_data = url_store.get(short_code)
if url_data:
# 增加点击计数
url_data['clicks'] += 1
return redirect(url_data['long_url'])
return jsonify({'error': '短链接不存在'}), 404
@app.route('/info/<short_code>')
def get_url_info(short_code):
"""获取短链接信息"""
url_data = url_store.get(short_code)
if url_data:
return jsonify(url_data)
return jsonify({'error': '短链接不存在'}), 404
if __name__ == '__main__':
app.run(debug=True, port=5000)
使用方法
- 数据库版本:直接运行会创建SQLite数据库存储映射关系
- 哈希版本:简单的内存缓存,适合测试
- 命令行版本:
python short_url.py shorten "https://example.com/long-url" - API版本:启动Flask服务后,POST请求到
/shorten
选择哪种方案取决于你的具体需求:
- 生产环境推荐数据库版本,可持久化存储
- 简单使用推荐命令行版本
- 微服务推荐API版本