golang實現微信模板消息推送

前言

本文是基於https://www.cnblogs.com/connect/p/python-wechat-iciba.html 這篇博客寫成的。該博客實現了用python將金山詞霸的每日一句推送到微信公衆測試號,我想既然python能實現,那麼用Golang也可以。

運行環境

1、阿里雲Linux服務器
2、Go開發環境
完整的項目代碼:https://github.com/qq737310694/WechatTemplate

獲取接口數據

1、每日一句接口

參數 必選 參數 必選
date string 格式爲:2013-05-06;如果date爲空,則默認取當天
type string 可選值爲last和next;以date日期爲準的,last返回前一天的,next返回後一天的

返回類型:JSON
JSON字段解釋:

屬性名 屬性值類型 說明
sid string 每日一句ID
tts string 音頻地址
content string 英文內容
note string 中文內容
love string 每日一句喜歡個數
translation string 詞霸小編
picture string 圖片地址
picture2 string 大圖片地址
caption string 標題
dateline string 時間
s_pv string 瀏覽數
sp_pv string 語音評測瀏覽數
tags array 相關標籤
fenxiang_img string 合成圖片,建議分享微博用的

返回示例:

{
    "sid": "3369",
    "tts": "http://news.iciba.com/admin/tts/2019-04-23-day.mp3",
    "content": "There is no such thing as a great talent without great will.",
    "note": "沒有偉大的意志力,便沒有雄才大略。",
    "love": "197",
    "translation": "小編的話:正如愛迪生所說一般,強者容易堅強。只有堅強的意志力才能給我們克服各種困難的勇氣和決心。",
    "picture": "http://cdn.iciba.com/news/word/20190423.jpg",
    "picture2": "http://cdn.iciba.com/news/word/big_20190423b.jpg",
    "caption": "詞霸每日一句",
    "dateline": "2019-04-23",
    "s_pv": "0",
    "sp_pv": "0",
    "tags": [
        {
            "id": null,
            "name": null
        }
    ],
    "fenxiang_img": "http://cdn.iciba.com/web/news/longweibo/imag/2019-04-23.jpg"
}

請求示例:

type sentence struct {
	Content     string `json:"content"`
	Note        string `json:"note"`
	Translation string `json:"translation"`
}

func getsen() (sentence, string) {
	resp, err := http.Get("http://open.iciba.com/dsapi/?date")
	sent := sentence{}
	if err != nil {
		fmt.Println("獲取每日一句失敗", err)
		return sent, ""
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("讀取內容失敗", err)
		return sent, ""
	}

	err = json.Unmarshal(body, &sent)
	if err != nil {
		fmt.Println("每日一句解析json失敗")
		return sent, ""
	}
	fenxiangurl := gjson.Get(string(body), "fenxiang_img").String()
	fmt.Println(sent)
	return sent, fenxiangurl
}

這裏使用了golang自帶的http包發起了一次get請求,然後將返回的json數據解析出來,另外使用了gjon這個包,該包可以直接從json字符串中解析出需要的字段,十分方便。(其實這段代碼我偷了個懶,如果內部有錯誤應該將錯誤return出去,大家不要學我啊 ~~o(>_<)o ~~)

2、獲取天氣預報接口

調用地址: https://www.tianqiapi.com/api
請求方式:GET
請求參數:

參數 必選 類型 說明
version string v1(版本標識)
cityid 以下參數3選1 string 101120201(城市編號,不要帶CN, 以下參數3選1)
city 3選1 string 青島(城市名稱,不要帶市和區)
ip 3選1 string 27.193.XX.XXX(IP地址)
callback string jsonp方式

返回類型:JSON
返回示例:

{
    "cityid": "101120201",
    "update_time": "2019-04-24 18:00:00",
    "city": "青島",
    "cityEn": "qingdao",
    "country": "中國",
    "countryEn": "China",
    "data": [
        {
            "day": "24日(今天)",
            "date": "2019-04-24",
            "week": "星期三",
            "wea": "陣雨",
            "wea_img": "lei",
            "air": 45,
            "humidity": 96,
            "air_level": "優",
            "air_tips": "空氣很好,可以外出活動,呼吸新鮮空氣,擁抱大自然!",
            "alarm": {
                "alarm_type": "大霧",
                "alarm_level": "橙色",
                "alarm_content": "青島市氣象臺2019年04月24日02時15分繼續發佈大霧橙色預警信號:目前我市沿海地區和近海海域已出現能見度小於200米局部小於100米的大霧,預計今天凌晨到白天,我市沿海地區和近海海域仍將有能見度小於200米的大霧天氣,局部小於100米,請注意防範。(預警信息來源:國家預警信息發佈中心)"
            },
            "tem1": "16℃",
            "tem2": "10℃",
            "tem": "13℃",
            "win": [
                "南風"
            ],
            "win_speed": "3-4級",
            "hours": [
                {
                    "day": "24日20時",
                    "wea": "晴",
                    "tem": "13℃",
                    "win": "南風",
                    "win_speed": "<3級"
                },
                {
                    "day": "24日23時",
                    "wea": "多雲",
                    "tem": "15℃",
                    "win": "南風",
                    "win_speed": "<3級"
                },
                {
                    "day": "25日02時",
                    "wea": "多雲",
                    "tem": "15℃",
                    "win": "南風",
                    "win_speed": "<3級"
                },
                {
                    "day": "25日05時",
                    "wea": "多雲",
                    "tem": "15℃",
                    "win": "南風",
                    "win_speed": "<3級"
                }
            ],
            "index": [
                {
                    "title": "紫外線指數",
                    "level": "最弱",
                    "desc": "輻射弱,塗擦SPF8-12防曬護膚品。"
                },
                {
                    "title": "減肥指數",
                    "level": null,
                    "desc": "天氣較舒適,減肥正當時。"
                },
                {
                    "title": "健臻·血糖指數",
                    "level": "較易波動",
                    "desc": "血糖較易波動,注意監測。"
                },
                {
                    "title": "穿衣指數",
                    "level": "較冷",
                    "desc": "建議着厚外套加毛衣等服裝。"
                },
                {
                    "title": "洗車指數",
                    "level": "不宜",
                    "desc": "有雨,雨水和泥水會弄髒愛車。"
                },
                {
                    "title": "空氣污染擴散指數",
                    "level": "中",
                    "desc": "易感人羣應適當減少室外活動。"
                }
            ]
        }
    ]
}

該接口會返回往後一週的天氣預報,因爲返回的參數過多,我只截取了當天的數據。如果需要其它數據可以自己請求一下。

請求示例代碼:

func getweather(city string) (string, string, string, string) {
	url := fmt.Sprintf("https://www.tianqiapi.com/api?version=%s&city=%s", WeatherVersion, city)
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("獲取天氣失敗", err)
		return "", "", "", ""
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("讀取內容失敗", err)
		return "", "", "", ""
	}

	data := gjson.Get(string(body), "data").Array()
	thisday := data[0].String()
	day := gjson.Get(thisday, "day").Str 	//日期
	wea := gjson.Get(thisday, "wea").Str	//天氣
	tem := gjson.Get(thisday, "tem").Str	//平均氣溫
	air_tips := gjson.Get(thisday, "air_tips").Str		//提示
	return day, wea, tem, air_tips
}

get請求獲得天氣數據,gjson包將當天的天氣信息解析出來後返回。同樣地,偷懶錯誤沒return出去 ?。

二、微信公衆平臺接口測試帳號

通過上一步我們已經成功的獲取到了數據,接下來申請一個微信公衆平臺測試帳號,其實正式帳號的操作也是一樣的,但方便起見,我們直接用測試號。

1、每日一句模板

1、掃碼登錄公衆平臺測試號
申請測試號的地址 https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
2、手機上確認登錄
3、找到 新增測試模板 ,添加模板消息
在這裏插入圖片描述
填寫模板標題 《每日一句》,填寫如下模板內容

{{content.DATA}}
{{note.DATA}}
{{translation.DATA}}

注意:後面的.DATA必須保留,前面是你定義的字段。
在這裏插入圖片描述
提交保存之後,記住該模板ID,一會兒會用到
在這裏插入圖片描述
4、找到測試號信息,記住 appid 和 appsecret,一會兒會用到
在這裏插入圖片描述
5、找到測試號二維碼。手機掃描此二維碼,關注之後,你的暱稱會出現在右側列表裏,記住該微信號,一會兒會用到(注:此微信號非你真實的微信號,而是你的微信在關注了該測試號後分配的在該號下的唯一ID)
在這裏插入圖片描述

2、天氣預報模板

和每日一句的添加方法一樣,區別在於第3步中新增測試模板使用的模板不同:

{{city.DATA}}
{{day.DATA}}
{{wea.DATA}}
{{tem1.DATA}}
{{air_tips.DATA}}

在這裏插入圖片描述

三、發送微信模板消息的程序

//發送每日一句,將json字符串拼接好後調用templatepost函數發送模板
func everydaysen() {
	req, fxurl := getsen()
	if req.Content == "" {
		return
	}
	access_token := getaccesstoken()
	if access_token == "" {
		return
	}

	flist := getflist(access_token)  //獲取公衆號關注人列表
	if flist == nil {
		return
	}

	reqdata := "{\"content\":{\"value\":\"" + req.Content + "\", \"color\":\"#0000CD\"}, \"note\":{\"value\":\"" + req.Note + "\"}, \"translation\":{\"value\":\"" + req.Translation + "\"}}"
	for _, v := range flist {
		templatepost(access_token, reqdata, fxurl, SentTemplateID, v.Str)
	}
}

//發送天氣預報
func weather() {
	access_token := getaccesstoken()
	if access_token == "" {
		return
	}

	flist := getflist(access_token)
	if flist == nil {
		return
	}

	var city string
	for _, v := range flist {
		switch v.Str {
		case "oeZ6P5kyGsLKn3sIGRVfpb8oT4mg":
			city = "青島"
			go sendweather(access_token, city, v.Str)
		case "oeZ6P5jvFNh2y_h_2UcaoTXBaC2o":
			city = "西安"
			go sendweather(access_token, city, v.Str)
		default:
		}
	}
	fmt.Println("weather is ok")
}

//獲取微信accesstoken
func getaccesstoken() string {
	url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%v&secret=%v", APPID, APPSECRET)
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("獲取微信token失敗", err)
		return ""
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("微信token讀取失敗", err)
		return ""
	}

	token := token{}
	err = json.Unmarshal(body, &token)
	if err != nil {
		fmt.Println("微信token解析json失敗", err)
		return ""
	}

	return token.AccessToken
}

//獲取關注人列表
func getflist(access_token string) []gjson.Result {
	url := "https://api.weixin.qq.com/cgi-bin/user/get?access_token=" + access_token + "&next_openid="
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("獲取關注列表失敗", err)
		return nil
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("讀取內容失敗", err)
		return nil
	}
	flist := gjson.Get(string(body), "data.openid").Array()
	return flist
}

//發送模板消息代碼
func templatepost(access_token string, reqdata string, fxurl string, templateid string, openid string) {
	url := "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + access_token

	reqbody := "{\"touser\":\"" + openid + "\", \"template_id\":\"" + templateid + "\", \"url\":\"" + fxurl + "\", \"data\": " + reqdata + "}"

	resp, err := http.Post(url,
		"application/x-www-form-urlencoded",
		strings.NewReader(string(reqbody)))
	if err != nil {
		fmt.Println(err)
		return
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(string(body))
}

//拼接json字符串,調用templatepost函數發送天氣模板
func sendweather(access_token, city, openid string) {
	day, wea, tem, air_tips := getweather(city)
	if day == "" || wea == "" || tem == ""|| air_tips == "" {
		return
	}
	reqdata := "{\"city\":{\"value\":\"城市:" + city + "\", \"color\":\"#0000CD\"}, \"day\":{\"value\":\"" + day + "\"}, \"wea\":{\"value\":\"天氣:" + wea + "\"}, \"tem1\":{\"value\":\"平均溫度:" + tem + "\"}, \"air_tips\":{\"value\":\"tips:" + air_tips + "\"}}"
	//fmt.Println(reqdata)
	templatepost(access_token, reqdata, "", WeatTemplateID, openid)
}

在發送模板消息之前要先獲取微信 accesstoken 和 關注人列表 ,再遍歷所有關注人,給每位關注人發模板消息,或者給某位特定的人發送。

四、設置定時發送

func main() {
	spec := "0 0 12 * * *" // 每天12:00
	spec1 := "0 0 7 * * *" // 每天早晨7:00
	c := cron.New()
	c.AddFunc(spec, everydaysen)
	c.AddFunc(spec1, weather)
	c.Start()
	fmt.Println("開啓定時任務")
	select {}
	//weather()
	//everydaysen()
}

使用了 github.com/robfig/cron 包的定時任務,使每天早晨7點和中午12點發送天氣預報和每日一句。

spec := “0 0 12 * * *”
這裏對應的分別是 “ 秒 分 時 日 月 周 ” 和linux裏的crontab定時任務差不多。

在阿里雲Linux服務器上後臺啓動該程序既可。

程序運行結果截圖:
在這裏插入圖片描述
完整的項目代碼:https://github.com/qq737310694/WechatTemplate
————————————————
版權聲明:本文爲CSDN博主「我是要成爲大神的男人」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/u012140251/article/details/89529540

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章