Dari parser poster teater Python ke bot Telegram. Bagian 2



Kami melanjutkan kisah pengembangan bot Telegram untuk pencarian tiket - HappyTicketsBot, awal dapat ditemukan di bagian pertama .

Di bagian kedua saya akan berbicara tentang bot itu sendiri, membagikan kodenya, serta ide-ide yang kemungkinan besar tidak menjadi kenyataan. Sebagian besar fungsi pada saat bot dibuat sudah ditulis dalam format skrip, jadi tugas utamanya adalah membuat antarmuka interaksi pengguna melalui Telegram-messenger. Ternyata tidak begitu boltologis seperti pada bagian 1, jadi perhatian banyak kode.

Spoiler: HappyTicketsBot tidak terbang untuk menghidupkan server asing, itu lokal dan Rusia, tetapi suatu hari (saya percaya) itu akan mulai =)

PEMBARUAN: Setelah bot dibagikan di antara publik teater, mereka menulisnya di media. Banjir pengguna melonjak tajam. Setelah beberapa hari permainan, "ambil segera, bagaimana itu jatuh" bot itu terbang ke server dan mengalami sejumlah perbaikan. Saya puas =)

1. Mulai dari awal


Karena tidak ada kata sama sekali dalam merancang bot Telegram, saya harus mulai dengan artikel dasar dan tutorial, yang sangat banyak di jaringan. Ya, ngomong-ngomong, apa back-end pada waktu itu, saya juga buruk membayangkan)) Himpunan pelajaran ini menjadi yang paling informatif dan diterapkan. Modul yang berinteraksi dengan Telegram adalah pyTelegramBotAPI ( github ).

Yang paling lama mengambil perkembangan ideologi dekorator, baca tentang mereka di artikel ini . Ada dua bagian dan sangat bisa dimengerti.

2. Skrip untuk interaksi bot dengan pengguna. Pencarian dasar


Seperti yang sudah disebutkan dalam kata pengantar dan bagian 1 artikel , hampir semua kode parsing sudah siap. Tetap mengubah metode pengaturan parameter pencarian. Berdasarkan ini, skrip perilaku bot dibangun. Perintah yang tersedia untuk pengguna terbatas pada set berikut:

  • / Temukan - mulai pencarian baru,
  • / Reset - mengatur ulang parameter pencarian dan memulai yang baru,
  • / LastSearch - mengembalikan hasil menggunakan parameter dari permintaan terakhir,
  • / addURL tambahkan URL kinerja untuk melacak penurunan harga,
  • / checkURL - memperbarui harga untuk pertunjukan yang menarik,
  • / showURL - daftarkan semua URL yang ditambahkan ke daftar minat

Menurut skrip pencarian dasar / cari, pengguna berpindah dari satu status ke status lainnya, secara berurutan memasukkan data yang diperlukan untuk filter. Setelah memasukkan parameter terakhir - tempat presentasi - poster diuraikan secara langsung menggunakan kamus yang dideklarasikan secara global, di mana kuncinya adalah ID pengguna, dan nilainya adalah parameter pencarian yang dimasukkan.

Untuk mengingat keadaan pengguna, mereka disimpan dalam database. Untuk bekerja dengannya, modul Vedis (konfigurator basis data nilai-kunci, baca dokumentasi ) dan Enum (bekerja dengan enumerasi, perincian 1 , 2 ) digunakan.

Dalam file konfigurasi terpisah Myconfig.py, kami menetapkan parameter bot (termasuk token unik yang diterima dari Telegram) dan mencantumkan status yang dapat digunakan pengguna. Mereka keluar sedikit.

from enum import Enum token = "4225555:AAGmfghjuGOI4sdfsdfs5656sdfsdf_c" # ,   (  ) db_file = "Mydatabase.vdb" class States(Enum): """   Vedis    ,        (str) """ S_START = "0" #    S_ENTER_MONTH = "1" S_ENTER_PRICE = "2" S_ENTER_TYPE = "3" S_ENTER_PLACE = "4" S_ENTER_URL="5" #       

Akibatnya, kami mendapatkan rantai transisi status langsung dari satu ke yang lain.



Untuk penyimpanan kami menggunakan basis data Veda. Inisialisasi pengguna yang mengirim pesan selalu dilakukan melalui message.chat.id.

Kode file dbwoker.py, yang menjelaskan interaksi dengan database
 from vedis import Vedis import Myconfig as config #      def get_current_state(user_id): with Vedis(config.db_file) as db: try: return db[user_id] except KeyError: #  /     return config.States.S_START.value #  -  #       def set_state(user_id, value): with Vedis(config.db_file) as db: try: db[user_id] = value return True except: print('  !') #   -   return False 


Di bawah ini adalah contoh dari pawang yang diaktifkan oleh perintah / find. Seperti yang Anda lihat, dalam contoh ini tidak ada entri data - hanya ada perubahan status menjadi "S_ENTER_MONTH". Setelah melihat pesan tentang memasukkan nomor, pengguna memasukkannya dan mengirim pesan. Setelah menerima pesan dengan status S_ENTER_MONTH, langkah selanjutnya dimulai. Dalam hal terjadi kesalahan input, status tidak berubah.

  #   @bot.message_handler(commands=["find"]) def cmd_find(message): state = dbworker.get_current_state(message.chat.id) """    ,         .     .    ,           """ if state == config.States.S_ENTER_MONTH.value: bot.send_message(message.chat.id, "    .   ") elif state == config.States.S_ENTER_PRICE.value: bot.send_message(message.chat.id, "      ,   ") elif state == config.States.S_ENTER_TYPE.value: bot.send_message(message.chat.id, ", -    ,       :( ...") else: #  ""   "0" -   bot.send_message(message.chat.id, "      ") dbworker.set_state(message.chat.id, config.States.S_ENTER_MONTH.value) #   

Jika bot menerima pesan dari pengguna dengan status S_ENTER_MONTH, maka penangan berikut diluncurkan. Secara ideologis, ini juga terjadi pada tahap lain dari skrip pencarian dasar.

 @bot.message_handler(func=lambda message: dbworker.get_current_state(message.chat.id) == config.States.S_ENTER_MONTH.value) def user_entering_month(message): if not message.text.isdigit(): bot.send_message(message.chat.id, ",    ") return # 1 num[message.chat.id]=message.text #  if int(num[message.chat.id])>12 or int(num[message.chat.id])<1: bot.send_message(message.chat.id, "     1  12.   ") # 2 return url_list[message.chat.id]=take_url(num[message.chat.id]) #  URL-   if url_list[message.chat.id]==[]: #    bot.send_message(message.chat.id, " ,     .     ") return bot.send_message(message.chat.id, "!      .") dbworker.set_state(message.chat.id, config.States.S_ENTER_PRICE.value) #     

Selain pencarian standar, dimungkinkan untuk menyimpan kinerja yang menarik.

3. Pelacakan perubahan harga


Pengguna dapat menambahkan URL ke daftar minat untuk menerima peringatan ketika harga turun. Kami ingat bahwa kami masih memiliki status tidak terdaftar dalam pencarian dasar - S_ENTER_URL. Masuk

 @bot.message_handler(commands=["addURL"]) def cmd_add_url(message): bot.send_message(message.chat.id, " url,   .  https://") dbworker.set_state(message.chat.id, config.States.S_ENTER_URL.value) #  @bot.message_handler(func=lambda message: dbworker.get_current_state(message.chat.id) == config.States.S_ENTER_URL.value) def user_entering_URL(message): perf_url=message.text user_id=message.chat.id try: add_new_URL(user_id,perf_url) bot.send_message(message.chat.id, '    !') dbworker.set_state(message.chat.id, config.States.S_START.value) #    except: bot.send_message(message.chat.id, 'URL !    !') dbworker.set_state(message.chat.id, config.States.S_ENTER_URL.value) 

Untuk menyimpan daftar, gunakan file .csv. Untuk berinteraksi dengannya, Anda memerlukan beberapa fungsi - menulis dan membaca dengan verifikasi perubahan harga. Jika berubah, beri tahu pengguna.

  def add_new_URL(user_id,perf_url): WAITING_FILE = "waiting_list.csv" with open(WAITING_FILE, "a", newline="") as file: curent_url='https://'+perf_url text=get_text(curent_url) #   1   minPrice, name,date,typ,place=find_lowest(text) user = [str(user_id), perf_url,str(minPrice)] writer = csv.writer(file) writer.writerow(user) 

Kode fungsi pembaruan harga sedikit lebih lama
 def update_prices(bot): WAITING_FILE = "waiting_list.csv" with open(WAITING_FILE, "r", newline="") as file: reader = csv.reader(file) waitingList=[] for row in reader: waitingList.append(list(row)) L=len(waitingList) lowest={} with open(WAITING_FILE, "w", newline="") as fl: writer = csv.writer(fl) for i in range(L): lowest[waitingList[i][1]]=waitingList[i][2] #   URL  for k in lowest.keys(): text=get_text('https://'+k) minPrice, name,date,typ,place=find_lowest(text) #    1   if minPrice==0: #   minPrice=100000 if int(minPrice)<int(lowest[k]): #   ,    lowest[k]=minPrice #    for i in range(L): if waitingList[i][1]==k: #  -  URL   waitingList[i][2]=str(minPrice) #  bot.send_message(int(gen[i][0]),'   '+k+'    '+str(minPrice)) writer.writerows(waitingList) #     .    ... ... 


Akibatnya, dengan perintah / checkURL, pengguna dapat memperoleh hasil seperti itu (sekarang saya mengerti bahwa perlu juga untuk menampilkan nama kinerja, tetapi ini adalah hal-hal dari seri โ€œtidak mencapai tanganโ€).



Baik, baik. Kami dapat mencari, kami dapat melacak. Beberapa teman mulai menggunakan bot, saya ingin mencari tahu siapa mereka dan apa yang mereka cari. Informasi ini baik untuk ditulis dalam log.

4. Kami menulis aktivitas dan kesalahan dalam log


Modul Logging akan membantu kami dalam hal ini. Informasi dicatat hanya pada tahap menyelesaikan pencarian dasar, di handler, di mana status pengguna beralih dari S_ENTER_PLACE ke S_START. Perekaman kesalahan, pada gilirannya, terjadi ketika mereka terjadi.

Saya tidak bisa mengatakan banyak tentang cara kerja modul, jadi lebih baik beralih ke informasi di luar .



Deskripsi Pencatat
 def save_logs(str): loggerInfo.info(str) #    logging.basicConfig(format = u'%(levelname)-8s [%(asctime)s] %(message)s', level = logging.ERROR, filename = u'loggerErrors.log') global loggerInfo loggerInfo = logging.getLogger(__name__) loggerInfo.setLevel(logging.INFO) handler = logging.FileHandler('loggerUsers.log') handler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) loggerInfo.addHandler(handler) log = logging.getLogger("ex") 


Karena koneksi terputus, bot secara berkala crash, sehingga kesalahan koneksi Internet tertangkap dan bot restart secara otomatis setelah 10 detik. Tapi itu tidak selalu menyelamatkan, jadi saya terus menjalankan TeamViewer, untuk meningkatkannya jika perlu.

5. Belum direalisasi


Kami mendapat bot yang menggantikan fungsi skrip, tetapi memungkinkan Anda untuk menerima informasi dalam bentuk yang nyaman di dalam messenger. Dia menutup kebutuhan dasar saya.

Pembongkaran dengan modul dan penulisan penangan ramping berlangsung sekitar satu bulan dalam mode kerja pada akhir pekan dan kadang-kadang di malam hari. Pada akhir periode ini, minat mulai memudar dan fungsionalitas macet di titik awal. Tidak mungkin untuk menerobos prinsip-prinsip bekerja di webhook-ahs, dan kemudian Telegram diblokir. Sebelum itu, ada rencana untuk menarik back-end ke server yang berfungsi, tapi ... vpn tidak akan dimasukkan ke sana untuk ini =)

Berikut adalah apa yang tersisa dalam rencana, beberapa di antaranya dapat dan akan direalisasikan sekali pada musim panas / musim dingin yang lesu:

  • uji beban dengan aliran pengguna yang besar. Belum jelas apakah bot akan bekerja secara stabil dan tidak membingungkan pengguna;
  • pemberitahuan penampilan pertunjukan baru dalam jadwal artis. Saya punya banyak "kelinci putih" favorit, saya tidak bisa melacak semua orang (tapi saya ingin);
  • Pemberitahuan penampilan pada penjualan tiket dari kategori tertentu. Ada seorang kenalan, seorang amatir dari deretan pertama kios, yang sulit ditangkap secara manual;
  • pengecekan otomatis URL yang diminati secara otomatis untuk pengurangan harga berdasarkan penghitung waktu. Sekarang ini dilakukan atas perintah, timer tidak dapat diatur dengan cepat, sehingga dibiarkan dengan cara yang sederhana;
  • pelestarian sejarah kunjungannya ke pertunjukan. Di suatu tempat di file .csv, cantumkan tanggal-nama-line-dari-artis-komentar Anda agar tidak hilang;
  • mencari kategori tiket tertentu. Tetapkan tidak hanya harga, tetapi juga sektor (lantai dasar, dll.);
  • mentransfer semuanya menjadi keterampilan untuk Alice. kenapa tidak
  • membuat aplikasi seluler dengan fungsi yang sama. kenapa tidak

Ada telepon di Teater Bolshoi. Untuk mendapatkan tiket Nureyev, tapi saya tidak bisa mengambil poster html di dua malam, jadi itu juga menunda daftar yang belum direalisasi.

TOTAL


Kemalasan adalah mesin kemajuan, dan itu menghentikannya. Hal-hal yang tidak terjadi saat mengunggah bot ke server pihak ketiga, namun hal ini membutuhkan kompetensi dan pengetahuan yang lebih luas di bidang Web. Proyek ini ternyata menarik dan memungkinkan kami untuk belajar Python sedikit lebih baik, melihat segi lain dari itu (selain pembelajaran Mesin biasa), dan juga menyajikan banyak malam yang indah di teater dengan harga murah. Berkat dia untuk ini, dia menutup tugas dengan keras.

Tidak peduli bagaimana saya mencoba, artikel itu masih mendapat banyak kode dan sedikit teks. Saya akan dengan senang hati menjelaskan hal-hal yang tidak dapat dipahami atau dijelaskan dalam komentar =)

Source: https://habr.com/ru/post/id445632/


All Articles