偷个懒,公号抠腚早报80%自动化——1.批量生成微信封面图

阿里云幸运券
简述
2018年的三月份写过一篇:《小猪的Python学习之旅 —— 18.Python微信转发小宇宙早报》,从一开始
手动转发别人发的新闻早报,到编写脚本到自动转发。然后毕竟这个是别人整理的,并不能保证准时,很多
时候早报变成了午报,然后还有存档问题,每次想看之前的早报就,都要微信搜聊天记录。啧啧,我琢磨着,
要不自己来整理早报。于是偷偷开始手动去整理早报,然后发在公号「抠腚男孩」上:

毕竟自己整理的,不确定看官能不能接受,得找几个小火汁来验证下下~

然后,把我整理的日报,套模板,改下日期,丢到童鞋群里看看他们有木有发现,测试两天后~

行吧,我就发吧,接下来简单说下每天发早报的流程。

1.制作当天早报的封面图
2.浏览新华社,i黑马,第一财经周刊等新闻站点,采集有趣的新闻,复制下标题。
3.把复制的标题粘贴到文本编辑器中,凑够15条新闻。
4.登录微信公众平台,打开昨天的文章,复制样式,粘贴,然后把今天的内容填进去。

接着检查下,没什么问题,就发布了。一开始,每天要耗费将近一个小时的时间来完成这件
事情,每天的摸鱼时间这么宝贵,花一个小时来做这件事情,显得有些得不偿失。作为一个
**勤(lan)奋(duo)**的开发仔,肯定要想办法来优化下,最好的结果就是:发早报完全自动化~

当然,也是想想而已,有读者可能好奇,为啥标题是80%,那么剩下的20%是什么?

答:15%是新闻的过滤,筛选有意思的新闻标题,这一步其实可以优化,最简单的就是,直接爬热搜
或者评论多的新闻标题,但是这样莫得灵魂,我更倾向于训练一个机器人,让他自动去筛选标题。
但是目前还不会这些东西,所以先搁一搁咯,还得手动去筛选~
剩下的5%是把早报发表到公号上,其实也可以自动化,通过selenium写个脚本自动点点点
就好了,不过个人感觉意义不大,而且我习惯发出去之前还需要预览下,确认内容
无误后才发送,毕竟文章发布后只能改标题,不能修改内容。
说下我目前想达到的一个形态吧:

1.编写脚本批量生成微信的封面图。
2.编写爬虫定时去爬取新闻,保存到本地数据库中。
3.编写接口,包括获取当天采集到的新闻,加入到新闻筛选池等。
4.编写用来筛选新闻的APP,利用上班坐地铁的时间快速筛选当天的新闻标题。
5.编写一键生成统一样式的早报文章的脚本。
6.编写一键生成当天新闻详情页面的脚本。
7.复制粘贴生成的样式文章,填写标题,发布者,在阅读原文中添加当天新闻详情页面的url,完成发布。
8.编写微信机器人,定时(暂定10点),拉取早报进行文本处理后,自动转发到相关的群。

好吧,大概的路线就这样,本节先从制作早报封面图开始**优(偷)化(懒)**吧。

1.封面图的制作过程
先来看看我每天的早报封面图吧,是介样的:

组成部分:背景图(900*383)+ 大标题(52px) + 二级标题(44px)
接着缩下我是制作这种封面图的流程:

1.平时闲着没事逛下一些壁纸的APP或者站点,觉得好看的就保存下来。
2.打开Pixelmator Pro新建一个900*383的模板,把图片拖进去,调节图片大小直到图片的宽度和模板的宽度相等。
3.接着移动调整缩放后的图片,直到自己喜欢位置。
4.依次添加大小标题,调整居中。
5.合并图层,裁剪。
6.导出成jpg文件。

为了让你们感受这个流程,我大概录了个Gif演示下,实际操作耗时远比这个久(7,8分钟的样子)。

每天如机器搬重复着这样的操作,多呆哦~然后,我竟然坚持了60+天(┬_┬);
着实需要一个脚本,把我从这种繁冗的工作中解脱出来。
读者可能对图源感兴趣,我一般喜欢直接保存壁纸APP里精选的靓图,
当然也可以自行爬取一些壁纸站点。另外,我发现,有些长图,其实
可以裁剪成几份来作为多期的封面,比如这样的图:

分割成两个,挺好看的。

感觉像像集卡一样,有点意思。

2.提取图片处理的流程
先来提取下图片处理的流程:

图片缩放:保持长宽比例不变进行缩放,直到宽为900px为止。
图片裁剪:先计算图片可以裁剪成多少份,以图片中间为基准裁剪,计算Y轴偏移,每个图片的坐标。
图片加字:对裁剪后的图片依次添加大小标题。

3.材料准备
行吧,处理流程说了,说下用到的Python库,直接通过pip命令安装即可:
(主要使用opencv来进行图片处理,pillow即PIL库)
pip install numpy
pip install opencv-python
pip install pillow
复制代码4.图片缩放
保持长宽比,设置为900px,我们通过opencv提供的imread()方法来获取一个图片对象,然后进行
相关操作。先获取一波高和宽度
import cv2

img = cv2.imread(‘1.jpg’)
(h, w) = img.shape[:2]
print(h, w)
腾讯云代金券

输出结果:956 1080

复制代码如果你想把图片显示出来,可以直接调用imshow()方法:
cv2.imshow(‘image’, img) # 参数依次为:窗口名称(窗口不能重名),读入的图片。
复制代码上述的代码,运行后会发现窗口一闪而过,可以调用waitKey()让窗口不关闭
cv2.waitkey() # 想窗口一直不关闭,可以不填参数或填0;也可以指定一个等待时间(单位毫秒)
# 在一个时间段内,等待用户按键触发关闭,如果一直不按键,到了时间会自动关闭。
复制代码但是,这里其实隐藏着一个小坑:如果你的图片是中文文件名或文件路径包含中文,调用imread会报错,比如:
img = cv2.imread(‘测试.jpg’)
cv2.imshow(‘img’, img)
cv2.waitKey()
复制代码运行结果:

同样调用imwrite()方法也是无法生成带有中文路径的图片的,可以自行编写两个函数来解决:
def cv_imread(file_path):
cv_img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1)
return cv_img

def cv_imwrite(img, file_path):
cv2.imencode(’.jpg’, img)[1].tofile(file_path)
复制代码行吧,能获取到宽高了,接着调用opencv提供的resize()方法调整图片的尺寸,参数依次为:
图片,宽高元组,还有一个可选参数:interpolation插值方法,默认使用INTER_LINEAR
双线性插值,其他的还有:INTER_NEAREST,INTER_AREA,INTER_CUBIC,INTER_LANCZOS4。
import cv2
import numpy as np

def cv_imread(file_path):
cv_img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1)
return cv_img

def cv_imwrite(img, file_path):
cv2.imencode(’.jpg’, img)[1].tofile(file_path)

img = cv_imread(‘测试.jpg’)
(h, w) = img.shape[:2]
print(“缩放前的尺寸:”, img.shape[:2])
res = cv2.resize(img, (900, round(h * (900 / w))))
print(“裁剪后的尺寸:”, res.shape[:2])
复制代码运行结果:
缩放前的尺寸: (956, 1080)
缩放后的尺寸: (797, 900)
复制代码5.图片裁剪
缩放完,接着就到裁剪了,先是计算图片能裁剪成几张:
crop_pic_count = int(ch / 383)
print(“图片可以裁剪为:%d张” % crop_pic_count)

输出结果:图片可以裁剪为:2张

复制代码接着是裁剪图片,可以通过:图片对象[y轴起始坐标:y轴终点坐标, x轴起始坐标:x轴终点坐标],来裁剪。
所以,我们要计算每个裁剪区域的对应的坐标方位。另外,这里还要考虑一个偏移,以中间位置为基准进行
裁剪,这样感觉会好一点。给个加偏移和不加偏移裁剪后的对比图吧:

so,我还是倾向于加偏移,计算偏移也很简单,直接拿高对383进行求余,然后除以2。
start_y = int(ch % 383 / 2)
复制代码接着根据能切成的图片张数,计算怎么裁剪
for i in range(0, crop_pic_count):
crop_img = res[383 * i + start_y: 383 * (i + 1) + start_y, 0:900]
cv_imwrite(crop_img, ‘剪切图%d.jpg’ % (i+1))
复制代码裁剪后的图片:

6.图片加字
行吧,图片也裁剪好了,接着就是图片加字了,可以通过opencv提供的putText()添加文字,
参数依次为: 图像,文字内容, 坐标 ,字体,大小,颜色,字体厚度。
img = cv_imread(‘剪切图0.jpg’)
cv2.putText(img, ‘Test’, (50, 300), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (255, 255, 255), 2)
cv2.imshow(‘image’, img)
cv2.waitKey()
复制代码运行结果如下:

加字成功,挺简单的,是吧?但是,如果你添加的文字不是字母或数字,而是中文的话,那么恭喜,黑人问号~

原因是:opencv自带的putText函数无法输出utf8类型的字符,因此无法将中文打印到图片上。
两个解决方法:

方法一:利用另一个freetype库,将字符解码转码,不过有点繁琐。
方法二:利用pillow库里ImageDraw类的text函数绘制中文,先从成cv2转PIL格式,加完中文再转回cv2格式输出。

这里采用的是方法二,text函数的参数:起始坐标元组,文字内容,字体,颜色。
问题来了,怎么确定绘制文字的起始坐标?

答:如果你要程序算,挺麻烦的,文字宽度怎么获取,既然图片尺寸固定,文字长度不变,为何不取巧一下呢?
直接在Pixelmator Pro上把文字拖好,然后复制下坐标,不就好了~

另外,这里笔者用的字体是 苹果-简,常规体,可以自行下载,记得把字体文件名改成英文文件名,
不然,会读取不到字体。好的,撸代码试试:
img = cv_imread(‘剪切图0.jpg’)

将图片从OpenCv格式转为PIL格式

img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

加载字体(字体文件名,字体大小)

title_font = ImageFont.truetype(‘apple-simple.ttf’, 52)
date_font = ImageFont.truetype(‘apple-simple.ttf’, 44)

绘制文字的位置

title_pos = (236, 110)
date_pos = (338, 192)

绘制内容

title_content = u"『抠腚早报速读』"
date_content = u"第190111期"

绘制

draw = ImageDraw.Draw(img_pil)
draw.text(title_pos, title_content, font=title_font, fill=(255, 255, 255))
draw.text(date_pos, date_content, font=date_font, fill=(255, 255, 255))
img_open_cv = cv2.cvtColor(np.asarray(img_pil), cv2.COLOR_RGB2BGR)
cv_imwrite(img_open_cv, “加字后.jpg”)
复制代码接着看下输出的图片:

啧啧啧,完美,到此自动裁剪生成一个早报封面的脚本就完成啦,接下来我们来补全和完善下我们的程序。
7.代码补全完善
就是加了循环,一些小逻辑,比较简单,注释也比较清晰,就不叨逼叨了,直接上完整代吧:

-- coding: utf-8 --

import os
import cv2
import numpy as np
import time
from PIL import Image, ImageDraw, ImageFont
from datetime import datetime, timedelta
import shutil

pic_source_dir = os.path.join(os.getcwd(), “news_pic_source\”) # 原图路径
pic_crop_dir = os.path.join(os.getcwd(), “news_pic_crop\”) # 裁剪后的图片路径
pic_font_dir = os.path.join(os.getcwd(), “news_pic_font\”) # 加字后的图片路径
start_date = “20190112” # 绘制图片的其起始日期

判断文件夹是否存在,不存在则新建

def is_dir_existed(path, mkdir=True):
if mkdir:
if not os.path.exists(path):
os.makedirs(path)
else:
return os.path.exists(path)

opencv读取中文路径名会乱码

def cv_imread(file_path):
cv_img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1)
return cv_img

opencv写入中文路径名会乱码

def cv_imwrite(img, file_path):
cv2.imencode(’.jpg’, img)[1].tofile(file_path)

把原图裁剪为多个小图(900*383)

def crop_little_pic(pic_path):
img = cv_imread(pic_path)
(sh, sw) = img.shape[:2]
# 将图片的宽设置为900,高则按比例缩放
res = cv2.resize(img, (900, round(sh * (900 / sw))))
# 获取缩放后的高和宽,判断图片可裁剪的张数
(ch, cw) = res.shape[:2]
crop_pic_count = int(ch / 383)
# 计算Y轴偏移
start_y = int(ch % 383 / 2)
# 根据图片的张数来决定怎么裁剪
for i in range(0, crop_pic_count):
crop_img = res[383 * i + start_y: 383 * (i + 1) + start_y, 0:900]
cv_imwrite(crop_img, os.path.join(pic_crop_dir, str(int(round(time.time() * 1000))) + ‘.jpg’))

绘制文字

def draw_text(pic_path, date):
img = cv_imread(pic_path)
# 将图片从OpenCv格式转为PIL格式
img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
# 加载字体(字体文件名,字体大小)
title_font = ImageFont.truetype(‘apple-simple.ttf’, 52)
date_font = ImageFont.truetype(‘apple-simple.ttf’, 44)
# 绘制文字的位置
title_pos = (236, 110)
date_pos = (316, 192)
# 绘制内容
title_content = u"『抠腚早报速读』"
date_content = u"第%s期" % date[2:]
# 绘制
draw = ImageDraw.Draw(img_pil)
draw.text(title_pos, title_content, font=title_font, fill=(255, 255, 255))
draw.text(date_pos, date_content, font=date_font, fill=(255, 255, 255))
img_open_cv = cv2.cvtColor(np.asarray(img_pil), cv2.COLOR_RGB2BGR)
cv_imwrite(img_open_cv, os.path.join(pic_font_dir, date[2:] + ‘.jpg’))

遍历获得某类文件路径列表

def fetch_file_path(path, file_type):
file_list = []
f = os.listdir(path)
for i in f:
if i.endswith(file_type):
file_list.append(os.path.join(path, i))
return file_list

构造生成日期列表

def init_date_list(begin_date, count):
d_list = []
begin_date = datetime.strptime(begin_date, “%Y%m%d”)
end_date = datetime.strptime((datetime.now() + timedelta(days=count)).strftime("%Y%m%d"), “%Y%m%d”)
while begin_date <= end_date:
date_str = begin_date.strftime("%Y%m%d")
d_list.append(date_str)
begin_date += timedelta(days=1)
return d_list

if name == ‘main’:
is_dir_existed(pic_source_dir)
while True:
choice = input(
“%s\n请输入你想进行的操作\n1.进行图片裁剪\n2.图片加字\n3.清空裁剪文件夹\n4.清空加字文件夹\n5.退出程序\n%s\n” % (’=’ * 32, ‘=’ * 32))
if choice == ‘1’:
is_dir_existed(pic_crop_dir)
pic_path_list = fetch_file_path(pic_source_dir, “.jpg”)
if len(pic_path_list) == 0:
print(“原图文件夹中无图片,请先添加图片!”)
else:
print(“开始批量裁剪…”)
begin = datetime.now()
for pic in pic_path_list:
crop_little_pic(pic)
end = datetime.now()
print(“批量裁剪完毕,生成图片:%d张,耗时:%s秒” % (len(fetch_file_path(pic_crop_dir, “.jpg”)), (end - begin).seconds))
elif choice == ‘2’:
is_dir_existed(pic_font_dir)
crop_path_list = fetch_file_path(pic_crop_dir, “.jpg”)
date_list = init_date_list(start_date, len(crop_path_list) + 1)
if len(crop_path_list) == 0:
print(“裁剪文件夹中无图片,请先生成裁剪图片!”)
else:
print(“开始批量加字…”)
begin = datetime.now()
print(len(crop_path_list), len(date_list))
for i in range(len(crop_path_list)):
draw_text(crop_path_list[i], date_list[i])
end = datetime.now()
print(“批量加字完毕,处理图片:%d张,耗时:%s秒” % (len(fetch_file_path(pic_font_dir, “.jpg”)), (end - begin).seconds))
elif choice == ‘3’:
if is_dir_existed(pic_crop_dir, False):
shutil.rmtree(pic_crop_dir)
print(“文件夹删除成功!”)
else:
print(“文件夹不存在,删除失败~”)
elif choice == ‘4’:
if is_dir_existed(pic_font_dir, False):
shutil.rmtree(pic_font_dir)
print(“文件夹删除成功!”)
else:
print(“文件夹不存在,删除失败~”)
elif choice == ‘5’:
exit(“退出程序~”)
else:
print(“错误序号,请确认后重新输入!!!”)
复制代码执行前,先准备一波图片原图,这里准备了:

接着运行一波代码,运行后依次键入1,2进行裁剪和加字:

啧啧,94张原图生成了243张封面图,而且,只花了十几秒,打开生成的文件夹看一波:

都生成到9月份了,2333,真人生苦短,我用Python,此处应该有掌声~

另外前几天写了个脚本是采集一堆视频第一帧然后进行处理的,赶脚有同学会需要,把核心代码也贴下把~

截取视频的第一帧

def fetch_video_first_frame(path_list):
for mp4 in path_list:
cap = cv2.VideoCapture(mp4)
if cap.isOpened():
ret, im = cap.read()
cv2.imencode(’.jpg’, im)[1].tofile(
os.path.join(pic_source_output_dir, mp4.split("\")[-1]).replace(“mp4”, “jpg”))
cap.release()

腾讯云代金券

原文链接

https://juejin.im/post/5c37100f6fb9a049fd100cae

服务推荐

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值