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


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

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

    alt

    数据获取

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

    http://jintian.160.com/

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

    def get_data(month, day):
        result_dict = dict()
        for i in range(13):
            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
    • 1

    这里提供了月和天的变量,就是为了后面我们做成 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
    • 1

    图片制作

    对于最终生成的图片,使用的是 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
    • 1

    使用系列配置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,
            }
    • 1

    大概的意思就是批量的设置 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
    • 1

    这里考验的就是 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"))
    • 1

    然后设置路由函数

    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())
    • 1

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

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

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

    http://47.105.185.84:8080/

    看到这里的朋友,如果你觉得满意请务必点个赞 + 在看 支持下。

    一键三连,私信获取完整代码~

    本文由 mdnice 多平台发布

  • 相关阅读:
    java基于ssm的体育馆票务管理系统
    《向量数据库》——都有哪些向量数据库,都有什么特点?
    OA项目之会议排座和送审
    【OS】操作系统课程笔记 第五章 并发性——互斥、同步和通信
    arm学习之基本汇编指令
    SQLServer统计监控SQL执行计划突变的方法
    【VSCode】配置C/C++开发环境教程(Windows系统)
    区块链通证的分类(各种分类一览表)
    Python装饰器ZERO 2 HERO
    ShardingJdbc实战-分库分表
  • 原文地址:https://blog.csdn.net/zhouwei_1989_/article/details/126192820