My Note

自己理解のためのブログ

金とプラチナの価格をGoとMackerelで可視化する

はじめに

今回は、Goでスクレイピングして金とプラチナの価格をMackerelで可視化します。

yhidetoshi.hatenablog.com こちらと同様にMackerelを使った可視化です。

前から金の積立をしているので価格が気になるのもあり、Mackerelでグラフ化しておきたいなー。という気持ちで。

前回、goqueryを使ってスクレイピングしたときの記事はこちらです。

yhidetoshi.hatenablog.com

アーキテクチャ

f:id:yhidetoshi:20190919182645p:plain

  1. CloudWatch EventでLambdaを定期実行
  2. Lmabda ( Go ) でサイトにスクレイピングでデータを取得
  3. Lambda ( Go ) でMackerelにメトリクスを投げる

Lambda ( Go )について

LambdaにはサイトをスクレイピングしてMackerelにメトリクスをPostする処理を定義して CloudWatch Eventを連携させます。Lambda関数やCloudwatchEventなどはServerlessFrameworkを利用してデプロイしました。

スクレイピングgoquery を利用しました。

godoc.org

*) Go: 1.12.4

  • main.go
package main

import (
    "fmt"
    "os"
    "strconv"
    "strings"
    "time"

    "github.com/PuerkitoBio/goquery"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/mackerelio/mackerel-client-go"
)

var (
    targetUrl = "https://gold.tanaka.co.jp/commodity/souba/index.php"
    mkrKey    = os.Getenv("MKRKEY")
    client    = mackerel.NewClient(mkrKey)
)

const (
    serviceName = "Metal"
    timezone    = "Asia/Tokyo"
    offset      = 9 * 60 * 60
)

func main() {
    lambda.Start(Handler)
}

// func main() {
func Handler() {
    var goldRetailTax, goldPurchaseTax, platinumRetailTax, platinumPurchaseTax string

    doc, err := goquery.NewDocument(targetUrl)
    if err != nil {
        fmt.Println(err)
    }

    // Fetch gold and platinum price
    doc.Find("#metal_price_sp").Each(func(_ int, s *goquery.Selection) {
        // Gold
        goldRetailTax = s.Children().Find("td.retail_tax").First().Text()
        goldPurchaseTax = s.Children().Find("td.purchase_tax").First().Text()
        // Platinum
        platinumRetailTax = s.Children().Find("td.retail_tax").Eq(1).Text()
        platinumPurchaseTax = s.Children().Find("td.purchase_tax").Eq(1).Text()
    })

    // Format
    strGoldRetailTax := strings.Replace(goldRetailTax[0:5], ",", "", -1)
    strGoldPurchaseTax := strings.Replace(goldPurchaseTax[0:5], ",", "", -1)
    strPlatinumRetailTax := strings.Replace(platinumRetailTax[0:5], ",", "", -1)
    strPlatinumPurchaseTax := strings.Replace(platinumPurchaseTax[0:5], ",", "", -1)

    // Convert string to int
    intGoldRetailTax, _ := strconv.Atoi(strGoldRetailTax)
    intGoldPurchaseTax, _ := strconv.Atoi(strGoldPurchaseTax)
    intPlatinumRetailTax, _ := strconv.Atoi(strPlatinumRetailTax)
    intPlatinumPurchaseTax, _ := strconv.Atoi(strPlatinumPurchaseTax)

    jst := time.FixedZone(timezone, offset)
    nowTime := time.Now().In(jst)

    mkrErr := PostValuesToMackerel(intGoldRetailTax, intGoldPurchaseTax, intPlatinumRetailTax, intPlatinumPurchaseTax, nowTime)
    if mkrErr != nil {
        fmt.Println(mkrErr)
    }
}

// PostValuesToMackerel Post Metrics to Mackerel
func PostValuesToMackerel(goldRetailTax int, goldPurchaseTax int, platinumRetailTax int, platinumPurchaseTax int, nowTime time.Time) error {
    // Post Gold metrics
    errGold := client.PostServiceMetricValues(serviceName, []*mackerel.MetricValue{
        &mackerel.MetricValue{
            Name:  "Gold.retail_tax",
            Time:  nowTime.Unix(),
            Value: goldRetailTax,
        },
        {
            Name:  "Gold.purchase_tax",
            Time:  nowTime.Unix(),
            Value: goldPurchaseTax,
        },
    })
    if errGold != nil {
        fmt.Println(errGold)
    }

    // Post Platinum metrics
    errPlatinum := client.PostServiceMetricValues(serviceName, []*mackerel.MetricValue{
        &mackerel.MetricValue{
            Name:  "Platinum.retail_tax",
            Time:  nowTime.Unix(),
            Value: platinumRetailTax,
        },
        {
            Name:  "Platinum.purchase_tax",
            Time:  nowTime.Unix(),
            Value: platinumPurchaseTax,
        },
    })
    if errPlatinum != nil {
        fmt.Println(errPlatinum)
    }

    return nil
}

デプロイ

  • Mackerelにサービスを登録する
export MKRKEY=XXX

curl -X POST https://api.mackerelio.com/api/v0/services \
    -H "X-Api-Key: ${MKRKEY}" \
    -H "Content-Type: application/json" \
    -d '{"name": "Metal", "memo": "metal"}'
make build
  • ServerlessFrameworkでデプロイする
sls deploy --aws-profile <PROFILE> --mkrkey ${MKRKEY}

ソースコード等はこちらにおいています。 ( Makefileや ServelessFrameworkのyamlファイルなども置いています )

github.com

結果 ( Mackerelの画面 )

f:id:yhidetoshi:20190919183157p:plain

さいごに

今回はGoで貴金属の価格が掲載されているサイトをgoqueryを利用してスクレイピングし、MackerelにメトリクスをPostすることで可視化しました。 次はこの貴金属の価格をjsonで返すAPIをGoで作りたいと思います。