前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【随笔】自动化油价推送:GitHub Actions 实战

【随笔】自动化油价推送:GitHub Actions 实战

作者头像
框架师
发布2023-12-16 09:38:21
1180
发布2023-12-16 09:38:21
举报
文章被收录于专栏:墨白的Java基地墨白的Java基地

前言

今年自五月份以来发生了许多事情,其中一个显著的变化是我购买了一辆车。刚开始觉得购车挺便捷的,然而提车的第一个月油费竟然直逼 1300 元,让我对这部分开支感到有些心疼。因此,我决定开发一个油价推送小程序,以便获取当前所在城市油价的实时变化情况。通过这个小程序,我可以方便地了解油价的走势,从而更好地掌握预算。为了使这个小程序更加实用,我将项目上传到了 GitHub,并且利用 Actions 定时在每天下午 4 点半自动推送油价变化。以下是我实现这一想法的具体思路。

获取源数据

在网上找到一个油价网站,http://www.qiyoujiage.com , 定位到自己所在的具体地址,例如:http://www.qiyoujiage.com/hubei/xxx.shtml ,通过 jsoup 抓取关键数据,如 92#-0# 汽油价格等其他自己需要的数据。

项目开始

创建一个普通 maven 项目,依赖如下:

代码语言:javascript
复制
<properties>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>21</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <hutool-all.version>5.8.23</hutool-all.version>
    <jsoup.version>1.16.1</jsoup.version>
    <thymeleaf.version>3.1.2.RELEASE</thymeleaf.version>
    <javax.mail-api.version>1.6.2</javax.mail-api.version>
</properties>

<dependencies>
    <!-- 工具类 -->
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>${hutool-all.version}</version>
    </dependency>
    <!-- 爬虫框架 -->
    <dependency>
        <groupId>org.jsoup</groupId>
        <artifactId>jsoup</artifactId>
        <version>${jsoup.version}</version>
    </dependency>
    <!-- 邮件模板 -->
    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf</artifactId>
        <version>${thymeleaf.version}</version>
    </dependency>
    <dependency>
        <groupId>javax.mail</groupId>
        <artifactId>javax.mail-api</artifactId>
        <version>${javax.mail-api.version}</version>
    </dependency>
    <!-- Java Mail -->
    <dependency>
        <groupId>com.sun.mail</groupId>
        <artifactId>javax.mail</artifactId>
        <version>${javax.mail-api.version}</version>
    </dependency>
</dependencies>

JDK 版本尽量保持一致,毕竟 SpringBoot 3.0 所要求的 JDK 版本最低都是 Java17 了,抱着 Java8 养老都不够用了。

具体的功能实现

代码语言:javascript
复制
package com.mobaijun.oil;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.extra.mail.MailAccount;
import cn.hutool.extra.mail.MailUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Description: [油价解析]
 * Author: [mobaijun]
 * Date: [2023/12/2 19:09]
 * IntelliJ IDEA Version: [IntelliJ IDEA 2023.1.4]
 */
public class OilParse {

    /**
     * 日志打印
     */
    private static final Log log = LogFactory.get(OilParse.class);

    /**
     * 爬取地址
     */
    private static final String START_URL = "http://www.qiyoujiage.com/hubei/shiyan.shtml";

    /**
     * 汽油说明
     */
    private static final String DE_SCRIPT_GASOLINE_MODEL = """
            92 汽油的平均密度为 0.725kg/L,一升 92 号汽油为 0.725 千克;
            95 号汽油的密度为 0.737g/ml,一升 95 号汽油为 0.737 千克;
            0 号柴油的密度在 0.8400--0.8600g/cm⒊之间,一升 0# 柴油大约是 0.84 千克;""";

    /**
     * 邮件发送
     *
     * @param args 参数
     */
    public static void main(String[] args) {
        String oilPriceEmail = generateOilPriceEmail(parseOilData());
        MailAccount account = createMailAccount();
        sendMail(account, oilPriceEmail);
    }

    private static Map<String, String> parseOilData() {
        Map<String, String> oilMap = new LinkedHashMap<>();
        try {
            Document document = Jsoup.connect(OilParse.START_URL).timeout(3000).get();
            String you = Objects.requireNonNull(document.getElementById("youjia")).text();
            oilMap.putAll(splitData(you));
        } catch (IOException e) {
            log.error("HTML parsing failed, please try again! error message:{}", e.getMessage());
        }
        return oilMap;
    }

    private static Map<String, String> splitData(String inputData) {
        Map<String, String> keyValuePairs = new LinkedHashMap<>();
        Pattern pattern = Pattern.compile("(\\S+)\\s(\\S+)");
        Matcher matcher = pattern.matcher(inputData);
        while (matcher.find()) {
            String key = matcher.group(1);
            String value = matcher.group(2);
            keyValuePairs.put(key, value);
        }
        return keyValuePairs;
    }

    private static MailAccount createMailAccount() {
        MailAccount account = new MailAccount();
        account.setHost("smtp.163.com");
        account.setPort(465);
        account.setUser("mobaijun8@163.com");
        account.setPass("你的邮箱授权密码 - 具体可 Google");
        account.setFrom("mobaijun8@163.com");
        account.setCharset(StandardCharsets.UTF_8);
        account.setStarttlsEnable(false);
        account.setSslEnable(true);
        return account;
    }

    private static void sendMail(MailAccount account, String oilPriceEmail) {
        try {
            MailUtil.send(account, "mobaijun8@163.com", "湖北今日油价", oilPriceEmail, true);
            log.info("邮件发送成功!");
        } catch (Exception e) {
            log.error("邮件发送失败:" + e.getMessage());
        }
    }

    private static String generateOilPriceEmail(Map<String, String> oilData) {
        // 读取 Thymeleaf 模板
        String template = readTemplate();
        // 使用 Thymeleaf 引擎进行数据填充
        TemplateEngine templateEngine = new TemplateEngine();
        Context context = new Context();
        context.setVariable("title", "湖北今日油价");
        context.setVariable("subTitle", "每日即时更新 单位: 元 / 升");
        context.setVariable("oilData", oilData);
        context.setVariable("oilDeScript", DE_SCRIPT_GASOLINE_MODEL);
        return templateEngine.process(template, context);
    }

    /**
     * 读取 Template
     *
     * @return 内容
     */
    private static String readTemplate() {
        try (InputStream inputStream = new ClassPathResource("oil_price_template.html").getStream()) {
            return IoUtil.read(inputStream, StandardCharsets.UTF_8);
        } catch (IOException e) {
            log.error("模板文件读取失败:{}" + e.getMessage());
            return "";
        }
    }
}

新建邮件模板

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta content="width=device-width, initial-scale=1.0" name="viewport">
    <style>
        body {
            background-image: url(?developer/article/2371519/&);
            background-size: cover;
            /* 使用深色背景 */
            background-color: #333;
            /* 将文字颜色改为黑色 */
            color: #000; /* 黑色 */
            font-family: Arial, sans-serif;
        }

        h1 {
            text-align: center;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            margin: 20px 0;
        }

        th, td {
            border: 1px solid #54d1d5;
            padding: 8px;
            text-align: left;
        }

        th {
            background-color: #70a0a4;
            color: #030303;
        }

        p {
            margin: 20px 0;
            color: #000; /* 黑色 */
        }

        h3 {
            text-align: center;
            color: #000; /* 黑色 */
        }

        blockquote {
            text-align: center;
            color: #000; /* 黑色 */
        }
    </style>
    <title></title>
</head>
<body>
<h1 th:text="$">湖北今日油价</h1>
<p style="text-align: center;"
   th:text="| 当日更新时间: ${#temporals.format(#temporals.createNow().plusHours(8),'yyyy-MM-dd HH:mm:ss')} 单位: 元 / 升 |"></p>
<table>
    <thead>
    <tr style="background-color: rgba(112, 160, 164, 0.5);">
        <th>汽油型号</th>
        <th>油价</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="entry : ${oilData}">
        <td th:text="${entry.key}">Type</td>
        <td th:text="${entry.value}">Price</td>
    </tr>
    </tbody>
</table>
<!-- 型号描述 -->
<h3 style="text-align: center; accent-color: #030303;">汽油型号说明</h3>
<blockquote style="text-align: center;" th:utext="${#vars.oilDeScript.replaceAll(';','</br></br>')}">汽油型号简介
</blockquote>
</body>
</html>

创建 ci.yml 文件

代码语言:javascript
复制
name: Run Java Main Method

on:
  workflow_dispatch:
  schedule:
    - cron: '30 8 * * *'

jobs:
  run-java-main:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Set up Java
        uses: actions/setup-java@v2
        with:
          distribution: 'adopt'
          java-version: '21'
      - name: Add execute permission to mvnw
        run: chmod +x mvnw

      - name: Build with Maven
        run: |
          ./mvnw -B package --file ./pom.xml

      - name: Run Java Main Method
        run: |
          java -jar target/oil-price-push-jar-with-dependencies.jar

配置 maven 插件

代码语言:javascript
复制
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>21</source>
                <target>21</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.3.0</version>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>com.mobaijun.oil.OilParse</mainClass>
                    </manifest>
                </archive>
                <descriptorRefs>
                    <!-- 这个 jar-with-dependencies 是 assembly 预先写好的一个,组装描述引用 -->
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <!-- 工程名 -->
                <finalName>${project.name}</finalName>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

最终效果

通过以上步骤就完成了一个简单的油价推送小程序,如有什么问题,欢迎在评论区留言,讨论!

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-12-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 获取源数据
  • 项目开始
  • 具体的功能实现
  • 新建邮件模板
  • 创建 ci.yml 文件
  • 配置 maven 插件
  • 最终效果
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com