使用DeepSeek+本地知识库,尝试从0到1搭建高度定制化工作流(自动化篇)
7.5. 配图生成
-
目的:由于小红书发布文章要求图文格式,因此在生成文案的基础上,我们还需要生成图文搭配文案进行发布。
-
原实现思路:
起初我打算使用deepseek的文生图模型Janus进行本地部署生成,参考博客:Deepseek发布的Janus-Pro-1B初体验但后来尝试使用后发现Janus现阶段对于这类特定任务的生成图还不太能够胜任。以下是我尝试使用文案让Janus生成的图片:
-
现实现思路:
- 当下普遍的方案是使用文案生成一段相关的html代码,再使用python中的自动化库来进行相应部分的截图,最后将截图与文案进行组合,形成图文格式。
-
代码实现:
-
html生成:
''' Author: yeffky Date: 2025-02-14 08:43:28 LastEditTime: 2025-02-15 19:28:28 ''' import requests import json import os from datetime import datetime def build_prompt(drafts):prompt = "根据下面的小红书文案,帮我生成一个html页面,包含小红书的封面(需要一个卡片状的封面,上面只需文案内容即可,需要吸引眼球),以及下方几个要点内容,要点内容和封面我希望制作成卡片形式,并且每一部分的div请为我附上属性id,id为'card1', 'card2', ...。要求符合小红书平台的图文要求规则以及平替风格,还要符合小红书平台的用户审美。回复只要给出代码即可,请不要添加多余表达" return f"""{prompt} \n\n小红书文案:\n\n{drafts}"""def get_deepseek_response(prompt, api_key):url = "https://api.deepseek.com/chat/completions"headers = {"Authorization": f"Bearer {api_key}",'Content-Type': 'application/json','Accept': 'application/json',}payload = json.dumps({"messages": [{"content": prompt,"role": "user"}],"model": "deepseek-reasoner","frequency_penalty": 0,"max_tokens": 2048,"presence_penalty": 0,"response_format": {"type": "text"},"stop": None,"stream": False,"stream_options": None,"temperature": 1,"top_p": 1,"tools": None,"tool_choice": "none","logprobs": False,"top_logprobs": None})response = Nonewhile not response:try:print("发送请求")response = requests.post(url, data=payload, headers=headers, timeout=200)response.raise_for_status()if not response.json():response = Noneexcept requests.exceptions.RequestException as e:print(f"请求失败:{str(e)},开始重试...")response = Nonereturn response.json()['choices'][0]['message']['content']def generate_html():api_key = os.getenv("DEEPSEEK_API_KEY")today = datetime.now().strftime("%Y-%m-%d")file_path = "./xiaohongshu_drafts/小红书_推广文案_千战系列" + today +".txt"drafts = open(file_path, "r", encoding="utf-8").read()prompt = build_prompt(drafts=drafts)response = get_deepseek_response(prompt, api_key)print(response)with open('./pic_generate/pic.html', 'w', encoding='utf-8') as f:f.write(response) -
截图:
''' Author: yeffky Date: 2025-02-14 09:41:09 LastEditTime: 2025-02-15 10:44:51 ''' from playwright.sync_api import sync_playwright import time import redef generate_pic(url):# 启动浏览器player = sync_playwright().start() # 初始化Playwright并启动chrome_driver = player.chromium # 获取Chromium浏览器实例browser = chrome_driver.launch(headless=False) # 启动浏览器,headless=False表示以非无头模式启动,即显示浏览器窗口context = browser.new_context() # 创建一个新的浏览器上下文(类似于一个新的浏览器窗口)page = context.new_page() # 在该上下文中创建一个新的页面(标签页)# 访问页面card_cnt = 0with(open('./pic_generate/pic.html', 'r', encoding='utf-8')) as f:page_content = f.read()card_cnt = len(re.findall(r'<div class="card" id="card\d+">', page_content))print(card_cnt)page.goto(url) # 导航到指定的URL# 截取相关卡片的截图for i in range(1, card_cnt + 1):card_pic = page.query_selector(f"id=card{i}") # 使用CSS选择器查找页面中的搜索按钮元素card_pic.screenshot(path=f"./pictures/card{i}.png") # 对搜索按钮元素进行截图并保存为b.png# 停止访问context.close() # 关闭浏览器上下文browser.close() # 关闭浏览器player.stop() # 停止Playwrightif __name__ == '__main__':url = 'D:/Project/UUCrawl/Code/pic_generate/pic.html'generate_pic(url)
-
7.6. 自动化发布
- 目的:将生成的图片和文案自动发布到小红书
- 实现思路:
- 1.使用python中的selenium库,模拟页面操作,登陆后需要将cookie保存下来,下次使用时直接读取cookie,避免重复登陆。同时保存一份token,每次调用登录时检查token是否过期,如未过期则无需登录操作。
- 2.登录后,模拟页面操作前往发布页面,使用send_keys()方法输入标题和正文,使用click()方法点击发布按钮。
- 参考开源项目:xhs_ai_publisher
- 代码实现:
'''
Author: yeffky
Date: 2025-02-15 20:28:32
LastEditTime: 2025-02-17 14:08:45
'''
import sys
sys.path.append("./")
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
from utils import line_process
import time
import json
import osclass XiaohongshuClient:def __init__(self):self.driver = webdriver.Chrome()self.wait = WebDriverWait(self.driver, 10)# 获取当前执行文件所在目录current_dir = os.path.dirname(os.path.abspath(__file__))self.token_file = os.path.join(current_dir, "xiaohongshu_token.json")self.cookies_file = os.path.join(current_dir, "xiaohongshu_cookies.json")self.token = self._load_token()self._load_cookies()def _load_token(self):"""从文件加载token"""if os.path.exists(self.token_file):try:with open(self.token_file, 'r') as f:token_data = json.load(f)# 检查token是否过期if token_data.get('expire_time', 0) > time.time():return token_data.get('token')except:passreturn Nonedef _save_token(self, token):"""保存token到文件"""token_data = {'token': token,# token有效期设为30天'expire_time': time.time() + 30 * 24 * 3600}with open(self.token_file, 'w') as f:json.dump(token_data, f)def _load_cookies(self):"""从文件加载cookies"""if os.path.exists(self.cookies_file):try:with open(self.cookies_file, 'r') as f:cookies = json.load(f)self.driver.get("https://creator.xiaohongshu.com")for cookie in cookies:self.driver.add_cookie(cookie)except:passdef _save_cookies(self):"""保存cookies到文件"""cookies = self.driver.get_cookies()with open(self.cookies_file, 'w') as f:json.dump(cookies, f)def login(self, phone, country_code="+86"):"""登录小红书"""# 如果token有效则直接返回if self.token:return# 尝试加载cookies进行登录self.driver.get("https://creator.xiaohongshu.com/login")self._load_cookies()self.driver.refresh()time.sleep(3)# 检查是否已经登录if self.driver.current_url != "https://creator.xiaohongshu.com/login":print("使用cookies登录成功")self.token = self._load_token()self._save_cookies()time.sleep(2)returnelse:# 清理无效的cookiesself.driver.delete_all_cookies()print("无效的cookies,已清理")# 如果cookies登录失败,则进行手动登录self.driver.get("https://creator.xiaohongshu.com/login")# 等待登录页面加载完成time.sleep(5)# 点击国家区号输入框country_input = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "input[placeholder='请选择选项']")))country_input.click()time.sleep(5)# 等待区号列表出现并点击+886# 等待区号列表出现并点击+86try:self.driver.find_element(By.XPATH, "/html/body/div[1]/div/div/div/div[2]/div[1]/div[2]/div/div/div/div/div/div[2]/div[1]/div[1]/div/div/div[1]/input").click()time.sleep(3)self.driver.find_element(By.XPATH, "/html/body/div[1]/div/div/div/div[2]/div[1]/div[2]/div/div/div/div/div/div[2]/div[1]/div[1]/div/div/div[1]/input").send_keys(country_code)time.sleep(3)# self.driver.find_element(By.XPATH, "/html/body/div[6]/div/div").click()# china_option = self.wait.until(EC.element_to_be_clickable((By.XPATH, "//div[contains(@class, 'css-cqcgee')]//div[contains(text(), '+86')]")))time.sleep(5)except Exception as e:print("无法找到国家区号选项")print(e)# 定位手机号输入框phone_input = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "input[placeholder='手机号']")))phone_input.clear()phone_input.send_keys(phone)# 点击发送验证码按钮try:send_code_btn = self.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".css-uyobdj")))send_code_btn.click()except:# 尝试其他可能的选择器try:send_code_btn = self.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".css-1vfl29"))) send_code_btn.click()except:try:send_code_btn = self.wait.until(EC.element_to_be_clickable((By.XPATH, "//button[contains(text(),'发送验证码')]")))send_code_btn.click()except:print("无法找到发送验证码按钮")# 输入验证码verification_code = input("请输入验证码: ")code_input = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "input[placeholder='验证码']")))code_input.clear()code_input.send_keys(verification_code)# 点击登录按钮login_button = self.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".beer-login-btn")))login_button.click()# 等待登录成功,获取tokentime.sleep(3)# 保存cookiesself._save_cookies()# 关闭浏览器# self.driver.quit()# print(f"获取到的token: {token}")# if token:# self._save_token(token)# self.token = token# else:# print("未能获取到token")def post_article(self, title, content, images=None):"""发布文章Args:title: 文章标题content: 文章内容images: 图片路径列表"""# 如果token失效则重新登录# 设置token# self.driver.execute_script(f'localStorage.setItem("token", "{self.token}")')time.sleep(3)print("点击发布按钮")# 点击发布按钮publish_btn = self.wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".btn.el-tooltip__trigger.el-tooltip__trigger")))publish_btn.click()# 如果是发布视频,则不操作这一步# 切换到上传图文time.sleep(3)tabs = self.driver.find_elements(By.CSS_SELECTOR, ".creator-tab")if len(tabs) > 1:tabs[1].click()time.sleep(3)# # 输入标题和内容# title_input = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".title-input")))# content_input = self.driver.find_element(By.CSS_SELECTOR, ".content-input")# title_input.send_keys(title)# content_input.send_keys(content)# 上传图片if images:upload_input = self.driver.find_element(By.CSS_SELECTOR,'input[type="file"]')# 将所有图片路径用\n连接成一个字符串一次性上传upload_input.send_keys('\n'.join(images))time.sleep(1)time.sleep(3)JS_ADD_TEXT_TO_INPUT = """var elm = arguments[0], txt = arguments[1];elm.value += txt;elm.dispatchEvent(new Event('change'));"""title_input = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".d-text")))self.driver.execute_script(JS_ADD_TEXT_TO_INPUT, title_input, title)# title_input.send_keys(title)# Start of Selection# Start of Selectionprint(content)JS_ADD_TEXT_TO_P = """var elm = arguments[0], txt = arguments[1];elm.textContent = txt;"""content_input = self.wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".ql-editor")))p_element = content_input.find_element(By.CSS_SELECTOR, "p")print(p_element)self.driver.execute_script(JS_ADD_TEXT_TO_P, p_element, content)# content_input.send_keys(123)# 发布time.sleep(600)submit_btn = self.driver.find_element(By.CSS_SELECTOR, ".el-button.publishBtn")submit_btn.click()def close(self):"""关闭浏览器"""self.driver.quit()def post_article():poster = XiaohongshuClient()phone = open('./docs/phone.txt').read()poster.login(phone)print("登录成功")print("开始发布文章")print(os.getcwd())title = open('./xiaohongshu_drafts/小红书_推广文案_千战系列2025-02-15.txt', 'r', encoding='utf-8').readline()article = line_process.get_article('./xiaohongshu_drafts/小红书_推广文案_千战系列2025-02-15.txt')print(article)images = os.listdir('./pictures')images = map(lambda x: os.path.join(r"D:\Project\UUCrawl\Code\pictures", x), images)poster.post_article(title, article, images)poster.close()
7.7. 主程序
from crawler import ip_crawler, data_crawler
from analysis import data_analysis
from pic_generate import pic_generate, html_generate
from post import xiaohongshu_post
import file_handlerif __name__ == '__main__':url = 'D:/Project/UUCrawl/Code/pic_generate/pic.html'# 获取IPip = ip_crawler.crawl_ip()# 获取数据data = data_crawler.crawl_data()# 数据分析data_analysis.analysis_data()file_handler.start_observer()# 生成htmlhtml_generate.generate_html()# 生成图片pic_generate.generate_pic(url)# 发布小红书xiaohongshu_post.post_article()
相关文章:
使用DeepSeek+本地知识库,尝试从0到1搭建高度定制化工作流(自动化篇)
7.5. 配图生成 目的:由于小红书发布文章要求图文格式,因此在生成文案的基础上,我们还需要生成图文搭配文案进行发布。 原实现思路: 起初我打算使用deepseek的文生图模型Janus进行本地部署生成,参考博客:De…...
Python 函数式编程全攻略:从理论到实战的深度解析
本文深入剖析 Python 函数式编程,详细讲解其概念、核心特性(迭代器、生成器等)、内置函数及相关模块(itertools、functools ),结合丰富示例与直观图表,助力读者全面掌握函数式编程技巧ÿ…...
Ollama 在 LangChain 中的使用
文章目录 一、langChain 介绍二、环境安装1.依赖库安装2.下载模型 三、基本使用示例1.使用 ChatPromptTemplate 进行对话2.流式输出3.工具调用4.多模态模型调用 四、进阶使用1.使用 ConversationChain 进行对话2.自定义提示模板3.构建一个简单的 RAG 问答系统 五、遇到问题与解…...
使用apt-rdepends制作软件离线deb安装包
使用apt-rdepends制作软件离线deb安装包 除基础软件外,还要获取软件依赖包。 依赖包工具安装 apt-get install apt-rdependsapt-rdepends工具使用 使用apt-rdepends工具,递归方式分析软件依赖,下载软件包本体,和依赖包。制作时…...
根据POD名称生成 三部曲:get、describe、log、exec
#!/bin/bash# 定义颜色变量 RED\033[0;31m GREEN\033[0;32m YELLOW\033[0;33m NC\033[0m # No Color# 检查是否传入 Pod 名称作为参数 if [ -z "$1" ]; then# 如果没有传参,则提示用户输入 Pod 名称echo -e "${YELLOW}Please enter the Pod name:${…...
SQL sever数据导入导出实验
1.创建数据库TCP-H (1)右键“数据库”,点击“新建数据库”即可 (2)用sql语言创建,此处以创建数据库DB_test为例,代码如下: use master;go--检查在当前服务器系统中的所有数据里面…...
python环境的yolov11.rknn物体检测
1.首先是我手里生成的一个yolo11的.rknn模型: 2.比对一下yolov5的模型: 2.1 yolov5模型的后期处理: outputs rknn.inference(inputs[img2], data_format[nhwc])np.save(./onnx_yolov5_0.npy, outputs[0])np.save(./onnx_yolov5_1.npy, outpu…...
I2C、SPI、UART
I2C:串口通信,同步,半双工,双线(数据线SDA时钟线SCL),最大距离1米到几米 SPI(串行外设接口):串口通信,同步,全双工,四线&…...
如何监控和优化 MySQL 中的慢 SQL
如何监控和优化 MySQL 中的慢 SQL 前言一、什么是慢 SQL?二、如何监控慢 SQL?1. 启用慢查询日志启用方法:日志内容: 2. 使用 mysqldumpslow 分析日志 三、如何分析慢 SQL?1. 使用 EXPLAIN 分析执行计划使用方法&#x…...
13-二叉树最小深度-深度优先(DFS)
一、定义 什么是二叉树的最小深度? 二叉树的最小深度是指从根节点到最近的叶子节点的最短路径上的节点数。叶子节点是指没有子节点的节点。 举个例子: 1/ \2 3/ 4 这棵树的最小深度是 2,因为从根节点 1 到叶子节点 3 的路径最短&#x…...
51单片机入门_10_数码管动态显示(数字的使用;简单动态显示;指定值的数码管动态显示)
接上篇的数码管静态显示,以下是接上篇介绍到的动态显示的原理。 动态显示的特点是将所有位数码管的段选线并联在一起,由位选线控制是哪一位数码管有效。选亮数码管采用动态扫描显示。所谓动态扫描显示即轮流向各位数码管送出字形码和相应的位选ÿ…...
代码补全『三重奏』:EverEdit如何用上下文识别+语法感知+智能片段重构你的编码效率!
1 代码自动完成 1.1 应用场景 在编辑文档时,为了提高编辑效率,编辑器一般都会带有自动完成功能,比如:输入括号时自动补全另一半,输入文字时,自动补全剩下的部分。 1.2 使用方法 1.2.1 自动缩进 单击主菜…...
电脑系统损坏,备份文件
一、工具准备 1.U盘:8G以上就够用,注意会格式化U盘,提前备份U盘内容 2.电脑:下载Windows系统并进行启动盘制作 二、Windows启动盘制作 1.微软官网下载启动盘制作工具微软官网下载启动盘制作工具https://www.microsoft.com/zh-c…...
Token Statistics Transformer:线性注意力革命,重新定义Transformer效率天花板
“TOKEN STATISTICS TRANSFORMER: LINEAR-TIME ATTENTION VIA VARIATIONAL RATE REDUCTION” 由Ziyang Wu等人撰写。文章提出一种新型Transformer注意力算子,通过对最大编码率降低( M C R 2 MCR^{2} MCR2)目标的变分形式进行展开优化得到&…...
Django 5实用指南(二)项目结构与管理
2.1 Django5项目结构概述 当你创建一个新的 Django 项目时,Django 会自动生成一个默认的项目结构。这个结构是根据 Django 的最佳实践来设计的,以便开发者能够清晰地管理和维护项目中的各种组件。理解并管理好这些文件和目录结构是 Django 开发的基础。…...
JAVA监听器(学习自用)
一、什么是监听器 servlet监听器是一种特殊的接口,用于监听特定的事件(如请求创建和销毁、会话创建和销毁、上下文的初始化和销毁)。 当Web应用程序中反生特定事件时,Servlet容器就会自动调用监听器中相应的方法来处理这些事件。…...
Ubuntu下mysql主从复制搭建
本文介绍mysql 8.4主从集群的搭建,从单个机器安装到集群的配置,整体走了一遍,希望对大家有帮助。mysql 8.4和之前的版本命令上有些变化,大家用来参考。 0、环境 ubuntu: 22.04mysql:8.4 1、安装mysql 1…...
VirtualBox 中使用 桥接网卡 并设置 MAC 地址
在 VirtualBox 中使用 桥接网卡 并设置 MAC 地址,可以按照以下步骤操作: 步骤 1:设置桥接网卡 打开 VirtualBox,选择你的虚拟机,点击 “设置” (Settings)。进入 “网络” (Network) 选项卡。在 “适配器 1” (Adapt…...
Ubuntu 20 掉显卡驱动的解决办法
目录 问题背景解决办法Step1:首先查看当前linux内核Step2:重启Step3:进入ubuntu advanced (即高级选项)Step4:查看有哪些linux内核Step5:如果滚回老板kernel还是没有驱动,就找到驱动…...
EasyPoi系列之框架集成及基础使用
EasyPoi系列之框架集成及基础使用 1 EasyPoi1.1 gitee仓库地址 2 EasyPoi集成至SpringBoot2.1 maven引入jar包 3 EasyPoi Excel导出3.1 基于实体对象导出3.1.1 Excel 注解3.1.2 编写实体3.1.3 编写导出方法3.1.4 导出效果 3.2 基于模板导出3.2.1 编写模板文件3.2.2 编写导出方法…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
