自动收集优惠券以获取免费文献

背景


在升时,存在以令人羡慕的规律性出现的奖金和优惠券系统。为了使妻子高兴,总的来说,他可以为自己找到一本有趣的书,他开始监视出现新优惠券的地点,然后将其放入电报中。但是几天后,我对这项业务感到厌倦,因此决定自动执行此过程,以便任何需要它的人都可以使用。


实作


由于我不断在电报中发布新的优惠券,并且总的来说,我喜欢这个工具,因此,我决定创建另一个电报自动程序,只要已经为其创建了足够的库即可。以golangtelegram-bot-api作为语言。我们还需要选择一种从中获取信息的资源,我想到了几个站点,并考虑编写一个整体的通用解析器,但是到了某个时候,我变得很懒惰,因此我决定选择一种资源为了即使重新启动后也可以存储优惠券,我决定使用一个简单的sqlite3数据库。我们将在其中存储有关优惠券的信息,以及在电报bot中有关注册用户的信息,以及有关用户已经收到和尚未收到哪些优惠券的信息。


看起来像这样


图片


网站解析


站点的解析将由goquery库完成-它的工作方式与jquery大致相同。
使用goquery.Document结构 html . , , . . unixtime, . , , . , , js .


Telegram bot


BotFather , telegram . telegram api , http websocket. , telegram-bot-api updater .


type SNBot struct {
    cfg *Config
    bot *tgbotapi.BotAPI
    upd tgbotapi.UpdatesChannel
}

func New(cfg *Config) (*SNBot, error) {
    bot, err := tgbotapi.NewBotAPI(cfg.Token)
    if err != nil {
        return nil, err
    }
    level.Info(cfg.Logger).Log("msg", "Authorized on account", "bot-name", bot.Self.UserName)
    u := tgbotapi.NewUpdate(0)
    u.Timeout = cfg.UpdateTime
    updates, err := bot.GetUpdatesChan(u)
    if err != nil {
        return nil, err
    }
    return &SNBot{
        cfg: cfg,
        bot: bot,
        upd: updates,
    }, nil
}

, , gocron. task gocron storage storage .


Task function
func task(bot *snbot.SNBot, s *storage.Storage, c *collector.Collector, logger kitlog.Logger) {
    c.Collect(collector.ConditionQuery{
        URI: "https://lovikod.ru/knigi/promokody-litres",
    })
    chats, err := s.GetChat()
    if err != nil {
        level.Error(logger).Log("msg", "failed get chats", "err", err)
    }
    for _, id := range chats {
        records, err := s.GetNotUseCoupon(id)
        if err != nil {
            level.Error(logger).Log("msg", "failed get coupons", "err", err)
            return
        }
        var msg string
        for i, rec := range records {
            msg = fmt.Sprintf("%v%v:\t%s \n--->: %s\n : %v\n: %s\n\n", msg, i+1, rec.Link, rec.Code, time.Unix(rec.Date, 0).Format("02.01.2006"), rec.Description)
        }
        if len(msg) != 0 {
            err = bot.Send(id, msg)
            if err != nil {
                level.Error(logger).Log("msg", "failed send message", "err", err)
                continue
            }
            err = s.MarkAsRead(id, records)
            if err != nil {
                level.Error(logger).Log("msg", "failed marked as read", "err", err)
                continue
            }
        }
    }
    level.Info(logger).Log("msg", "send all chats new coupons")
}

- , , , .

func (s *SNBot) Send(chatID int64, msg string) error {
    level.Error(s.cfg.Logger).Log("msg", "try send", "chatID", chatID)
    var numericKeyboard = tgbotapi.NewReplyKeyboard(
        tgbotapi.NewKeyboardButtonRow(
            tgbotapi.NewKeyboardButton("/print5"),
        ),
    )
    m := tgbotapi.NewMessage(chatID, msg)
    m.ReplyMarkup = numericKeyboard
    _, err := s.bot.Send(m)
    if err != nil {
        if err.Error() == errBlockedByUser {
            s.cfg.Storage.UpdChatActivity(chatID, false)
        }
        return err
    }
    return nil
}

  Dockerfile


,   .


# build binary
FROM golang:1.10.3-alpine3.8 AS build
RUN apk add --no-cache linux-headers gcc g++
ARG VERSION=dev
WORKDIR /go/src/github.com/wenkaler/xfreehack
COPY . /go/src/github.com/wenkaler/xfreehack
RUN CGO_ENABLED=1 go build \
    -o /out/xfree \
    -ldflags "-X main.serviceVersion=$VERSION" \
    github.com/wenkaler/xfreehack/cmd

# copy to alpine image
FROM alpine:3.8
WORKDIR /app
RUN mkdir /db
COPY --from=build /out/xfree /app
RUN apk add --no-cache tzdata
RUN apk --no-cache add ca-certificates
ENV TZ Europe/Moscow
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
CMD ["/app/xfree"]

Systemd


. 2.6, upgrad- systemd. ? — 3.


[Unit]
Description=Xfree service
After=network.target
After=network-online.target

[Service]
ExecStart=/urs/local/bin/xfree
Environment="TELEGRAM_TOKEN=$TELEGRAM_TOKEN" "PATH_DB=/db/xfree.db"
TimeoutSec=30
Restart=on-failure
RestartSec=30

[Install]
WantedBy=multi-user.target


 现在,我的妻子很高兴她可以收到有关LitRes的免费书籍,但我只是想解决这个问题,还有一些可以改进的地方,如果MarkAsRead失败,请添加警告系统(到目前为止,这还没有发生,但您永远不会知道) ,他现在也取消了订阅,不再向未订阅他的人发送消息,您需要在再次按/ start命令后将其恢复为活动状态。好吧,总的来说,可以添加选择分发时间和优惠券的功能,因为该站点不仅具有LiteRes的优惠券。但这一切都是必要的,到目前为止尚未收到此类申请。


参考文献


  1. 项目本身
  2. 优惠券网站
  3. 机器人名称@xFreeCouponBot

All Articles