余文乐

Configuration

先搞一个测试号,并且让收消息的人关注,获取 USER_ID

有自己个人号更好,我的没管它自动注销了

微信测试号关注

加个消息模版,获取 TEMPLATE_ID,加上测试号本身的 APP_ID APP_SECRET ,配置就齐了:

模版消息

在项目 Setting -> Secrets -> Actions 里新建几个我们要用的配置:

这里查天气的城市 CITY 是地级市汉字

生日 BIRTHDAYm-d 格式

纪念日 START_DATEY-m-d 格式

secrets

Workflow

使用 GitHub 的 Actions 建立工作流:

支持定时 schedule 与手动 workflow_dispatch 执行脚本 main.py,并且把设置中写的配置读出来

.github/workflows/main.yml
name: morning on: schedule: - cron: '1 23 * * *' workflow_dispatch: jobs: send_message: runs-on: ubuntu-latest name: send good morning steps: - name: checkout uses: actions/checkout@v3 with: ref: master - name: sender uses: actions/setup-python@v2 with: python-version: '3.x' architecture: 'x64' - run: pip install -r ./requirements.txt && python ./main.py env: APP_ID: ${{ secrets.APP_ID }} APP_SECRET: ${{ secrets.APP_SECRET }} TEMPLATE_ID: ${{ secrets.TEMPLATE_ID }} USER_ID: ${{ secrets.USER_ID }} START_DATE: ${{ secrets.START_DATE }} BIRTHDAY: ${{ secrets.BIRTHDAY }} CITY: ${{ secrets.CITY }}

这里 Cron 格式是标准的分时日月年,更多内容查看文档:

UTC 时间,北京时间要减 8

schedule

Python

先把配置拿出来:

today = datetime.utcnow() + timedelta(hours=8)
today = datetime.strptime(str(today.date()), "%Y-%m-%d")
start_date = os.getenv('START_DATE')
city = os.getenv('CITY')
birthday = os.getenv('BIRTHDAY')

app_id = os.getenv('APP_ID')
app_secret = os.getenv('APP_SECRET')
user_ids = os.getenv('USER_ID', '').split("\n")
template_id = os.getenv('TEMPLATE_ID')

获取城市天气:

def get_weather():
  if city is None:
    print('check your CITY config')
    return None
  url = "http://autodev.openspeech.cn/csp/api/v2.1/weather?openId=aiuicus&clientType=android&sign=android&city=" + city
  res = requests.get(url).json()
  if res is None:
    return None
  weather = res['data']['list'][0]
  return weather

计算纪念日:

def get_memorial_days_count():
  if start_date is None:
    print('check your START_DATE config')
    return 0
  delta = today - datetime.strptime(start_date, "%Y-%m-%d")
  return delta.days

计算生日:

def get_birthday_left():
  if birthday is None:
    print('check your BIRTHDAY config')
    return 0
  next = datetime.strptime(str(date.today().year) + "-" + birthday, "%Y-%m-%d")
  if next < datetime.now():
    next = next.replace(year=next.year + 1)
  return (next - today).days

获取一句情话:

失败重新调用

def get_words():
  words = requests.get("https://api.shadiao.pro/chp")
  if words.status_code != 200:
    return get_words()
  return words.json()['data']['text']

请求微信接口:

配置模版消息时 {{words.DATA}} 对应 data.words 字段,依此类推

try:
  client = WeChatClient(app_id, app_secret)
except WeChatClientException as e:
  print('get access token fail')
  exit(502)

wm = WeChatMessage(client)
weather = get_weather()
if weather is None:
  print('get weather fail')
  exit(422)
data = {
  "city": {
    "value": city,
    "color": get_random_color()
  },
  "date": {
    "value": today.strftime('%Y年%m月%d日'),
    "color": get_random_color()
  },
  "weather": {
    "value": weather['weather'],
    "color": get_random_color()
  },
  "temperature": {
    "value": math.floor(weather['temp']),
    "color": get_random_color()
  },
  "highest": {
    "value": math.floor(weather['high']),
    "color": get_random_color()
  },
  "lowest": {
    "value": math.floor(weather['low']),
    "color": get_random_color()
  },
  "love_days": {
    "value": get_memorial_days_count(),
    "color": get_random_color()
  },
  "birthday_left": {
    "value": get_birthday_left(),
    "color": get_random_color()
  },
  "words": {
    "value": get_words(),
    "color": get_random_color()
  },
}

if __name__ == '__main__':
  count = 0
  try:
    for user_id in user_ids:
      res = wm.send_template(user_id, template_id, data)
      count+=1
  except WeChatClientException as e:
    print('wechat error:%s.code:%d' % (e.errmsg, e.errcode))
    exit(502)

  print("total" + str(count) + "messages")

随机颜色为了好看点,手机上生效:

def get_random_color():
  return "#%06x" % random.randint(0, 0xFFFFFF)

引入依赖:

from datetime import date, datetime, timedelta
import math
from wechatpy import WeChatClient, WeChatClientException
from wechatpy.client.api import WeChatMessage
import requests
import os
import random
requirements.txt
certifi==2022.6.15 cffi==1.15.1 charset-normalizer==2.1.0 cryptography==37.0.4 idna==3.3 optionaldict==0.1.2 pycparser==2.21 python-dateutil==2.8.2 requests==2.28.1 six==1.16.0 urllib3==1.26.11 wechatpy==1.8.18 xmltodict==0.13.0

最终效果如图:

手机效果