下载地址:https://www.pan38.com/dow/share.php?code=JCnzE 提取密码:6714
就是可以通过代码实现小红书卡片的效果,这个办法非常的稳定,主要问题是因为小红书没有公开的接口,所以只能通过我们以下的python的方式操作实现。
import tkinter as tk
from tkinter import ttk, messagebox
import webbrowser
import json
import os
import random
from PIL import Image, ImageTk
import urllib.request
import io
class XiaohongshuCardGenerator:
def init(self, root):
self.root = root
self.root.title("小红书私信卡片生成器 v1.0")
self.root.geometry("800x600")
self.root.resizable(True, True)
# 初始化变量
self.card_data = {
"title": "",
"content": "",
"image_url": "",
"button_text": "点击跳转",
"link_url": "",
"theme": "default",
"card_style": "style1"
}
# 创建UI
self.create_widgets()
self.load_themes()
def create_widgets(self):
# 顶部标题
header = ttk.Frame(self.root)
header.pack(fill=tk.X, padx=10, pady=10)
ttk.Label(header, text="小红书私信卡片生成器", font=("Arial", 16, "bold")).pack(side=tk.LEFT)
# 主内容区域
main_frame = ttk.Frame(self.root)
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
# 左侧表单区域
form_frame = ttk.Frame(main_frame)
form_frame.pack(side=tk.LEFT, fill=tk.Y, padx=5, pady=5)
# 卡片标题
ttk.Label(form_frame, text="卡片标题:").grid(row=0, column=0, sticky=tk.W, pady=5)
self.title_entry = ttk.Entry(form_frame, width=30)
self.title_entry.grid(row=0, column=1, sticky=tk.W, pady=5)
# 卡片内容
ttk.Label(form_frame, text="卡片内容:").grid(row=1, column=0, sticky=tk.W, pady=5)
self.content_text = tk.Text(form_frame, width=30, height=5)
self.content_text.grid(row=1, column=1, sticky=tk.W, pady=5)
# 图片URL
ttk.Label(form_frame, text="图片URL:").grid(row=2, column=0, sticky=tk.W, pady=5)
self.image_entry = ttk.Entry(form_frame, width=30)
self.image_entry.grid(row=2, column=1, sticky=tk.W, pady=5)
ttk.Button(form_frame, text="随机图片", command=self.get_random_image).grid(row=2, column=2, padx=5)
# 按钮文字
ttk.Label(form_frame, text="按钮文字:").grid(row=3, column=0, sticky=tk.W, pady=5)
self.button_entry = ttk.Entry(form_frame, width=30)
self.button_entry.insert(0, "点击跳转")
self.button_entry.grid(row=3, column=1, sticky=tk.W, pady=5)
# 跳转链接
ttk.Label(form_frame, text="跳转链接:").grid(row=4, column=0, sticky=tk.W, pady=5)
self.link_entry = ttk.Entry(form_frame, width=30)
self.link_entry.grid(row=4, column=1, sticky=tk.W, pady=5)
# 主题选择
ttk.Label(form_frame, text="主题:").grid(row=5, column=0, sticky=tk.W, pady=5)
self.theme_var = tk.StringVar()
self.theme_combobox = ttk.Combobox(form_frame, textvariable=self.theme_var, width=27)
self.theme_combobox.grid(row=5, column=1, sticky=tk.W, pady=5)
# 卡片样式
ttk.Label(form_frame, text="卡片样式:").grid(row=6, column=0, sticky=tk.W, pady=5)
self.style_var = tk.StringVar()
self.style_combobox = ttk.Combobox(form_frame, textvariable=self.style_var,
values=["style1", "style2", "style3"], width=27)
self.style_combobox.set("style1")
self.style_combobox.grid(row=6, column=1, sticky=tk.W, pady=5)
# 操作按钮
button_frame = ttk.Frame(form_frame)
button_frame.grid(row=7, column=0, columnspan=2, pady=10)
ttk.Button(button_frame, text="生成卡片", command=self.generate_card).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="复制代码", command=self.copy_code).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="保存配置", command=self.save_config).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="加载配置", command=self.load_config).pack(side=tk.LEFT, padx=5)
# 右侧预览区域
preview_frame = ttk.Frame(main_frame)
preview_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5)
ttk.Label(preview_frame, text="卡片预览:", font=("Arial", 12)).pack(anchor=tk.NW)
self.preview_canvas = tk.Canvas(preview_frame, bg="white", width=400, height=400)
self.preview_canvas.pack(fill=tk.BOTH, expand=True, pady=5)
# 底部代码区域
code_frame = ttk.Frame(self.root)
code_frame.pack(fill=tk.BOTH, padx=10, pady=5)
ttk.Label(code_frame, text="生成的HTML代码:", font=("Arial", 12)).pack(anchor=tk.NW)
self.code_text = tk.Text(code_frame, width=80, height=8, font=("Consolas", 10))
self.code_text.pack(fill=tk.BOTH, expand=True)
def load_themes(self):
themes = ["default", "pink", "blue", "green", "purple"]
self.theme_combobox["values"] = themes
self.theme_combobox.set("default")
def get_random_image(self):
width = random.randint(300, 800)
height = random.randint(200, 600)
url = f"https://picsum.photos/{width}/{height}"
self.image_entry.delete(0, tk.END)
self.image_entry.insert(0, url)
def update_preview(self):
self.preview_canvas.delete("all")
# 绘制卡片背景
card_width = 350
card_height = 250
x = (400 - card_width) / 2
y = (400 - card_height) / 2
# 根据主题设置颜色
if self.card_data["theme"] == "pink":
bg_color = "#ffebee"
text_color = "#d81b60"
button_color = "#f06292"
elif self.card_data["theme"] == "blue":
bg_color = "#e3f2fd"
text_color = "#1565c0"
button_color = "#64b5f6"
elif self.card_data["theme"] == "green":
bg_color = "#e8f5e9"
text_color = "#2e7d32"
button_color = "#81c784"
elif self.card_data["theme"] == "purple":
bg_color = "#f3e5f5"
text_color = "#7b1fa2"
button_color = "#ba68c8"
else: # default
bg_color = "#f5f5f5"
text_color = "#212121"
button_color = "#9e9e9e"
# 绘制卡片
self.preview_canvas.create_rectangle(x, y, x+card_width, y+card_height,
fill=bg_color, outline="#e0e0e0", width=2)
# 绘制图片
if self.card_data["image_url"]:
try:
with urllib.request.urlopen(self.card_data["image_url"]) as url:
image_data = url.read()
image = Image.open(io.BytesIO(image_data))
image.thumbnail((200, 120))
photo = ImageTk.PhotoImage(image)
self.preview_canvas.image = photo # 保持引用
img_x = x + (card_width - image.width) / 2
self.preview_canvas.create_image(img_x, y+10, anchor=tk.NW, image=photo)
except:
self.preview_canvas.create_text(x+card_width/2, y+70,
text="图片加载失败", fill="red")
# 绘制标题
self.preview_canvas.create_text(x+card_width/2, y+140,
text=self.card_data["title"],
fill=text_color, font=("Arial", 14, "bold"))
# 绘制内容
self.preview_canvas.create_text(x+card_width/2, y+170,
text=self.card_data["content"],
fill=text_color, font=("Arial", 10), width=card_width-20)
# 绘制按钮
button_width = 100
button_height = 30
button_x = x + (card_width - button_width) / 2
button_y = y + card_height - button_height - 15
self.preview_canvas.create_rectangle(button_x, button_y,
button_x+button_width, button_y+button_height,
fill=button_color, outline=button_color)
self.preview_canvas.create_text(button_x+button_width/2, button_y+button_height/2,
text=self.card_data["button_text"],
fill="white", font=("Arial", 10, "bold"))
def generate_card(self):
# 获取表单数据
self.card_data["title"] = self.title_entry.get()
self.card_data["content"] = self.content_text.get("1.0", tk.END).strip()
self.card_data["image_url"] = self.image_entry.get()
self.card_data["button_text"] = self.button_entry.get()
self.card_data["link_url"] = self.link_entry.get()
self.card_data["theme"] = self.theme_var.get()
self.card_data["card_style"] = self.style_var.get()
# 验证必填字段
if not self.card_data["title"] or not self.card_data["link_url"]:
messagebox.showerror("错误", "标题和跳转链接是必填项")
return
# 更新预览
self.update_preview()
# 生成HTML代码
html_code = self.generate_html_code()
self.code_text.delete("1.0", tk.END)
self.code_text.insert("1.0", html_code)
def generate_html_code(self):
# 根据主题设置CSS
if self.card_data["theme"] == "pink":
css = """
.xh-card {
background-color: #ffebee;
color: #d81b60;
border: 1px solid #f8bbd0;
}
.xh-btn {
background-color: #f06292;
color: white;
}
"""
elif self.card_data["theme"] == "blue":
css = """
.xh-card {
background-color: #e3f2fd;
color: #1565c0;
border: 1px solid #bbdefb;
}
.xh-btn {
background-color: #64b5f6;
color: white;
}
"""
elif self.card_data["theme"] == "green":
css = """
.xh-card {
background-color: #e8f5e9;
color: #2e7d32;
border: 1px solid #c8e6c9;
}
.xh-btn {
background-color: #81c784;
color: white;
}
"""
elif self.card_data["theme"] == "purple":
css = """
.xh-card {
background-color: #f3e5f5;
color: #7b1fa2;
border: 1px solid #e1bee7;
}
.xh-btn {
background-color: #ba68c8;
color: white;
}
"""
else: # default
css = """
.xh-card {
background-color: #f5f5f5;
color: #212121;
border: 1px solid #e0e0e0;
}
.xh-btn {
background-color: #9e9e9e;
color: white;
}
"""
# 根据样式设置卡片布局
if self.card_data["card_style"] == "style1":
card_html = f"""
<div class="xh-card" style="width: 350px; padding: 20px; border-radius: 10px; margin: 20px auto; text-align: center; box-shadow: 0 4px 8px rgba(0,0,0,0.1);">
<img src="{self.card_data['image_url']}" alt="卡片图片" style="max-width: 100%; height: auto; border-radius: 5px; margin-bottom: 15px;">
<h3 style="margin: 10px 0;">{self.card_data['title']}</h3>
<p style="margin: 10px 0; font-size: 14px;">{self.card_data['content']}</p>
<a href="{self.card_data['link_url']}" class="xh-btn" style="display: inline-block; padding: 8px 20px; border-radius: 5px; text-decoration: none; margin-top: 15px; font-weight: bold;">{self.card_data['button_text']}</a>
</div>
"""
elif self.card_data["card_style"] == "style2":
card_html = f"""
<div class="xh-card" style="width: 350px; padding: 0; border-radius: 10px; margin: 20px auto; overflow: hidden; box-shadow: 0 4px 8px rgba(0,0,0,0.1);">
<img src="{self.card_data['image_url']}" alt="卡片图片" style="width: 100%; height: 150px; object-fit: cover;">
<div style="padding: 15px;">
<h3 style="margin: 10px 0;">{self.card_data['title']}</h3>
<p style="margin: 10px 0; font-size: 14px;">{self.card_data['content']}</p>
<a href="{self.card_data['link_url']}" class="xh-btn" style="display: inline-block; padding: 8px 20px; border-radius: 5px; text-decoration: none; margin-top: 10px; font-weight: bold;">{self.card_data['button_text']}</a>
</div>
</div>
"""
else: # style3
card_html = f"""
<div class="xh-card" style="width: 350px; padding: 20px; border-radius: 10px; margin: 20px auto; text-align: left; box-shadow: 0 4px 8px rgba(0,0,0,0.1); display: flex; flex-direction: column;">
<div style="display: flex; margin-bottom: 15px;">
<img src="{self.card_data['image_url']}" alt="卡片图片" style="width: 80px; height: 80px; border-radius: 5px; object-fit: cover; margin-right: 15px;">
<div>
<h3 style="margin: 0 0 5px 0;">{self.card_data['title']}</h3>
<p style="margin: 0; font-size: 14px; color: #666;">{self.card_data['content']}</p>
</div>
</div>
<a href="{self.card_data['link_url']}" class="xh-btn" style="align-self: flex-end; padding: 8px 20px; border-radius: 5px; text-decoration: none; font-weight: bold;">{self.card_data['button_text']}</a>
</div>
"""
# 完整HTML代码
html = f"""
<!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>
{css}
body {
{
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
background-color: #fafafa;
padding: 20px;
}}
</style>
</head>
<body>
{card_html}
</body>
</html>
"""
return html.strip()
def copy_code(self):
code = self.code_text.get("1.0", tk.END)
if code.strip():
self.root.clipboard_clear()
self.root.clipboard_append(code)
messagebox.showinfo("成功", "代码已复制到剪贴板")
else:
messagebox.showerror("错误", "没有可复制的代码")
def save_config(self实现