使用Python自动制作《历史上的今天》宣传图片

简介: 使用Python自动制作《历史上的今天》宣传图片

大家好,今天分享一个通过 Python 自动创建相关图片的教程,而这个相关图片就是《历史上的今天》,那么为啥是历史呢,因为萝卜哥是一个历史迷,从小就喜欢啃历史书,随着年龄的增长,这份热情还是没有减退~

好了闲话不都说,我们直接上干货


数据获取

首先就是数据哪里来,我试过使用网上的一些免费历史查询接口,但是效果都不理想,这些接口不是太不稳定,就是数据不友好。最后我还是选择了一个精简的网站,直接扒网站页面信息即可

http://jintian.160.com/

网站很简单,也没有任何反爬措施,我们直接抓取数据

def get_data(month, day):
    result_dict = dict()
    for i in range(1, 3):
        url = "http://jintian.160.com/ashx/GreatThing.ashx?act=getgreatthinglist&page=%s&m=%s&d=%s&c=" % (str(i), month, day)
        data = requests.get(url)
        html = BeautifulSoup(data.json()["data"])
        data_li = html.find_all("li")
        for li in data_li:
            result = deal_some(li.text)
            tmp = result.split(" ")
            year = tmp[0].split("年")[0]
            new_day = tmp[0].split("年")[1]
            result_dict[year] = tmp[1]
    return result_dict, new_day

这里提供了月和天的变量,就是为了后面我们做成 web 服务时可以方面的获取任何时间的历史信息

然后我们再编写一个函数,把获取到的数据转化成 DataFrame 格式

def gen_df(result_dict):
    df = pd.DataFrame.from_dict(result_dict, orient='index', columns=['事件'])
    df = df.reset_index().rename(columns={'index': '年份'})
    return df

图片制作

对于最终生成的图片,使用的是 PyEcharts 制作,核心代码复用了《可以叫我才哥》公众号号主才哥的相关代码,下面我们简单解析下相关代码

首先我们明确图片基础是 Line 类型,没错就是我们平时用的最多的折线图!

先生成 Y 轴 数据

def gen_y(data):
    y_data = []
    counter = 0
    position = ['left', 'right']
    for idx, row in data.iterrows():
        msg = '{bbb|%s}\n{aaa|%s}' % (row['年份'], row['事件'])
        l_item = opts.LineItem(
            name=10,
            value=counter,
            symbol='emptyCircle',
            symbol_size=10,
            label_opts=opts.LabelOpts(
                is_show=True,
                font_size=16,
                position=position[counter%2],
                formatter=msg,
                rich = {
                    'aaa': {
                        'fontSize': 18,
                        'color': 'red',
                        'fontWeight':'bold',
                        'align':position[(counter+1)%2],
                        },
                    'bbb': {
                        'fontSize': 15,
                        'color': '#000',
                        'align':position[(counter+1)%2]}}
                )
        )
        y_data.append(l_item)
        counter+=1
    return y_data

使用系列配置pyecharts.options当中的LineItem类,不过很奇怪的是,这个类竟然在 PyEcharts 官网中找不到,还是查看了官方源码才大概了解其作用

class LineItem(BasicOpts):
    def __init__(
        self,
        name: Union[str, Numeric] = None,
        value: Union[str, Numeric] = None,
        *,
        symbol: Optional[str] = "circle",
        symbol_size: Numeric = 4,
        symbol_rotate: Optional[Numeric] = None,
        symbol_keep_aspect: bool = False,
        symbol_offset: Optional[Sequence] = None,
        label_opts: Union[LabelOpts, dict, None] = None,
        itemstyle_opts: Union[ItemStyleOpts, dict, None] = None,
        tooltip_opts: Union[TooltipOpts, dict, None] = None,
    ):
        self.opts: dict = {
            "name": name,
            "value": value,
            "symbol": symbol,
            "symbolSize": symbol_size,
            "symbolRotate": symbol_rotate,
            "symbolKeepAspect": symbol_keep_aspect,
            "symbolOffset": symbol_offset,
            "label": label_opts,
            "itemStyle": itemstyle_opts,
            "tooltip": tooltip_opts,
        }

大概的意思就是批量的设置 Line 的属性,这里不得不吐槽下 PyEcharts 官方文档,真的该好好维护下啊~(如果我这里理解的不对,欢迎指出,咱们一起学习~)

也就是说上面的代码生成了一系列数据,这些数据 X 轴都是 10,Y 轴是从 0 开始,一直到循环的最后一个值递增,同时还通过LabelOpts设置了 msg 信息,也就是我们最终看到的历史信息

XY 轴数据设置好之后,就是其他的样式调整了

def myLine(y, day):
    line = Line(
        init_opts=opts.InitOpts(
            theme='light',
            width='1000px',
            height='800px'
        )
    )
    line.add_xaxis(
        ['']
    )
    line.add_yaxis(
        '',
        y,
        linestyle_opts={
            'normal': {
                'width': 4,  # 设置线宽
                'color':'red',
                'shadowColor': 'rgba(155, 18, 184, .3)',  # 阴影颜色
                'shadowBlur': 10,  # 阴影大小
                'shadowOffsetY': 10,  # Y轴方向阴影偏移
                'shadowOffsetX': 10,  # x轴方向阴影偏移
            }
        },
        itemstyle_opts={
            'normal': {
                'color':'red',
                'shadowColor': 'rgba(155, 18, 184, .3)',  # 阴影颜色
                'shadowBlur': 10,  # 阴影大小
                'shadowOffsetY': 10,  # Y轴方向阴影偏移
                'shadowOffsetX': 10,  # x轴方向阴影偏移
            }
        },
        tooltip_opts=opts.TooltipOpts(is_show=False)
    )
    line.set_global_opts(
        xaxis_opts=opts.AxisOpts(is_show=False, type_='category'),
        yaxis_opts=opts.AxisOpts(is_show=False, type_='value', max_=len(y)),
        title_opts=opts.TitleOpts(
            title="历史上的今天-%s" % day, pos_left='center', pos_top='2%',
            title_textstyle_opts=opts.TextStyleOpts(color='red', font_size=20),
            subtitle="公众号:萝卜大杂烩 出品"
        ),
        toolbox_opts=opts.ToolboxOpts(
            is_show=True,
            orient="vertical",
            feature=opts.ToolBoxFeatureOpts(
                save_as_image=opts.ToolBoxFeatureSaveAsImageOpts(type_="jpeg", title="保存为jpeg",
                                                                 background_color="white"),
                restore=opts.ToolBoxFeatureRestoreOpts(),
                data_view=opts.ToolBoxFeatureDataViewOpts(),
                data_zoom=opts.ToolBoxFeatureDataZoomOpts(),
                magic_type=opts.ToolBoxFeatureDataViewOpts(),
                brush=opts.ToolBoxFeatureDataZoomOpts(),
            )
        ),
        graphic_opts=[
                    opts.GraphicGroup(
                                graphic_item=opts.GraphicItem(id_='1',left="center", top="center", z=-1),
                                children=[# tokyo
                                        opts.GraphicImage(graphic_item=opts.GraphicItem(id_="logo",
                                                                                        left='center',
                                                                                        z=-1),
                                                          graphic_imagestyle_opts=opts.GraphicImageStyleOpts(
                                            image="1.jpg",
                                            width=800,
                                            height=1000,
                                            opacity=0.1,)
                                        )
                                    ]
                                    )
                                    ]
    )
    return line

这里考验的就是 PyEcharts 的熟练程度了,反正萝卜我是不达标的,这样样式如果是我自己,可能要对照官网调整大半天,哈哈哈

好了,图片制作就介绍到这里

部署 Web 服务

因为有个需求就是每天获取图片,然后转发到微信群,那么最方便的方法就是部署成 Web,在公网上访问即可

对于这种临时的,个人网站,还是推荐使用 Flask,毕竟快就是优势(这里的快指的是编写快,上手快~)

导入 Flask 和 PyEcharts 相关库

from flask import Flask
from jinja2 import Markup, Environment, FileSystemLoader
from pyecharts.globals import CurrentConfig
import datetime
from flask import request
# 关于 CurrentConfig,可参考 [基本使用-全局变量]
CurrentConfig.GLOBAL_ENV = Environment(loader=FileSystemLoader("./templates"))

然后设置路由函数

def gen_line(month, day):
    result_dict, day = get_data(month, day)
    df = gen_df(result_dict)
    y = gen_y(df)
    line = myLine(y, day)
    return line
@app.route("/")
def index():
    month = request.args.get("month")
    day = request.args.get("day")
    if month and day:
        c = gen_line(month, day)
        return Markup(c.render_embed())
    i = datetime.datetime.now()
    c = gen_line(i.month, i.day)
    return Markup(c.render_embed())

这样就好了,通过 Flask 自带的 Web 容器启动即可

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0")

好了,今天的分享就到这里,想要体验的同学,可以访问这个网址

http://47.105.185.84:8080/

相关文章
|
1月前
|
存储 人工智能 开发工具
AI助理化繁为简,速取代码参数——使用python SDK 处理OSS存储的图片
只需要通过向AI助理提问的方式输入您的需求,即可瞬间获得核心流程代码及参数,缩短学习路径、提升开发效率。
1432 4
AI助理化繁为简,速取代码参数——使用python SDK 处理OSS存储的图片
|
1月前
|
Python
Python实用记录(六):如何打开txt文档并删除指定绝对路径下图片
这篇文章介绍了如何使用Python打开txt文档,删除文档中指定路径的图片,并提供了一段示例代码来展示这一过程。
28 1
|
1月前
|
计算机视觉 Python
Python实用记录(一):如何将不同类型视频按关键帧提取并保存图片,实现图片裁剪功能
这篇文章介绍了如何使用Python和OpenCV库从不同格式的视频文件中按关键帧提取图片,并展示了图片裁剪的方法。
66 0
|
3月前
|
计算机视觉 Windows Python
windows下使用python + opencv读取含有中文路径的图片 和 把图片数据保存到含有中文的路径下
在Windows系统中,直接使用`cv2.imread()`和`cv2.imwrite()`处理含中文路径的图像文件时会遇到问题。读取时会返回空数据,保存时则无法正确保存至目标目录。为解决这些问题,可以使用`cv2.imdecode()`结合`np.fromfile()`来读取图像,并使用`cv2.imencode()`结合`tofile()`方法来保存图像至含中文的路径。这种方法有效避免了路径编码问题,确保图像处理流程顺畅进行。
325 1
|
1月前
|
Python
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
使用Python的socket库实现客户端到服务器端的图片传输,包括客户端和服务器端的代码实现,以及传输结果的展示。
132 3
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
|
1月前
|
Python
Python实用记录(四):os模块-去后缀或者改后缀/指定目录下图片或者子目录图片写入txt/csv
本文介绍了如何使用Python的os模块来操作文件,包括更改文件后缀、分割文件路径和后缀、将指定目录下的所有图片写入txt文档,以及将指定目录下所有子目录中的图片写入csv文档,并为每个子目录分配一个标签。
16 1
|
1月前
|
编解码 UED Python
Python批量修改指定目录下图片的大小名文章
Python批量修改指定目录下图片的大小名文章
16 1
|
1月前
|
iOS开发 MacOS Python
Python编程小案例—利用flask查询本机IP归属并输出网页图片
Python编程小案例—利用flask查询本机IP归属并输出网页图片
|
1月前
|
数据采集 自然语言处理 Python
用 Python 生成并识别图片验证码
用 Python 生成并识别图片验证码
29 1
|
2月前
|
数据采集 开发者 Python
Python之怎么爬取图片网站
Python之怎么爬取图片网站