一、项目背景
偶然看到一篇公众号文章,通过代码方式自动生成微信聊天记录,然后自动合成视频,用这种流水线方式一天最多能产出上百条短视频,在DY和B站里有不少此类视频,流量还都不错。搜索过后发现还有不少此类成熟的产品在售卖,最低包月9.9元。
本着来都来了的心态,自己也想用文章提示的技术思路折腾的实现下,于是有了此次小项目。技术采用python现有成熟的库实现,由于本人还是个技术小白,所有代码看起来比较幼稚,望各位大佬谅解!废话不多说开干。
二、可行性分析
先分析下整个项目流程。
1、找到能添加微信聊天记录的页面(大佬可以自己搭一个页面)
2、利用selenium库自动化添加聊天记录
3、分步保存聊天记录页面
4、利用opencv库将页面合成视频
三、最小实现方案
先做个最简单两人纯文字的聊天流程
1、先逐个对话生成图片
2、将图片合并成短视频
最后实现的效果如下:
四、实现方式及难点解决
python 3.12
1、逐个对话生成图片代码
import base64
import time
from selenium import webdriver
import re
from selenium.webdriver.common.by import By
#读取需要显示的文本
txt_path=''#你收集的段子txt文件
touxiang1=''#用户1头像
touxiang2=''#用户2头像
jietu_path=''#截图保存位置
sucai1 = open(txt_path, 'rb')
sucai2 = sucai1.readlines()
duanzi = []
answ = []
for line in sucai2:
duanzi.append(str(line, 'utf-8'))
#去除换行回车符,将问题和回答切分成不同的字符
for i in range(len(duanzi)):
duanzi[i] = re.sub(r'[\n\r]', '', duanzi[i])
resp = re.split("?", duanzi[i]) #注意问号的中英文符号切换
for j in range(2):
answ.append(resp[j])
#1.创建Chrome或Firefox浏览器对象,这会在电脑上在打开一个浏览器窗口
browser = webdriver.Chrome()
#2.通过浏览器向服务器发送URL请求。如果能打开百度网站,说明安装成功。
browser.get("https://app.ippapp.com/screenchat/")
#微信聊天界面外观设置
def waiguan_set():
# 点击手机外观
input0 = browser.find_element(By.CSS_SELECTOR, '#tab-0')
input0.click()
# 选择浅色风格
input1 = browser.find_element(By.CSS_SELECTOR,
'#pane-0 > div > form > div:nth-child(1) > div > div > label:nth-child(2) > span.el-radio__input > span')
input1.click()
# 修改运营商
input2 = browser.find_element(By.CSS_SELECTOR,
'#pane-0 > div > form > div:nth-child(3) > div > div > input')
input2.clear()
input2.send_keys('天地通信')
# 修改时间
input3 = browser.find_element(By.CSS_SELECTOR,
'#pane-0 > div > form > div:nth-child(8) > div > div > input')
input3.clear()
input3.send_keys('23:59:00')
# 确定修改后的时间
input4 = browser.find_element(By.CSS_SELECTOR,
'body > div.el-time-panel.el-popper > div.el-time-panel__footer > button.el-time-panel__btn.confirm')
input4.click()
# 选择屏幕不锁定
input5 = browser.find_element(By.CSS_SELECTOR,
'#pane-0 > div > form > div:nth-child(9) > div > div > label:nth-child(2) > span.el-radio__input > span')
input5.click()
# 选择电池状态正常
input6 = browser.find_element(By.CSS_SELECTOR,
'#pane-0 > div > form > div:nth-child(13) > div > div > label:nth-child(1) > span.el-radio__input > span')
input6.click()
#微信聊天界面外观设置
def neirong_bg_set():
# 点击内容设置
input0 = browser.find_element(By.CSS_SELECTOR, '#tab-1')
input0.click()
# 添加时间
input1 = browser.find_element(By.CSS_SELECTOR,
'#pane-1 > div:nth-child(2) > form > div:nth-child(3) > div > button')
input1.click()
# 修改时间
input2 = browser.find_element(By.CSS_SELECTOR,
'#shareBox > div > div.content-container > div > div:nth-child(1) > div')
input2.click()
# 确认修改时间
input3 = browser.find_element(By.CSS_SELECTOR,
'body > div.el-message-box__wrapper > div > div.el-message-box__btns > button.el-button.el-button--default.el-button--small.el-button--primary')
input3.click()
# 修改日期类型
input4 = browser.find_element(By.CSS_SELECTOR,
'#app > div.el-dialog__wrapper > div > div.el-dialog__body > form > div > div:nth-child(1) > div > div > label.el-radio.is-checked > span.el-radio__input.is-checked > span')
input4.click()
# 填写修改日期
input5 = browser.find_element(By.CSS_SELECTOR,
'#app > div.el-dialog__wrapper > div > div.el-dialog__body > form > div > div:nth-child(2) > div > div > input')
input5.clear()
input5.send_keys('07月22日')
# 填写修改时间
input6 = browser.find_element(By.CSS_SELECTOR,
'#app > div.el-dialog__wrapper > div > div.el-dialog__body > form > div > div:nth-child(3) > div > div > input')
input6.clear()
input6.send_keys('下午23:59')
# 确定
input7 = browser.find_element(By.CSS_SELECTOR,
'#app > div.el-dialog__wrapper > div > div.el-dialog__footer > div > button.el-button.el-button--primary.el-button--small')
input7.click()
# 添加用户头像1
input8 = browser.find_element(By.CSS_SELECTOR,
'#pane-1 > div:nth-child(2) > form > div:nth-child(6) > div:nth-child(2) > div > div > input')
input8.send_keys(touxiang1)
# 添加用户头像2
input9 = browser.find_element(By.CSS_SELECTOR,
'#pane-1 > div:nth-child(2) > form > div:nth-child(7) > div:nth-child(2) > div > div > input')
input9.send_keys(touxiang2)
#添加用户1、2对话
def duihua(i):
for index1 in range(i):
#偶数是用户1对话
if index1 % 2 == 0:
# 用户1添加问题
input1 = browser.find_element(By.CSS_SELECTOR,
'#pane-1 > div:nth-child(2) > form > div:nth-child(6) > div:nth-child(4) > div > div:nth-child(2) > button:nth-child(1)')
input1.click()
#编辑用户1对话
user_duihua(index1)
# 用户1输入问题
input5 = browser.find_element(By.CSS_SELECTOR,
'#app > div.el-dialog__wrapper > div > div.el-dialog__body > form > div > div > div > div > input')
input5.send_keys(answ[index1])
input6 = browser.find_element(By.CSS_SELECTOR,
'#app > div.el-dialog__wrapper > div > div.el-dialog__footer > div > button.el-button.el-button--primary.el-button--small')
input6.click()
#截图
jietu(index1)
#奇数是用户2对话
else:
input2 = browser.find_element(By.CSS_SELECTOR,
'#pane-1 > div:nth-child(2) > form > div:nth-child(7) > div:nth-child(4) > div > div:nth-child(2) > button:nth-child(1)') # 用户2添加问题
input2.click()
#编辑用户2对话
user_duihua(index1)
input7 = browser.find_element(By.CSS_SELECTOR,
'#app > div.el-dialog__wrapper > div > div.el-dialog__body > form > div > div > div > div > input') # 用户2输入问题
input7.send_keys(answ[index1])
input8 = browser.find_element(By.CSS_SELECTOR,
'#app > div.el-dialog__wrapper > div > div.el-dialog__footer > div > button.el-button.el-button--primary.el-button--small')
input8.click()
#截图
jietu(index1)
#编辑用户对话
def user_duihua(i):
#点击修改对话, 注意选择单元框的css_selector
input3 = browser.find_element(By.CSS_SELECTOR,
'#shareBox > div > div.content-container > div > div:nth-child(%s) > div > '
'div.message-content > span' % str(i + 2))
#定位到要修改的对话位置,模拟页面滑动
browser.find_element(By.CSS_SELECTOR,
'#shareBox > div > div.content-container > div > div:nth-child(%s) > div > div.message-content > span'
% str(i + 2)).location_once_scrolled_into_view
input3.click()
#点击编辑对话
input4 = browser.find_element(By.CSS_SELECTOR,
'body > div.el-message-box__wrapper > div > div.el-message-box__btns > button.el-button.el-button--default.el-button--small.el-button--primary') # 用户编辑问题
input4.click()
#截图对话
def jietu(i):
#点击生成图片
input1 = browser.find_element(By.CSS_SELECTOR,
'#app > div.page-header > div.header-button > button')
input1.click()
#停顿2秒等待截图出现
time.sleep(2)
#定位src
input2 = browser.find_element(By.CSS_SELECTOR,
'#app > div.page-header > div.el-dialog__wrapper > div > div.el-dialog__body > div > div.share-image-block > div > img')
input3 = input2.get_attribute('src')
#图片编码是base64,转码后下载保存
input3 = input3[22:]
input3 = base64.b64decode(input3)
with open(jietu_path+'/page%s.jpg' % str(i), mode='wb') as f:
f.write(input3)
#关闭截图页面
input4 = browser.find_element(By.CSS_SELECTOR,
'#app > div.page-header > div.el-dialog__wrapper > div > div.el-dialog__header > button')
input4.click()
#截完图等2秒
time.sleep(2)
waiguan_set()
neirong_bg_set()
duihua(len(answ))
2、合并图片生成短视频代码
import cv2
import os
# 图片文件夹路径
image_folder = ''#截图的位置
# 输出视频文件路径
output_video = ''#要保存mp4视频文件位置
# 获取文件夹中所有图片的文件名
images = [img for img in os.listdir(image_folder) if img.endswith('.jpg')]
# 按照文件名排序
images.sort(key=lambda x:int(x.replace('page','').split('.')[0]))
#获取图片的宽度和高度
width = 754
height = 1338
fps = 0.618
# 创建VideoWriter对象,指定输出视频文件的路径、帧率、宽度和高度等参数
fourcc = cv2.VideoWriter_fourcc(*'mp4v') # 选择视频编解码器
video = cv2.VideoWriter(output_video, fourcc, fps, (width, height))
# 遍历所有图片,将它们写入输出视频文件
for image in images:
img = cv2.imread(os.path.join(image_folder, image))
video.write(img)
# 释放VideoWriter对象,释放资源
video.release()
3、难点
- 如果用google浏览器,需要提前查看自己google浏览器版本并安装对应的googledriver
- 127版本以上下载地址:Chrome for Testing availability
- selenium库用4.1.1可以显示浏览器自动操作页面
-
selenium模拟上传图片操作,定位后使用send_keys方法,一定要符合input和type=‘file’条件。可参考这篇文章:
-
生成图片后要等2秒,不然图片刷不出来会报错
-
截完图后等2秒,不然添加下一次对话会报错
-
对话太多时,页面如果不滑动会定位不到新的对话标签,模拟鼠标滑动效果不好使,不如直接定位到新的标签位置然后再滑动。(这一步折腾了2天,最后解决了)
driver.find_element(By.CSS_SELECTOR,'').location_once_scrolled_into_view
-
cv2库,安装的时候用 opencv_python,但在导入使用的时候使用 cv2
-
图片一定要排序后再合成视频
五、优化
- 用OOP优化程序,最好能模仿现有售卖的产品形成一个交互界面。
- 可以本地建一个微信聊天页面,修改不同手机型号的页面。
- 优化微信聊天界面,增加实时打字输入,表情包,发语音功能。
- 进一步编辑视频,添加BGM,素材效果。