基金估值通知小助手

基金估值通知小助手

由于经常忘记基金,昨天突发奇想,可以爬取当前估值信息然后利用钉钉机器人+crontab发送通知,效果图

效果图

获取估值信息

首先需要获取估值信息,组装发送的内容的格式

func fundMsg() string {
    result := `
## 基金估值情况

---

`
    c := colly.NewCollector(
        colly.AllowedDomains("fund.eastmoney.com", "fundgz.1234567.com.cn"),
    )

    c.OnRequest(func(r *colly.Request) {
        //fmt.Println("Visiting", r.URL.String())
    })
    c.OnResponse(func(response *colly.Response) {
        res := string(response.Body)
        if len(res) > 10 {
            jsonStr := res[8 : len(res)-2]
            var mapResult map[string]interface{}
            if err := json.Unmarshal([]byte(jsonStr), &mapResult); err != nil {
                fmt.Println(err)
            }
            var inc string
            gszzl := fmt.Sprintf("%s", mapResult["gszzl"])
            if strings.Index(gszzl, "-") == -1 {
                inc = "↑"
            } else {
                inc = "↓"
            }
            result += fmt.Sprintf("* %s(%s)\t%s\t%s\n", mapResult["name"], mapResult["fundcode"], mapResult["gszzl"], inc)
        }
    })

    for _, value := range fundCodes {
        _ = c.Visit("http://fundgz.1234567.com.cn/js/" + value + ".js")
    }
    return result
}

发送钉钉通知

翻了下钉钉开发文档,上面没有go的sdk,不过好在文档比较详细,主要是签名算法的生成比较麻烦 (主要原因是对go不熟悉) ,代码如下:

签名

func sign(timestamp int64) string {
    signStr := strconv.FormatInt(timestamp, 10) + "\n" + secret
    h := hmac.New(sha256.New, []byte(secret))
    h.Write([]byte(signStr))
    return url.QueryEscape(base64.StdEncoding.EncodeToString(h.Sum(nil)))
}

发送通知

这是发送markdown格式的通知,也可以发送其他格式的通知,具体参考钉钉开发文档

func dingTaskNotice(fundInfo func() string) string {
    timestamp := time.Now().UnixNano() / 1e6
    sendUrl := fmt.Sprintf("https://oapi.dingtalk.com/robot/send?access_token=%s&timestamp=%d&sign=%s", accessToken, timestamp, sign(timestamp))
    data := fmt.Sprintf(`{
        "msgtype": "markdown",
        "markdown": {
            "title": "基金估值",
            "text": "%s"
        }
    }`, fundInfo())
    buf := &bytes.Buffer{}
    err := binary.Write(buf, binary.BigEndian, []byte(data))
    if err != nil {
        panic(err)
    }
    res, err := http.Post(sendUrl, "application/json", buf)
    if err != nil {
        panic(err)
    }
    defer res.Body.Close()
    result, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }
    return string(result)
}

部署

打包成可执行文件

$ set GOOS=linux
$ go build

crontab调度

$ chmod +x fund_notice
$ crontab -e 

# 可根据需求修改
*/30 10-15 * * 1-5 /data/jobs/fund_notice
:wq

$ systemctl restart crond.service

完整代码

package main

import (
    "bytes"
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "encoding/binary"
    "encoding/json"
    "fmt"
    "github.com/gocolly/colly"
    "io/ioutil"
    "net/http"
    "net/url"
    "strconv"
    "strings"
    "time"
)

var (
    secret      = "secret"       // 替换
    accessToken = "accessToken"  // 替换
    fundCodes   = []string{
        "162605", "260108", "009898", "110011", "005368", "007824", "110022", "001632",
        "001475", "501019", "001838", "320007", "519674", "002547", "006229", "004851",
        "008086", "000136", "001063", "000408", "501058", "501057", "162703", "001983",
        "161725", "501018", "040025", "005918"}
)

func sign(timestamp int64) string {
    signStr := strconv.FormatInt(timestamp, 10) + "\n" + secret
    h := hmac.New(sha256.New, []byte(secret))
    h.Write([]byte(signStr))
    return url.QueryEscape(base64.StdEncoding.EncodeToString(h.Sum(nil)))
}
func dingTaskNotice(fundInfo func() string) string {
    timestamp := time.Now().UnixNano() / 1e6
    sendUrl := fmt.Sprintf("https://oapi.dingtalk.com/robot/send?access_token=%s&timestamp=%d&sign=%s", accessToken, timestamp, sign(timestamp))
    data := fmt.Sprintf(`{
        "msgtype": "markdown",
        "markdown": {
            "title": "基金估值",
            "text": "%s"
        }
    }`, fundInfo())
    buf := &bytes.Buffer{}
    err := binary.Write(buf, binary.BigEndian, []byte(data))
    if err != nil {
        panic(err)
    }
    res, err := http.Post(sendUrl, "application/json", buf)
    if err != nil {
        panic(err)
    }
    defer res.Body.Close()
    result, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }
    return string(result)
}

func fundMsg() string {
    result := `
## 基金估值情况

---

`
    var funds []map[string]interface{}

    c := colly.NewCollector(
        colly.AllowedDomains("fund.eastmoney.com", "fundgz.1234567.com.cn"),
    )

    c.OnRequest(func(r *colly.Request) {
        //fmt.Println("Visiting", r.URL.String())
    })
    c.OnResponse(func(response *colly.Response) {
        res := string(response.Body)
        if len(res) > 10 {
            jsonStr := res[8 : len(res)-2]
            var mapResult map[string]interface{}
            if err := json.Unmarshal([]byte(jsonStr), &mapResult); err != nil {
                fmt.Println(err)
            }
            funds = append(funds, mapResult)
        }
    })

    for _, value := range fundCodes {
        _ = c.Visit("http://fundgz.1234567.com.cn/js/" + value + ".js")
    }

    sort(funds)
    for _, value := range funds {
        var inc string
        gszzl := fmt.Sprintf("%s", value["gszzl"])
        if strings.Index(gszzl, "-") == -1 {
            inc = "↑"
        } else {
            inc = "↓"
        }
        result += fmt.Sprintf("* %s(%s)\t%s\t%s\n", value["name"], value["fundcode"], value["gszzl"], inc)
    }
    return result
}

func sort(funds []map[string]interface{}) {
    for i, value1 := range funds {
        gszzl1, _ := strconv.ParseFloat(fmt.Sprintf("%s", value1["gszzl"]), 10)
        for j, value2 := range funds {
            gszzl2, _ := strconv.ParseFloat(fmt.Sprintf("%s", value2["gszzl"]), 10)
            if gszzl1 > gszzl2 {
                funds[i], funds[j] = funds[j], funds[i]
            }
        }
    }
}

func main() {
    //fmt.Println(fundMsg())
    fmt.Println(dingTaskNotice(fundMsg))
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值