us-coach-spider/product/controller.go
timerzz dffffd52d7
Some checks failed
Build image / build (push) Failing after 1m13s
feat coach outlet 史低价格时推送
2024-06-19 21:06:25 +08:00

163 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package product
import (
"context"
"fmt"
"gitea.timerzz.com/kedaya_haitao/common/model/product"
coach_client "gitea.timerzz.com/kedaya_haitao/common/pkg/coach-client"
"gitea.timerzz.com/kedaya_haitao/pusher/kitex_gen/push"
"gitea.timerzz.com/kedaya_haitao/pusher/rpc/pusher"
"github.com/golang/glog"
"github.com/samber/lo"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"log/slog"
"time"
)
type Controller struct {
ctx context.Context
client *coach_client.US
updateTime time.Time // 上次抓取时间
db *gorm.DB
calculates []productv1.CalculateProcess
Option
}
func NewController(client *coach_client.US, db *gorm.DB) *Controller {
ctl := &Controller{
client: client,
db: db,
}
ctl.AutoMigrate()
ctl.LoadOption()
ctl.LoadCalculateProcess()
return ctl
}
func (c *Controller) AutoMigrate() {
if err := c.db.AutoMigrate(&productv1.Product{}, &productv1.HistoryPrice{}, &Option{}, &productv1.CalculateProcess{}); err != nil {
panic(err)
}
}
func (c *Controller) Run(ctx context.Context) {
c.ctx = ctx
ticker := time.NewTicker(c.Interval)
if err := c.Crawl(); err != nil {
slog.Error(err.Error())
} else {
slog.Info("抓取信息成功")
c.updateTime = time.Now()
}
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
if err := c.Crawl(); err != nil {
slog.Error(err.Error())
} else {
slog.Info("抓取信息成功")
c.updateTime = time.Now()
}
}
}
}
func (c *Controller) Crawl() error {
slog.Info("开始抓取信息")
for page, totalPage := 1, -1; page <= totalPage || totalPage == -1; page++ {
resp, err := c.client.ViewAllBags(c.ctx, page)
if err != nil {
return fmt.Errorf("访问coach第%d页失败: %w", page, err)
}
totalPage = resp.PageData.TotalPages
if err = c.saveRespData(resp.PageData.Products); err != nil {
return fmt.Errorf("保存第%d页数据失败: %w", page, err)
}
glog.Infof("第%d页数据保存成功", page)
}
return nil
}
func (c *Controller) saveRespData(list []coach_client.Product) error {
var products = make([]productv1.Product, 0, len(list))
for _, resp := range list {
for _, color := range resp.Colors {
price, _ := lo.Find(resp.VariantsOnSale, func(item coach_client.Variant) bool {
return item.Id == color.VgId
})
// 获取已经存的运费和得物价格
var savedProduct productv1.Product
c.db.Model(&savedProduct).Where("pid = ?", color.VgId).Select("freight", "dw_price").Scan(&savedProduct)
if savedProduct.Freight == 0 {
savedProduct.Freight = c.Freight
}
p := productv1.Product{
UpdatedAt: time.Now(),
Name: resp.Name,
Pid: color.VgId,
Color: color.Text,
Link: fmt.Sprintf("%s/%s", "https://www.coachoutlet.com", color.Url),
Image: color.Media.Thumbnail.Src,
Orderable: color.Orderable,
DiscPercent: price.Price.MarkdownDiscPercent,
OriginalPrice: price.Price.Sales.Value,
Freight: savedProduct.Freight,
ExchangeRate: c.ExchangeRate,
DWPrice: savedProduct.DWPrice,
}
var calculate []productv1.CalculateProcess
c.db.Model(&productv1.CalculateProcess{}).Find(&calculate, "pid = ? AND website = ?", color.VgId, productv1.WebSite_US_Coach_Outlet)
p.CalCNY(append(calculate, c.calculates...))
products = append(products, p)
}
}
// 去重
products = lo.UniqBy(products, func(p productv1.Product) string {
return p.Pid
})
if len(products) == 0 {
return nil
}
lo.ForEach(products, func(p productv1.Product, _ int) {
p.CalRate()
if p.Rate >= 15 && p.Orderable {
c.Push("美国coach outlet有收益大于15%的商品", fmt.Sprintf("coach outlet 商品 %s 收益率达到:%.2f%% \n商品名%s\n链接%s", p.Pid, p.Rate, p.Name, p.Link))
return
}
var historyPrice []productv1.HistoryPrice
c.db.Model(&productv1.HistoryPrice{}).Find(&historyPrice, "pid = ?", p.Pid)
if len(historyPrice) > 0 {
lowestPrice := lo.MinBy(historyPrice, func(a productv1.HistoryPrice, b productv1.HistoryPrice) bool {
return a.OriginalPrice < b.OriginalPrice
})
if p.OriginalPrice < lowestPrice.OriginalPrice {
c.Push("美国coach outlet有商品价格史低", fmt.Sprintf("coach outlet 商品 %s 价格为%.2f之前最低价为:%.2f \n商品名%s\n链接%s", p.Pid, p.OriginalPrice, lowestPrice.OriginalPrice, p.Name, p.Link))
}
}
})
return c.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "pid"}},
DoUpdates: clause.AssignmentColumns([]string{"name", "color", "link", "orderable", "original_price", "cny_price", "cal_mark", "rate", "price_status", "disc_percent", "updated_at"}),
}).Create(products).Error
}
func (c *Controller) Push(title, content string) {
resp, err := pusher.Push(c.ctx, &push.PushReq{
Ids: []int64{2},
Title: title,
Content: content,
})
if err != nil {
glog.Errorf("消息推送失败:%v", err)
}
if resp.Code != 0 {
glog.Errorf("消息推送失败:%s", resp.Msg)
}
}