فهرست عناوین

موضوع قبلی

حل مسائل روزانهٔ پایتون

موضوع بعدی

الگوریتم غربالگری اعداد اوّل اراتستن

بازیابی مخاطب‌ها از پیام‌رسان...

پیش‌زمینهٔ مشکل

احتمالاً برای شما و یا اطرافیانتان هم پیش آمده باشد؛ که به خاطر خرابی و یا گم کردن تلفن همراه و نداشتن پشتیبان، همهٔ لیست مخاطب‌هایی را که داشته‌اید را از دست رفته ببینید.

چند وقت پیش‌تر، یکی از اطرافیان -که خیلی خاطرش هم عزیز بود- برای بازیابی فهرست مخاطب‌های تلفن هوشمندش از من کمک خواست. در اصل ماجرا از این قرار بود که به طور تصادفی به جای حذف یکی از مخاطب‌ها؛ همهٔ فهرست مخاطب‌های گوشی خود را یک‌جا حذف کرده بود و تنها جایی که شماره‌ها و نام مخاطب‌ها موجود بودند؛ حساب تلگرامش بود؛ و نه جایی مثل حساب گوگل.

این‌جا بود که تلاش کردم با دانسته‌های برنامه‌نویسی خودم و کمی جستجوی آنلاین این مسئله را حل کنم. راه حل من این طور بود که باید:

  1. یک ربات در سمت تلگرام تعریف می‌کردم؛

  2. یک برنامه برای خواندن پیام‌های و تجزیه‌ و تحلیل پیام‌های رسیده به ربات می‌نوشتم که:
    1. پیام‌های وارد شده به ربات را می‌خواند؛

    2. یک فایل متنی برای ذخیرهٔ مخاطب‌ها ایجاد می‌کرد؛

    3. همهٔ مخاطب‌های فرستاده شده به ربات را می‌گرفت؛

    4. مشخّصات مخاطب مانند نام، نام خانوادگی و شمارهٔ تلفن فرد را از پیام جدا می‌کرد؛

    5. این مشخّصات را در الگو‌ی مشخّص مخاطب‌ها (vcard 2.1) جا زده و کارت تماس مجازی به دست آمده را در فایل ساخته شده می‌نوشت

    6. مراحل ۳.۱ تا ۳.۵ را آن‌قدر انجام می‌داد که دیگر پیام مخاطبی باقی نمی‌مفایل فهرست مخاطب‌ها را دوباره به فرستندهٔ مخاطب‌ها برمی‌گرداند؛ند؛

  3. شناسهٔ یکتای ربات را به برنامه‌‌ی بالا -که روی سیستم شخصی اجرا کرده بودم- وارد می‌کردم؛ تا ربات و برنامه به هم وصل شوند و برنامه بتواند پیام‌های ربات را بخواند؛

  4. مخاطب‌ها را به صورت دسته‌ای به ربات می‌فرستادم؛

  5. در نهایت فایل خروجی را که شامل نام، نام خانوادگی و شمارهٔ تلفن (همراه، محلّ کار و یا منزل شخص بود) را از ربات دریافت و به فهرست مخاطب‌های گوشی وارد می‌کردم.

گام ۱: تعریف ربات

توجه

اگر قبلاً با ربات‌های تلگرام در حدّی کار کرده‌اید که می‌دانید از کجا شناسهٔ ربات را بگیرید از این بخش با خیال راحت رد شوید.

برای ایجاد ربات، در بخش جستجوی دنبال ربات BotFather@ بگردید. بعد از شروع به کار ربات، این پیام‌ها را بدون توضیحات فارسی به ترتیب برای ربات بفرستید:

  1. newbot/ (فرمان ایجاد ربات جدید)

  2. در مر‌حلهٔ بعد برای ربات خود یک نام انتخاب کنید.

  3. برای ربات خود یک نام کاربری انتخاب کنید. متن نام باید به کلمهٔ bot ختم شود. در تلگرام در انتهای نام کاربری ربات‌ها باید این کلمه وجود داشته باشد.

  4. در پیام بعدی، تلگرام به شما پیوند، شناسه (token) و پیوند راهنمای رابط برنامه‌نویسی ربات را می‌دهد، مثل این:

تصویر رابط کابری ربات ساز

نمونهٔ پیام دریافت شناسهٔ رابط برنامه‌نویسی ربات

اگر برای دفعات بعد خواستید شناسهٔ برنامه‌نویسی را دوباره بگیرید؛ کافیست در BotFather فرمان token/ را وارد کنید و از فهرست ربات‌هایی که ساخته‌اید ربات مورد نظرتان را انتخاب کنید.

گام ۲: ساخت هستهٔ اصلی ربات

زمانی که این برنامه را نوشتم، برای این کار از از کتابخانهٔ telegram استفاده کردم. چون با اندکی جستجو متوجّه شدم قابلیّت‌هایی را که می‌خواستم به سادگی در اختیارم می‌گذاشت.

توجه

نصب بسته‌های پایتون از نمایهٔ بسته‌های پایتون

شما می‌توانید آن را با وارد کردن این دستور در محیط خط فرمان نصب کنید (اگر از لینوکس استفاده می‌کنید، شاید لازم باشد به جای pip از pip3 استفاده کنید): .. code-block:: python

pip install telegram

بعد از نصب کتابخانه و ایجاد فایل برنامه، در گام اوّل آن را فراخوان می‌کنیم:

import telegram

و با دادن شناسهٔ ربات، رباتمان را در یک متغیّر تعریف می‌کنیم تا به همهٔ ویژگی‌های آن دسترسی داشته باشیم:

bot = telegram('bot ID goes here!')#اون وسط شناسهٔ ربات رو به صورت یک رشته‌متن می‌گذاریم.

سپس، شناسهٔ گفتگو و آخرین پیام‌های فرستاده شده را از ربات می‌خوانیم و درون یک لیست برای استفاده‌ ذخیره می‌کنیم:

chat_id = bot.get_updates( )[ -1 ].message.chat_id
updateslist = bot.getUpdates()

ین مرحله‌ چندان الزامی نیست. برای طبیعی‌تر کردن فرآیند پاسخ دهی ترجیح دادم که ابتدا ربات یک پیام با متن «در حال پردازش» بفرستد و وضعیّتش هم به در حال تایپ تغییر کند. انگار که دارد همهٔ این‌ها را برای فرستنده می‌نویسد:

bot.sendMessage ( chat_id = chat_id, text = 'Processing...' )
bot.send_chat_action( chat_id = chat_id, action = telegram.ChatAction.TYPING )

برای ذخیره مخاطب‌ها یک فایل متنی با پسوند vcf. و کدگذاری صفحهٔ utf-8 ایجاد می‌کنیم. برای این کار با تابع open یک فایل ایجاد/باز می‌کنیم. همچنین، به نشانوند mode تابع  open دو مقدار w و t را می‌دهیم. برای حالت نوشتن از w استفاده می‌کنیم تا اگر فایل از قبل اطّلاعاتی را داشته باشد آن‌ها را قبل از نوشتن حذف می‌کند. مقدار t هم مشخّص می‌کند که فایل را به صورت متنی ذخیره کند؛ و نه به صورت مقدار‌های دودویی:

f = open( 'contactsHon.vcf', mode = 'wt', encoding = 'utf-8' )

توجه

اگر می‌خواهید از حالت‌های مختلف خواندن و نوشتن فایل با تابع open این‌جا را بخوانید.

در نهایت، برنامهٔ ربات از لیست پیام‌های دریافت‌شدهٔ همان گفتگو، نام و نام خانوادگی هر فرد را در پیام می‌خواند و نوع تلفن آن‌ها (همراه یا زمینی) آن را با توجّه به جای آن تشخیص می‌دهد و در متغیّر‌های مشخّص‌شده ذخیره می‌کند. از آن‌جایی که مخاطب فرستاده شده می‌تواند شامل تصویر هم باشد؛ خواندن تصویر مخاطب هم به همین اندازه آسان است و می‌توان آن را در یک متغیّر دیگر ذخیره کرد.

فایل را می‌بندد. دقّت کنید که بستن فایل ضروری است؛ چون اگر بسته نشود ممکن است بعضی داده‌های در آن نوشته نشده باشند؛ حتّی اگر اجرای برنامه بدون خطا باشد. (البتّه تصویر مخاطب را درج نمی‌کند):

global n
for n in updateslist:
        # asserting message in contact
        first_name = n [ 'message' ][ 'contact' ][ 'first_name' ]
        last_name = n [ 'message' ][ 'contact' ][ 'last_name' ]
        phone_number = n [ 'message' ][ 'contact' ][ 'phone_number' ]
        #change telephone type on number type
        if int ( phone_number [ 2 ] ) == 9 :
                phone_type = 'CELL'

        else:
                phone_type = 'home'
            ##photo=bot.getUserProfilePhotos(n['message']['photo']['user_id'][0])

        vcard = f"""
BEGIN:VCARD
VERSION:2.1
N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:{last_name};{first_name};;;
FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:{first_name} {last_name}
TEL;{phone_type}:+{phone_number}
END:VCARD
"""
        f.writelines ( vcard )

f.close( )

در نهایت فایل را برای کاربر می‌فرستیم:

bot.sendMessage( chat_id = chat_id, text = 'Vcard file creation finished.' )
bot.send_document( chat_id = chat_id, document = open ( 'contactsHon.vcf', 'rb' ), )

گام ۳: آزمون و بهینه‌سازی برنامه

زمانی که برنامه را کامل کردم؛ با موفّقیّت توانستم تمام مخاطب‌های حذف شده را برگردانم. البتّه، مدّتی بعد که همین برنامه را خواستم دوباره اجرا کنم؛ به خاطر به‌روز رسانی‌ها و تغییرات تلگرام و کتابخانه‌ای که استفاده کرده بودم؛ برنامه دچار خطا شد و دیگر اجرا نشد. البتّه، با دانش الآنم باید باید خیلی از قسمت‌های برنامه را رفع اشکال می‌کردم،... مثل این‌ها:

  • یک راه دیگر برای این کار این بود که یک زیر کلاس از کلاس کتابخانهٔ ربات تعریف می‌کردیم که ویژگی‌هایی را که می‌خواستیم را داشته باشد و قسمت‌های بعدی را درون کلاس تعریف می‌کردیم.

  • اگر ‌می‌خواهید برنامه بعد از پایان کارش خودکار فایل را هم ببند، باید تابع باز کردن فایل را با with این طور بنویسیم و تمام دستورهای بعدی را درون بخش with. با این کار بعد از تمام شدن with فایل خودکار بسته می‌شود:

    with open( 'contactsHon.vcf', mode = 'wt', encoding = 'utf-8' ) as f:
        #کارهایی که روی فایل باید انجام شوند
        pass
    
  • خیلی از این کارها مثل خواندن نام و مشخّصات را بدون ذخیره در متغیّر هم می‌شد انجام داد، مثل خیلی از برنامه‌های تک‌خطّی‌ پایتون. ولی انجام زیاد این کار خوانایی برنامه را پایین‌ می‌آورد و رفع اشکال برنامه طولانی و خسته‌کننده می‌شود. در نتیجه، اگر می خواستم این برنامه را بعد از دست چند سال (مثل الآن) دوباره بخوانم؛ به سختی متوجّه می‌شدم چه اتّفاقی افتاده و برنامه‌ چطور کار می‌کند.

  • از همه مهم‌تر این که این برنامه را بعد از مدّتی دوباره که خواستم اجرا کنم و توسعه بدهم با خطا مواجه شد. علّت هم تغییرات کتابخانه‌ها و تلگرام بود. برای همین با توجّه به به روز نشدن کتابخانهٔ استفاده شده این برنامه تا زمان نگارش تمرین، توانید در نمایهٔ بسته‌های پایتون دنبال یکی بهتر و به‌روزتر بگردید.

جمع‌بندی و توسعهٔ بیشتر

در این تمرین سعی کردیم فهرست مخاطب‌های از دست رفته را با ربات تلگرام برگردانیم. ابتدا یک ربات ساختیم و با اتصال آن به برنامه‌ای که روی سیستم در حال اجرا بود؛ پیام‌ها را به آن منتقل کردیم. نوشتن برنامه برای بقیّهٔ پیام رسان‌ها که از حالتی مانند تلگرام پشتیبانی می‌کنند (مثل بله، گپ و ...) در صورت داشتن رابط برنامه‌نویسی پایتون احتمالاً مشابه تلگرام باشد. بعضی از پیام‌رسان‌ها (مانند شاد) نه فقط برای پایتون، بلکه هیچ زبانی رابط برنامه‌نویسی ارائه نداده‌اند. برای ادامهٔ این کد -فارغ از هر پیام‌رسانی-، می‌توانید روی این موارد کار کنید:

  • این کد با رویکرد برنامه‌نویسی رویه‌ای نوشته شده. چطور می‌توان این برنامه را شیئ‌گرا نوشت؟

  • چطور می‌توانیم تصویر مخاطب را به vcard هر فرد اضافه کنیم؟

  • با توجّه به روز نشدن کتابخانه‌ای استفاده شده در این تمرین؛ می‌توان از کدام کتابخانه‌ها به

  • عنوان جایگزین استفاده کرد؟

  • اشکالات این کد کجاست و چطور می‌توان آن را بهینه‌تر کرد؟