Mengotomatiskan koleksi kupon untuk literatur gratis

Latar Belakang


Di liter ada sistem bonus dan kupon yang muncul dengan keteraturan yang patut ditiru. Untuk membuat istrinya bahagia, dan secara umum, ia dapat menemukan buku yang menarik untuk dirinya sendiri, ia mulai memantau situs tempat kupon baru muncul dan menjatuhkannya di telegram. Tetapi hanya beberapa hari kemudian saya sudah bosan dengan bisnis ini dan saya memutuskan untuk mengotomatiskan proses ini sehingga bisa tersedia untuk semua orang yang menginginkannya.


Penerapan


Karena saya terus-menerus memasang kupon baru di telegram, dan secara umum saya suka alat ini, saya memutuskan untuk membuat bot lain untuk telegram, selama cukup banyak perpustakaan yang telah dibuat untuknya. Ambil bahasa golang dan perpustakaan telegram-bot-api sebagai bahasa . Kita juga perlu memilih sumber daya untuk menarik informasi, saya memiliki beberapa situs dalam pikiran dan saya berpikir untuk menulis parser universal secara keseluruhan, tetapi pada beberapa titik saya menjadi malas, dan saya memutuskan untuk memilih satu sumber daya. Untuk menyimpan kupon bahkan setelah restart, saya memutuskan untuk menggunakan database sqlite3 sederhana. Kami akan menyimpan informasi tentang kupon di dalamnya, serta informasi tentang pengguna terdaftar di bot telegram, serta informasi tentang kupon mana yang telah diterima pengguna dan mana yang belum.


Itu terlihat seperti ini


gambar


Penguraian situs


Penguraian situs akan dilakukan oleh perpustakaan goquery - kerjanya hampir sama dengan jquery.
Menggunakan struktur 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


 Sekarang istri saya senang bahwa dia dapat menerima buku-buku gratis tentang liter, tetapi saya hanya tertarik untuk menyelesaikan masalah ini. Masih ada sesuatu yang dapat diperbaiki, tambahkan sistem peringatan jika MarkAsRead gagal, (sejauh ini belum terjadi, tetapi Anda tidak pernah tahu) , ia juga sekarang berhenti berlangganan dan tidak lagi mengirim pesan ke orang yang telah berhenti berlangganan darinya dan Anda harus mengembalikannya ke status aktif setelah menekan kembali perintah / mulai. Nah, secara umum, tambahkan kemampuan untuk memilih waktu distribusi dan pilihan kupon, karena situs tidak hanya memiliki kupon dari LiteRes. Tapi ini semua perlu, sejauh ini belum ada aplikasi yang diterima.


Referensi


  1. Proyek itu sendiri
  2. Situs web Kupon
  3. Nama Bot @xFreeCouponBot

All Articles