اذهب إلى المحتوى

التحكم في لوحة المفاتيح والفأرة عبر أتمتة واجهة الاستخدام الرسومية GUI في بايثون


Ola Abbas

من المفيد معرفة وحدات بايثون Python المختلفة لتحرير جداول البيانات وتنزيل الملفات وتشغيل البرامج، ولكن لا توجد في بعض الأحيان أيّ وحداتٍ للتطبيقات التي تحتاج إلى العمل معها، فالأدوات الأساسية لأتمتة المهام على حاسوبك هي البرامج التي تكتبها وتتحكم في لوحة المفاتيح والفأرة مباشرةً، حيث يمكن لهذه البرامج التحكم في التطبيقات الأخرى من خلال إرسال ضغطات مفاتيح افتراضية ونقرات افتراضية بالفأرة إليها كما لو أنك جالس أمام حاسوبك وتتفاعل مع التطبيقات بنفسك.

تُعرَف هذه التقنية باسم أتمتة واجهة المستخدم الرسومية Graphical User Interface Automation أو GUI automation اختصارًا، حيث يمكن لبرامجك باستخدام هذه التقنية فعل أيّ شيء يمكن أن يفعله المستخدم الجالس أمام الحاسوب باستثناء سكب القهوة على لوحة المفاتيح طبعًا. يمكن عَدّ أتمتة واجهة المستخدم الرسومية كبرمجة ذراع آلية، حيث يمكنك برمجة الذراع الآلية للكتابة باستخدام لوحة المفاتيح وتحريك الفأرة نيابةً عنك، وتُعَد هذه التقنية مفيدة خاصةً للمهام التي تتضمن الكثير من النقر أو ملء الاستمارات.

تبيع بعض الشركات حلولَ الأتمتة المبتكرة والمكلفة، والتي تُسوَّق عادةً بأنها أتمتة العمليات الآلية Robotic Process Automation أو RPA اختصارًا، حيث لا تختلف هذه المنتجات فعليًا عن سكربتات بايثون التي يمكنك إنشاؤها بنفسك باستخدام الوحدة pyautogui التي تحتوي على دوال لمحاكاة حركات الفأرة ونقرات الأزرار وتمرير عجلة الفأرة. سنوضّح في هذا المقال مجموعة فرعية فقط من ميزات الوحدة PyAutoGUI، حيث يمكنك العثور على التوثيق الكامل على موقعها الرسمي.

تثبيت الوحدة pyautogui

يمكن لوحدة pyautogui إرسال ضغطات المفاتيح ونقرات الفأرة الافتراضية إلى أنظمة تشغيل ويندوز Windows وماك macOS ولينكس Linux، حيث يمكن لمستخدمي ويندوز وماك macOS ببساطة استخدام أداة pip لتثبيت الوحدة PyAutoGUI، ولكن يجب على مستخدمي نظام لينكس أولًا تثبيت بعض البرامج التي تعتمد عليها وحدة PyAutoGUI، لذا افتح نافذة طرفية Terminal وأدخِل الأوامر التالية:

sudo apt install scrot python3-tk python3-dev

يمكنك تثبيت الوحدة PyAutoGUI من خلال تشغيل الأمر pip install --user pyautogui، ولكن لا تستخدم الأمر sudo مع الأداة pip، إذ يمكن أن تثبِّتَ وحداتٍ مع تثبيت بايثون الذي يستخدمه نظام التشغيل، مما يتسبب في حدوث تعارضات مع أيّ سكربتات تعتمد على ضبطها الأصلي، ولكن يجب استخدام الأمر sudo عند تثبيت التطبيقات باستخدام apt.

يمكنك اختبار صحة تثبيت الوحدة PyAutoGUI من خلال تشغيل الأمر import pyautogui في الصدفة التفاعلية Interactive Shell والتحقق من وجود رسائل خطأ.

ملاحظة: لا تحفظ برنامجك بالاسم pyautogui.py، إذ ستستورد لغة بايثون برنامجك بدلًا من الوحدة PyAutoGUI وستتلقّى رسائل خطأ مثل الرسالة AttributeError: module 'pyautogui' has no attribute 'click'‎ عند تشغيل الأمر import pyautogui.

إعداد تطبيقات إمكانية الوصول Accessibility على نظام ماك macOS

لا يسمح نظام ماك للبرامج بالتحكم في الفأرة أو لوحة المفاتيح كإجراءٍ أمني، لذا يجب ضبط البرنامج الذي يشغّل سكربت بايثون ليكون تطبيقًا لإمكانية الوصول لكي تعمل وحدة PyAutoGUI على نظام تشغيل ماك، إذ لن يكون لاستدعاءات دوال PyAutoGUI أيّ تأثير بدون إجراء هذه الخطوة.

اجعل تطبيقك مفتوحًا سواء شغّلته من محرّر Mu أو بيئة IDLE أو الطرفية Terminal، ثم افتح "تفضيلات النظام System Preferences" وانتقل إلى التبويب "إمكانية الوصول Accessibility". ستظهر التطبيقات المفتوحة حاليًا تحت العنوان "السماح للتطبيقات التالية بالتحكم في حاسوبك Allow the apps below to control your computer". تحقّق من تطبيق Mu أو IDLE أو الطرفية Terminal أو أيّ تطبيق تستخدمه لتشغيل سكربتات بايثون الخاصة بك، وسيُطلَب منك إدخال كلمة مرورك لتأكيد هذه التغييرات.

البقاء على المسار الصحيح

يجب أن تعرف كيفية التهرب من المشكلات التي قد تواجهك قبل الانتقال إلى أتمتة واجهة المستخدم الرسومية، فمثلًا يمكن لسكربت بايثون تحريك الفأرة والكتابة من خلال ضغطات المفاتيح بسرعة مذهلة، وقد يكون الأمر سريعًا جدًا بحيث لا تتمكّن البرامج الأخرى من مجاراة هذه السرعة، وإذا حدث خطأٌ ما مع استمرار برنامجك في تحريك الفأرة، فسيكون من الصعب معرفة ما يفعله البرنامج بالضبط أو كيفية حل هذه المشكلة. كما يمكن أن يخرج برنامجك عن السيطرة بالرغم من أنه يتبع تعليماتك بطريقة مثالية مثل المكانس المسحورة من فيلم The Sorcerer’s Apprentice من إنتاج شركة ديزني، والتي ظلت تملأ حوض ميكي بالماء ثم تملأه أكثر من اللازم، وقد يكون إيقاف البرنامج أمرًا صعبًا إذا كانت الفأرة تتحرك من تلقاء نفسها، مما يمنعك من النقر على نافذة محرّر Mu لإغلاقه. توجد لحسن الحظ عدة طرق لمنع مشاكل أتمتة واجهة المستخدم الرسومية أو حلها، والتي سنوضّحها فيما يلي.

التوقف المؤقت والفشل الآمن

إذا ظهر خطأ في برنامجك ولم تتمكّن من استخدام لوحة المفاتيح والفأرة لإغلاقه، فيمكنك استخدام ميزة الفشل الآمن في وحدة PyAutoGUI. حرّك الفأرة بسرعة إلى إحدى زوايا الشاشة الأربعة مثلًا، حيث يكون لكل استدعاء للدالة الخاصة بوحدة PyAutoGUI تأخير قدره 10 جزء من الثانية بعد تنفيذ الإجراء الخاص بها ليمنحك وقتًا كافيًا لتحريك الفأرة إلى الزاوية. إذا وجدَت وحدة PyAutoGUI بعد ذلك أن مؤشر الفأرة في الزاوية، فستطلق الاستثناء pyautogui.FailSafeException. لن يكون للتعليمات التي ليست تابعة لوحدة PyAutoGUI هذا التأخير الذي مقداره 10 جزء من الثانية.

إذا وجدت نفسك في موقف تحتاج فيه إلى إيقاف برنامج PyAutoGUI، فما عليك سوى تحريك الفأرة بسرعة باتجاه الزاوية لإيقافه.

إغلاق كل شيء من خلال تسجيل الخروج

قد تكون أبسط طريقة لإيقاف برنامج أتمتة واجهة المستخدم الرسومية الخارج عن السيطرة هي تسجيل الخروج، مما يؤدي إلى إيقاف تشغيل جميع البرامج التي تكون قيد التشغيل. مفتاح اختصار تسجيل الخروج هو CTRL-ALT-DEL في نظامي ويندوز ولينكس، وهو ‎01_000064.jpg‎-SHIFT-OPTION-Q على نظام ماك. ستفقد أيّ عمل غير محفوظ عند تسجيل الخروج، ولكنك لن تضطر إلى الانتظار حتى تنتهي عملية إعادة التشغيل الكاملة للحاسوب.

التحكم في حركة الفأرة

ستتعلّم في هذا القسم كيفية تحريك الفأرة وتعقّب موضعها على الشاشة باستخدام الوحدة PyAutoGUI، ولكن يجب أولًا أن تفهم كيفية عمل هذه الوحدة مع الإحداثيات.

تستخدم دوال الفأرة الخاصة بوحدة PyAutoGUI إحداثيات x و y، حيث يبين الشكل التالي نظام إحداثيات شاشة الحاسوب، وهو مشابه لنظام الإحداثيات المستخدَم مع الصور الذي ناقشناه في المقال السابق، إذ توجد نقطة الأصل Origin حيث تكون قيمة x و y صفر في الزاوية العلوية اليسرى من الشاشة، وتزداد إحداثيات x باتجاه اليمين، وتزداد إحداثيات y باتجاه الأسفل. تكون جميع الإحداثيات أعدادًا صحيحة موجبة، إذ لا توجد إحداثيات سالبة.

02_000125-معرب.png

إحداثيات شاشة الحاسوب بدقة مقدارها 1920‎×1080

تمثّل الدقة Resolution عدد البكسلات لعرض وطول الشاشة، حيث إذا كانت دقة شاشتك مضبوطة على القيمة ‎1920×1080، فستكون إحداثيات الزاوية العلوية اليسرى هو ‎(0, 0)‎، وستكون إحداثيات الزاوية السفلية اليمنى هو ‎(1919, 1079)‎.

تعيد الدالة pyautogui.size()‎ مجموعةً Tuple مكوّنة من عددين صحيحين لعرض الشاشة وارتفاعها بالبكسل. لندخِل مثلًا ما يلي في الصدفة التفاعلية:

>>> import pyautogui
>>> wh = pyautogui.size() # الحصول على دقة الشاشة
>>> wh
Size(width=1920, height=1080)
>>> wh[0]
1920
>>> wh.width
1920

تعيد الدالة pyautogui.size()‎ المجموعة ‎(1920, 1080)‎‎ على حاسوب دقته 1920‎×1080، إذ قد تختلف القيمة المُعادة اعتمادًا على دقة شاشتك. يُعَد الكائن Size الذي تعيده الدالة size()‎ مجموعة مُسمَّاة Named Tuples، حيث يكون للمجموعات المُسماة فهارس رقمية مثل المجموعات العادية وأسماء سمات Attribute مثل الكائنات، إذ يُقيَّم كل من wh[0]‎ و wh.width بأنه عرض الشاشة. لن نشرح المجموعات المُسمَّاة في هذا المقال، ولكن تذكّر فقط أنه يمكنك استخدامها باستخدام الطريقة نفسها التي تستخدم بها المجموعات العادية.

تحريك الفأرة

تعرّفنا على مفهوم إحداثيات الشاشة، ويمكننا الآن تحريك الفأرة، حيث تحرّك الدالة pyautogui.moveTo()‎ مؤشر الفأرة مباشرةً إلى موضعٍ محدّد على الشاشة. تشكّل القيم الصحيحة لإحداثيات x و y الوسيطين الأول والثاني لهذه الدالة على التوالي، ويحدّد وسيط الكلمات المفتاحية Keyword Argument الاختياري duration -الذي هو عدد صحيح أو عشري- عدد الثواني التي يجب أن يستغرقها تحريك الفأرة للوصول إلى وِجهتها، وإذا تركتَ هذا الوسيط دون تحديد، فإن القيمة الافتراضية هي 0 للحركة الفورية، وتكون جميع وسطاء الكلمات المفتاحية duration في دوال PyAutoGUI اختيارية. أدخِل مثلًا ما يلي في الصدفة التفاعلية:

>>> import pyautogui
>>> for i in range(10): # تحريك الفأرة في مربع
...       pyautogui.moveTo(100, 100, duration=0.25)
...       pyautogui.moveTo(200, 100, duration=0.25)
...       pyautogui.moveTo(200, 200, duration=0.25)
...       pyautogui.moveTo(100, 200, duration=0.25)

يحرّك المثال السابق مؤشر الفأرة باتجاه عقارب الساعة وفق نمطٍ مربع بين الإحداثيات الأربعة المُعطات 10 مرات، حيث تستغرق كل حركة ربع ثانية كما يحدّده وسيط الكلمات المفتاحية duration=0.25، وإن لم تمرّر الوسيط الثالث إلى أيٍّ من استدعاءات الدالة pyautogui.moveTo()‎، فسينتقل مؤشر الفأرة من نقطة إلى أخرى مباشرةً.

تحرّك الدالة pyautogui.move()‎ مؤشر الفأرة نسبةً إلى موضعه الحالي، حيث يحرّك المثال التالي الفأرة وفق نمط المربع نفسه، ولكنه يبدأ المربع من أيّ مكان توجد فيه الفأرة على الشاشة عند بدء تشغيل الشيفرة البرمجية:

>>> import pyautogui
>>> for i in range(10):
...       pyautogui.move(100, 0, duration=0.25)   # إلى اليمين
...       pyautogui.move(0, 100, duration=0.25)   # للأسفل
...       pyautogui.move(-100, 0, duration=0.25)  # إلى اليسار
...       pyautogui.move(0, -100, duration=0.25)  # للأعلى

تأخذ الدالة pyautogui.move()‎ أيضًا ثلاثة وسطاء هي: عدد البكسلات التي يجب تحريكها أفقيًا إلى اليمين، وعدد البكسلات التي يجب تحريكها عموديًا للأسفل، والمدة التي يجب أن يستغرقها إكمال الحركة (اختياريًا). سيؤدي استخدام العدد الصحيح السالب مع الوسيط الأول أو الثاني إلى تحريك الفأرة إلى اليسار أو للأعلى على التوالي.

الحصول على موضع الفأرة

يمكنك تحديد موضع الفأرة الحالي من خلال استدعاء الدالة pyautogui.position()‎ التي ستعيد المجموعة المُسمَّاة Point لموضعي x و y الخاصين بمؤشر الفأرة عند استدعاء الدالة. أدخِل مثلًا ما يلي في الصدفة التفاعلية مع تحريك الفأرة بعد كل استدعاء:

>>> pyautogui.position() # الحصول على موضع الفأرة الحالي
Point(x=311, y=622)
>>> pyautogui.position() # الحصول على موضع الفأرة الحالي مرة أخرى
Point(x=377, y=481)
>>> p = pyautogui.position() # الحصول على موضع الفأرة الحالي مرة أخرى
>>> p
Point(x=1536, y=637)
>>> p[0] # ‫يقع الإحداثي x عند الفهرس 0
1536
>>> p.x # يوجد الإحداثي‫ x أيضًا في السمة x
1536

ستختلف قيمك المُعادة اعتمادًا على مكان مؤشر الفأرة.

التحكم في تفاعل الفأرة

تعرّفتَ كيفية تحريك الفأرة ومعرفة مكانها على الشاشة، وأصبحتَ الآن جاهزًا لبدء النقر والسحب والتمرير.

النقر باستخدام الفأرة

يمكنك إرسال نقرة افتراضية باستخدام الفأرة إلى حاسوبك من خلال استدعاء التابع pyautogui.click()‎، حيث تستخدم هذه النقرة زر الفأرة الأيسر افتراضيًا وتُطبَّق في أيّ مكان يوجد فيه مؤشر الفأرة حاليًا. يمكنك تمرير إحداثيات x و y لهذه النقرة كوسيط أول وثانٍ اختياريين إلى التابع إذا أدرتَ أن تُطبَّق في مكانٍ آخر غير موضع الفأرة الحالي.

إذا أدرتَ تحديد زر الفأرة الذي يجب استخدامه، فضمّن وسيط الكلمات المفتاحية button مع قيم 'left' أو 'middle' أو 'right'، فمثلًا سيؤدي الاستدعاء pyautogui.click(100, 150, button='left')‎ إلى النقر على زر الفأرة الأيسر عند الإحداثيات ‎(100, 150)‎، بينما سيؤدي الاستدعاء pyautogui.click(200, 250, button='right')‎ إلى النقر بزر الفأرة الأيمن عند الإحداثيات ‎(200, 250)‎.

أدخِل مثلًا ما يلي في الصدفة التفاعلية:

>>> import pyautogui
>>> pyautogui.click(10, 5) # ‫تحريك الفأرة إلى الإحداثيات ‎(10, 5)‎ ثم النقر

يُفترَض أن ترى مؤشر الفأرة يتحرك بالقرب من الزاوية العلوية اليسرى من الشاشة ثم يحدث النقر مرة واحدة. يمكن تعريف "النقرة" الكاملة على أنها الضغط على زر الفأرة للأسفل ثم تحريره للأعلى دون تحريك المؤشر، ويمكنك أيضًا إجراء نقرة من خلال استدعاء الدالة pyautogui.mouseDown()‎ التي تضغط زر الفأرة للأسفل فقط، ثم استدعاء الدالة pyautogui.mouseUp()‎ التي تحرّر الزر. تمتلك هاتان الدالتان وسطاء الدالة click()‎ نفسها، ولكن تُعَد الدالة click()‎ مجرد دالة مغلِّفة ملائمة لهاتين الدالتين.

تنقر الدالة pyautogui.doubleClick()‎ نقرتين باستخدام زر الفأرة الأيسر، بينما تنقر الدالتان pyautogui.rightClick()‎ و pyautogui.middleClick()‎ نقرة واحدة باستخدام زري الفأرة الأيمن والأوسط على التوالي.

سحب Dragging الفأرة

يعني السحب تحريكَ الفأرة أثناء الضغط باستمرار على أحد أزرارها، فمثلًا يمكنك نقل الملفات بين المجلدات من خلال سحب أيقونات المجلدات، أو يمكنك نقل المواعيد في تطبيق التقويم من خلال سحبها باستخدام الفأرة.

توفر وحدة PyAutoGUI الدالتين pyautogui.dragTo()‎ و pyautogui.drag()‎ لسحب مؤشر الفأرة إلى موقع جديد أو موقع متعلق بموقعه الحالي. تستخدم الدالتان dragTo()‎ و drag()‎ وسطاء الدالتين moveTo()‎ و move()‎ نفسها وهي: حركة الإحداثي x أو الحركة أفقيًا وحركة الإحداثي y أو الحركة عموديًا ومدة زمنية اختيارية. لا يطبّق نظام ماك السحب تطبيقًا صحيحًا عندما تتحرك الفأرة بسرعة كبيرة، لذا يوصَى بتمرير وسيط الكلمات المفتاحية duration.

لنجرّب هذه الدوال، لذا افتح تطبيق رسمٍ مثل تطبيق الرسام MS Paint على ويندوز أو تطبيق Paintbrush على نظام ماك ، أو تطبيق GNU Paint على نظام لينكس، حيث سنستخدم وحدة PyAutoGUI للرسم في هذه التطبيقات. إن لم يكن لديك تطبيق رسم، فيمكنك استخدام تطبيق sumopaint عبر الإنترنت.

أدخِل ما يلي في نافذة ملفٍ جديد في محرّرك واحفظه بالاسم spiralDraw.py مع وجود مؤشر الفأرة على لوحة الرسم الخاصة بتطبيق الرسم وتحديد أداة القلم Pencil أو الفرشاة Brush:

   import pyautogui, time
 time.sleep(5)
 pyautogui.click()    # النقر لتنشيط النافذة
   distance = 300
   change = 20
   while distance > 0:
     pyautogui.drag(distance, 0, duration=0.2)   # التحرك يمينًا
     distance = distance  change
     pyautogui.drag(0, distance, duration=0.2)   # التحرك للأسفل
     pyautogui.drag(-distance, 0, duration=0.2)  # التحرك يسارًا
       distance = distance  change
       pyautogui.drag(0, -distance, duration=0.2)  # التحرك للأعلى

سيكون هناك تأخير لمدة خمس ثوانٍ ➊ عند تشغيل هذا البرنامج لتتمكّن من تحريك مؤشر الفأرة على نافذة برنامج الرسم مع تحديد أداة القلم أو الفرشاة، ثم سيتحكّم برنامج spiralDraw.py في الفأرة وينقر لتنشيط نافذة برنامج الرسم ➋. النافذة النشطة هي النافذة التي تقبل حاليًا الإدخال من لوحة المفاتيح، وستؤثّر الإجراءات التي تتخذها مثل الكتابة أو سحب الفأرة على تلك النافذة، وتُعرَف النافذة النشطة أيضًا بالنافذة المُركَّزة أو النافذة الأمامية.

يرسم برنامج spiralDraw.py نمطًا حلزونيًا مربعًا مثل النمط الموجود على يسار الشكل الآتي بعد أن يصبح برنامج الرسم نشطًا. يمكنك أيضًا إنشاء صورة حلزونية مربعة باستخدام الوحدة Pillow التي ناقشناها في المقال السابق، ولكن يتيح لك إنشاء الصورة من خلال التحكم في الفأرة لرسمها في برنامج الرسام MS Paint الاستفادةَ من أنماط الفرشاة المتنوعة لهذا البرنامج كما في الشكل الموجود على يمين الشكل التالي، بالإضافة إلى ميزات متقدمة أخرى مثل التدرجات أو أداة التعبئة، حيث يمكنك تحديد إعدادات الفرشاة مسبقًا بنفسك أو جعل شيفرة بايثون الخاصة بك تحدّد هذه الإعدادات، ثم يمكنك تشغيل برنامج الرسم الحلزوني.

03 000073

نتائج مثال استخدام الدالة pyautogui.drag()‎ المرسومة باستخدام فُرش برنامج الرسام المختلفة

يبدأ المتغير distance عند القيمة 200، لذلك يسحب استدعاء الدالة drag()‎ الأول المؤشر بمقدار 200 بكسل إلى اليمين، ويستغرق ذلك 0.2 ثانية ➌ في التكرار الأول لحلقة while، ثم تُقلَّل قيمة المتغير distance إلى القيمة 195 ➍، ويسحب استدعاء الدالة drag()‎ الثاني المؤشر بمقدار 195 بكسل للأسفل ➎. يسحب استدعاء الدالة drag()‎ الثالث المؤشر بمقدار ‎-195 أفقيًا (أي بمقدار 195 إلى اليسار) ➏، وتُقلَّل قيمة المتغير distance إلى 190، ويسحب استدعاء drag()‎ الأخير المؤشر بمقدار 190 بكسل للأعلى. تُسحَب الفأرة إلى اليمين والأسفل واليسار والأعلى في كل تكرار، وتكون قيمة المتغير distance أصغر قليلًا مما كانت عليه في التكرار السابق. يمكنك تحريك مؤشر الفأرة لرسم شكل حلزوني مربع من خلال تكرار هذه الشيفرة البرمجية.

يمكنك رسم هذا الحلزوني يدويًا (أو باستخدام الفأرة)، ولكن يجب أن تعمل ببطء لتكون دقيقًا جدًا، ولكن يمكن للوحدة PyAutoGUI إنجاز ذلك في بضع ثوانٍ.

ملاحظة: لا تستطيع الوحدة PyAutoGUI حاليًا إرسال نقرات الفأرة أو ضغطات المفاتيح إلى برامج معينة مثل برامج مكافحة الفيروسات (لمنع الفيروسات من تعطيل البرنامج) أو ألعاب الفيديو على نظام ويندوز (التي تستخدم طريقة مختلفة لتلقي دخل الفأرة ولوحة المفاتيح). يمكنك التحقق من توثيق الوحدة PyAutoGUI على موقعها الرسمي لمعرفة ما إذا كانت هذه الميزات مدعومة في نظامك.

التمرير بالفأرة

دالة الوحدة PyAutoGUI الأخيرة الخاصة بالفأرة هي الدالة scroll()‎ التي نمرّر إليها وسيطًا نوعه عدد صحيح يمثّل عدد الوحدات التي تريد تمرير الفأرة عبرها للأعلى أو للأسفل، حيث يختلف حجم هذه الوحدة باختلاف نظام التشغيل والتطبيق، لذا يجب اأن تجرّب لمعرفة مقدار التمرير في حالتك، ويُطبَّق التمرير عند الموضع الحالي لمؤشر الفأرة. يؤدي تمرير عدد صحيح موجب إلى التمرير للأعلى، بينما يؤدي تمرير عدد صحيح سالب إلى التمرير للأسفل. شغّل ما يلي في الصدفة التفاعلية للمحرّر Mu أثناء وجود مؤشر الفأرة على نافذة هذا المحرّر:

>>> pyautogui.scroll(200)

سترى أن برنامج Mu يُمرَّر للأعلى إذا كان مؤشر الفأرة على حقل نصي يمكن تمريره للأعلى.

تخطيط حركات الفأرة

إحدى صعوبات كتابة برنامج يؤتمت عملية النقر على الشاشة هي العثور على إحداثيات x و y للأشياء التي ترغب في النقر عليها، ولكن يمكن أن تساعدك الدالة pyautogui.mouseInfo()‎ في هذا الأمر، حيث يُفترَض استدعاء هذه الدالة من الصدفة التفاعلية، وليس كجزء من برنامجك. تشغِّل هذه الدالة تطبيقًا صغيرًا اسمه MouseInfo المُضمَّن مع الوحدة PyAutoGUI، وتبدو نافذة هذا التطبيق كما يلي:

04 000019

نافذة التطبيق MouseInfo

أدخِل الآن ما يلي في الصدفة التفاعلية:

>>> import pyautogui
>>> pyautogui.mouseInfo()

يؤدي ذلك إلى ظهور نافذة تطبيق MouseInfo، حيث توفر لك هذه النافذة معلومات حول الموضع الحالي لمؤشر الفأرة، بالإضافة إلى لون البكسل الموجود تحت مؤشر الفأرة كمجموعة RGB مكونة من ثلاثة أعداد صحيحة وكقيمة ست عشرية، حيث يظهر اللون نفسه في مربع اللون Color الموجود في النافذة.

يمكنك تسجيل معلومات الإحداثيات أو البكسلات من خلال النقر على أحد أزرار النسخ Copy أو التسجيل Log الثمانية، حيث ستنسخ أزرار Copy All و Copy XY و Copy RGB و Copy RGB Hex معلوماتها الخاصة في الحافظة Clipboard، وستكتب الأزرار Log All و Log XY و Log RGB و Log RGB Hex معلوماتها الخاصة في الحقل النصي الكبير من هذه النافذة، ويمكنك حفظ النص الموجود في هذا الحقل لتسجيل النص بالنقر على زر الحفظ Save Log.

لاحظ تحديد مربع الاختيار ‎3 Sec. Button Delay‎ افتراضيًا، مما يتسبب في تأخير لمدة 3 ثوانٍ بين النقر على زر النسخ Copy أو التسجيل Log وحدوث النسخ أو التسجيل، ويمنحك ذلك وقتًا قصيرًا للنقر على الزر ثم تحريك الفأرة إلى الموضع المطلوب. قد يكون من الأسهل إلغاء تحديد مربع الاختيار 3‎ Sec. Button Delay، وتحريك الفأرة إلى موضعٍ معين، ثم الضغط على المفاتيح من F1 إلى F8 لنسخ موضع الفأرة أو تسجيله. يمكنك إلقاء نظرة على قوائم النسخ والتسجيل الموجودة أعلى نافذة تطبيق MouseInfo لمعرفة المفاتيح المرتبطة بهذه الأزرار.

ألغِ مثلًا تحديد مربع الاختيار ‎3 Sec. Button Delay‎، ثم حرّك الفأرة على الشاشة أثناء الضغط على الزر F6، ولاحظ كيفية تسجيل إحداثيات x و y للفأرة في الحقل النصي الكبير في منتصف النافذة، حيث يمكنك لاحقًا استخدام هذه الإحداثيات في سكربتات PyAutoGUI الخاصة بك.

اطّلع على توثيق تطبيق MouseInfo الكامل لمزيدٍ من المعلومات.

العمل مع الشاشات

ليس من الضروري أن تنقر أو تكتب برامجُك لأتمتة واجهة المستخدم الرسومية دون رؤية ما يحدث، إذ تحتوي الوحدة PyAutoGUI على ميزات لقطة الشاشة التي يمكنها إنشاء ملف صورة بناءً على محتويات الشاشة الحالية، ويمكن لهذه الدوال أيضًا إعادة كائن Image الخاص بالوحدة Pillow لمظهر الشاشة الحالي. اطّلع على المقال السابق وثبّت الوحدة pillow قبل الاستمرار في هذا القسم.

يجب أن تثبّت برنامج scrot على الحواسيب التي تعمل على نظام لينكس لاستخدام دوال لقطة الشاشة في الوحدة PyAutoGUI، لذا شغّل الأمر sudo apt install scrot في نافذةالطرفية لتثبيت هذا البرنامج. إذا كنت تستخدم نظام تشغيل ويندوز أو ماك، فانتقل إلى الخطوة التالية من هذا القسم.

الحصول على لقطة الشاشة

يمكنك التقاط لقطات شاشة في لغة بايثون من خلال استدعاء الدالة pyautogui.screenshot()‎، لذا أدخِل ما يلي في الصدفة التفاعلية:

>>> import pyautogui
>>> im = pyautogui.screenshot()

سيحتوي المتغير im على كائن Image للقطة الشاشة، وبالتالي يمكنك الآن استدعاء التوابع مع كائن Image في المتغير im مثل أيّ كائن Image آخر. اطّلع على المقال السابق للحصول على مزيدٍ من التفاصيل حول كائنات Image.

تحليل لقطة الشاشة

لنفترض أن إحدى الخطوات في برنامجك لأتمتة واجهة المستخدم الرسومية هي النقر على زر رمادي، حيث يمكنك التقاط لقطة شاشة قبل استدعاء التابع click()‎ وإلقاء نظرة على البكسل الذي سينقر سكربتك عليه، فإن لم يكن لون هذا البكسل رماديًا مثل الزر الرمادي، فهذا يعني أن برنامجك يعلم أن هناك خطأً ما، وبالتالي قد تتحرك النافذة بطريقة غير متوقعة، أو قد يوقِف مربع حوار منبثق الزر. يمكن لبرنامجك عندها رؤية أنه لا ينقر على الشيء الصحيح ويوقِف نفسه بدلًا من الاستمرار وإحداث فوضى من خلال النقر على الشيء الخطأ.

يمكنك الحصول على قيمة لون RGB لبكسل معين على الشاشة باستخدام الدالة pixel()‎. أدخِل مثلًا ما يلي في الصدفة التفاعلية:

>>> import pyautogui
>>> pyautogui.pixel((0, 0))
(176, 176, 175)
>>> pyautogui.pixel((50, 200))
(130, 135, 144)

مرّر مجموعة من الإحداثيات مثل ‎(0, 0)‎ أو ‎(50, 200)‎ إلى الدالة pixel()‎ التي ستخبرك بلون البكسل عند تلك الإحداثيات في صورتك. القيمة المُعادة من الدالة pixel()‎ هي مجموعة RGB مكونة من ثلاثة أعداد صحيحة تمثّل مقدار اللون الأحمر والأخضر والأزرق في البكسل، ولا توجد قيمة رابعة تمثّل قيمة ألفا Alpha، لأن صور لقطة الشاشة معتمة Opaque تمامًا.

تعيد الدالة pixelMatchesColor()‎ الخاصة بوحدة PyAutoGUI القيمة True إذا تطابق البكسل الموجود عند إحداثيات x و y المُعطاة على الشاشة مع اللون المُعطَى. يُعَد الوسيطان الأول والثاني أعدادًا صحيحة تمثّل إحداثيات x و y، والوسيط الثالث هو مجموعة مكونة من ثلاثة أعداد صحيحة تمثّل لون RGB الذي يجب أن يتطابق مع البكسل الموجود على الشاشة. أدخِل مثلًا ما يلي في الصدفة التفاعلية:

   >>> import pyautogui
 >>> pyautogui.pixel((50, 200))
   (130, 135, 144)
 >>> pyautogui.pixelMatchesColor(50, 200, (130, 135, 144))
   True
 >>> pyautogui.pixelMatchesColor(50, 200, (255, 135, 144))
   False

استخدمنا الدالة pixel()‎ للحصول على مجموعة RGB التي تمثّل لون البكسل عند إحداثيات مُحدَّدة ➊، وسنمرّر الآن الإحداثيات نفسها ومجموعة RGB إلى الدالة pixelMatchesColor()‎ ➋، والتي يجب أن تعيد القيمة True. نغيّر بعد ذلك قيمةً من مجموعة RGB ونستدعي الدالة pixelMatchesColor()‎ مرةً أخرى مع الإحداثيات نفسها ➌، حيث يجب أن تعيد القيمة False. يمكن أن يكون استدعاء هذه الدالة مفيدًا عندما تكون برامجك لأتمتة واجهة المستخدم الرسومية على وشك استدعاء التابع click()‎ . لاحظ أن اللون عند الإحداثيات المحددة يجب أن يكون متطابقًا تمامًا، حيث إذا كان مختلفًا قليلًا مثل ‎(255, 255, 254)‎ بدلًا من ‎(255, 255, 255)‎، فستعيد الدالة ‎pixelMatchesColor()‎ القيمة False.

التعرف على الصور

إن لم تكن على معرفة مسبقة بالمكان الذي يجب أن تنقر عليه الوحدة PyAutoGUI، فيمكنك استخدام ميزة التعرّف على الصور، لذا أعطِ وحدة PyAutoGUI صورةً لما تريد النقر عليه ودعه يكتشف الإحداثيات.

إذا التقطتَ مسبقًا لقطة شاشة للحصول على صورة زر الإرسال Submit في الملف submit.png مثلًا، فستعيد الدالة locateOnScreen()‎ إحداثيات مكان وجود تلك الصورة. لنتعرّف على كيفية عمل هذه الدالة، لذا حاول التقاط لقطة شاشة لمنطقة صغيرة من شاشتك، ثم احفظ الصورة وأدخِل ما يلي في الصدفة التفاعلية مع وضع اسم ملف لقطة الشاشة الخاصة بك مكان 'submit.png':

>>> import pyautogui
>>> b = pyautogui.locateOnScreen('submit.png')
>>> b
Box(left=643, top=745, width=70, height=29)
>>> b[0]
643
>>> b.left
643

يُعَد كائن Box مجموعةً مسماة تعيدها الدالة locateOnScreen()‎ وله إحداثي x للحافة اليسرى وإحداثي y للحافة العلوية والعرض والارتفاع لمكان العثور على الصورة الأول على الشاشة. إذا طبّقتَ ذلك على حاسوبك باستخدام لقطة شاشتك، فستكون القيمة المُعادة مختلفة عن القيمة الموضحة في مثالنا.

إذا تعذر العثور على الصورة على الشاشة، فستعيد الدالة locateOnScreen()‎ القيمة None. لاحظ أن الصورة الموجودة على الشاشة يجب أن تتطابق تمامًا مع الصورة المُقدَّمة للتعرّف عليها، حيث إذا كانت الصورة مختلفة ببكسل واحد، فسترفع الدالة locateOnScreen()‎ الاستثناء ImageNotFoundException. إذا غيّرتَ دقة الشاشة، فقد لا تتطابق الصور من لقطات الشاشة السابقة مع الصور الموجودة على شاشتك الحالية، لذا يمكنك تغيير القياسات في إعدادات العرض لنظام تشغيلك كما هو موضّح في الشكل التالي:

05 000113

إعدادات قياسات العرض في نظام ويندوز 10 (على اليسار) ونظام ماك (على اليمين)

إذا عُثِر على الصورة في عدة أماكن على الشاشة، فستعيد الدالة locateAllOnScreen()‎ كائن Generator الذي يمكنك تمريره إلى التابع list()‎ لإعادة قائمة من المجموعات المكونة من أربعة أعداد صحيحة، حيث ستوجد مجموعة واحدة مكونة من أربعة أعداد صحيحة لكل موقع توجد فيه الصورة على الشاشة. تابع مثال الصدفة التفاعلية من خلال إدخال ما يلي مع وضع ملف الصورة الخاص بك مكان 'submit.png':

>>> list(pyautogui.locateAllOnScreen('submit.png'))
[(643, 745, 70, 29), (1007, 801, 70, 29)]

تمثل كل مجموعة من هذه المجموعات المكونة من أربعة أعداد صحيحة منطقةً من الشاشة، حيث تظهَر الصورة في موقعين في المثال السابق. إذا وُجِدت صورتُك في منطقةٍ واحدة فقط، فسيؤدي استخدام التابع list()‎ والدالة locateAllOnScreen()‎ إلى إعادة قائمة تحتوي على مجموعة واحدة فقط.

نحصل على المجموعة المكونة من أربعة أعداد صحيحة التي تمثّل الصورة التي تريد تحديدها، ثم يمكننا النقر على مركز هذه المنطقة من خلال تمرير هذه المجموعة إلى التابع click()‎. لندخل الآن مثلًا ما يلي في الصدفة التفاعلية:

>>> pyautogui.click((643, 745, 70, 29))

يمكنك أيضًا تمرير اسم ملف الصورة مباشرةً إلى التابع click()‎ كما يلي:

>>> pyautogui.click('submit.png')

تقبل الدالتان moveTo()‎ و dragTo()‎ أيضًا وسطاء لاسم ملف الصورة. تذكّر أن الدالة locateOnScreen()‎ ترفع استثناءً إن لم تتمكّن من العثور على الصورة على الشاشة، لذا يجب أن تستدعيها من داخل تعليمة try كما يلي:

try:
    location = pyautogui.locateOnScreen('submit.png')
except:
    print('Image could not be found.')

سيؤدي استثناء عدم العثور على الصورة على الشاشة إلى تعطّل برنامجك إن لم تستخدم تعليمات try و except، لذا من الجيد استخدام تعليمات try و except عند استدعاء الدالة locateOnScreen()‎ لأنك لا تستطيع التأكّد من أن برنامجك سيعثر على الصورة دائمًا.

الحصول على معلومات النافذة

يُعَد التعرّف على الصور طريقة ضعيفة للعثور على الأشياء التي تظهر على الشاشة، حيث إذا كان هناك بكسل واحد بلون مختلف، فلن تتمكن الدالة pyautogui.locateOnScreen()‎ من العثور على الصورة، لذا إذا كنت بحاجة إلى العثور على مكان وجود نافذة معينة على الشاشة، فمن الأسرع والأكثر موثوقية استخدام ميزات النافذة الخاصة بوحدة PyAutoGUI.

ملاحظة: تعمل ميزات النافذة الخاصة بوحدة PyAutoGUI على نظام تشغيل ويندوز فقط، ولا تعمل على نظام تشغيل ماك أو لينكس ابتداءً من الإصدار 0.9.46، وتأتي هذه الميزات من احتواء الوحدة PyAutoGUI على الوحدة PyGetWindow.

الحصول على النافذة النشطة

النافذة النشطة على شاشتك هي النافذة الموجودة حاليًا في المقدمة والتي تقبل الإدخال من لوحة المفاتيح. إذا كنت تكتب حاليًا شيفرة برمجية في المحرّر Mu، فإن نافذته هي النافذة النشطة، حيث ستُنشَّط نافذة واحدة فقط من بين جميع النوافذ التي تظهر على شاشتك في كل مرة. استدعِ الدالة pyautogui.getActiveWindow()‎ في الصدفة التفاعلية للحصول على كائن Window أو كائن Win32Window عند التشغيل على نظام ويندوز.

يمكنك استرداد أيٍّ من سمات الكائن Window التي تمثّل حجمه وموضعه وعنوانه بعد الحصول عليه وهذه السمات هي:

  • left و right و top و bottom: عدد صحيح واحد يمثّل الإحداثي x أو y لطرف النافذة.
  • topleft و topright و bottomleft و bottomright: مجموعة مسماة مكونة من عددين صحيحين يمثّلان إحداثيات (x, y) لزاوية النافذة.
  • midleft و midright و midleft و midright: مجموعة مسماة مكونة من عددين صحيحين يمثلان إحداثيات (x, y) لمنتصف طرف النافذة.
  • width و height: عدد صحيح واحد يمثّل أحد أبعاد النافذة بالبكسل.
  • size: مجموعة مسماة مكونة من عددين صحيحين يمثّلان عرض وارتفاع النافذة (width, height).
  • area: عدد صحيح واحد يمثل مساحة النافذة بالبكسل.
  • center: مجموعة مسماة مكونة من عددين صحيحين يمثلان إحداثيات (x, y) لمركز النافذة.
  • centerx و centery : عدد صحيح واحد يمثل إحداثي x أو y لمركز النافذة.
  • box: مجموعة مسماة مكونة من أربعة أعداد صحيحة لقياسات يسار وأعلى وعرض وارتفاع النافذة (left, top, width, height).
  • title: سلسلة من النص الموجود في شريط العنوان أعلى النافذة.

أدخِل مثلًا ما يلي في الصدفة التفاعلية للحصول على معلومات موضع النافذة وحجمها وعنوانها من كائن Window:

>>> import pyautogui
>>> fw = pyautogui.getActiveWindow()
>>> fw
Win32Window(hWnd=2034368)
>>> str(fw)
'<Win32Window left="500", top="300", width="2070", height="1208", title="Mu 1.0.1 – test1.py">'
>>> fw.title
'Mu 1.0.1 – test1.py'
>>> fw.size
(2070, 1208)
>>> fw.left, fw.top, fw.right, fw.bottom
(500, 300, 2070, 1208)
>>> fw.topleft
(256, 144)
>>> fw.area
2500560
>>> pyautogui.click(fw.left + 10, fw.top + 20)

يمكنك الآن استخدام هذه السمات لحساب الإحداثيات الدقيقة في النافذة، فمثلًا إذا كنت تعلم أن الزر الذي تريد النقر عليه يقع دائمًا على بعد 10 بكسلات على اليمين و20 بكسلًا للأسفل من الزاوية العلوية اليسرى للنافذة، وأن الزاوية العلوية اليسرى للنافذة تقع عند إحداثيات الشاشة ‎(300, 500)‎، فسيؤدي استدعاء التابع pyautogui.click(310, 520)‎ (أو pyautogui.click(fw.left + 10, fw.top + 20)‎ إذا احتوى المتغير fw على كائن Window الخاص بالنافذة) إلى النقر على هذا الزر، وبالتالي لن تضطر إلى الاعتماد على الدالة locateOnScreen()‎ الأبطأ والأقل موثوقية للعثور على الزر.

طرق أخرى للحصول على النافذة

تُعَد الدالة getActiveWindow()‎ مفيدةً للحصول على النافذة النشطة في وقت استدعاء الدالة، ولكن ستحتاج إلى استخدام بعض الدوال الأخرى للحصول على كائنات Window للنوافذ الأخرى على الشاشة، حيث تعيد الدوال الأربع التالية قائمةً بكائنات Window، وإن لم تتمكّن من العثور على أيّ نوافذ، فستعيد قائمةً فارغة:

  • pyautogui.getAllWindows()‎: تعيد قائمةً بكائنات Window لكل نافذة مرئية على الشاشة.
  • pyautogui.getWindowsAt(x, y)‎: تعيد قائمةً بكائنات Window لكل نافذة مرئية تتضمن النقطة (x, y).
  • pyautogui.getWindowsWithTitle(title)‎: تعيد قائمةً بكائنات Window لكل نافذة مرئية تتضمن السلسلة النصية title في شريط العنوان الخاص بها.
  • pyautogui.getActiveWindow()‎: تعيد كائن Window للنافذة التي تتلقّى تركيز لوحة المفاتيح حاليًا.
  • تحتوي الوحدة PyAutoGUI أيضًا على الدالة pyautogui.getAllTitles()‎ التي تعيد قائمةً بالسلاسل النصية لكل نافذة مرئية.

معالجة النوافذ

يمكن لسمات النوافذ أن تفعل أكثر من مجرد إخبارك بحجم النافذة وموضعها، إذ يمكنك أيضًا ضبط قيمها لتغيير حجم النافذة أو تحريكها، فمثلًا أدخِل ما يلي في الصدفة التفاعلية:

   >>> import pyautogui
   >>> fw = pyautogui.getActiveWindow()
 >>> fw.width # الحصول على العرض الحالي للنافذة
   1669
 >>> fw.topleft # الحصول على الموضع الحالي للنافذة
   (174, 153)
 >>> fw.width = 1000 # تغيير حجم العرض
 >>> fw.topleft = (800, 400) # تحريك النافذة

نستخدم أولًا سمات كائن Window لمعرفة معلومات حول حجم النافذة ➊ وموضعها ➋. يجب أن تتحرك النافذة ➍ وتصبح أضيق ➌ كما في الشكل التالي بعد استدعاء هذه الدوال في المحرّر Mu:

06 000058

نافذة المحرّر Mu قبل (في الأعلى) وبعد (في الأسفل) باستخدام سمات كائن Window لتحريك النافذة وتغيير حجمها

يمكنك أيضًا اكتشاف وتغيير حالات تصغير النافذة وتكبيرها وتنشيطها، لذا جرّب إدخال ما يلي في الصدفة التفاعلية:

   >>> import pyautogui
   >>> fw = pyautogui.getActiveWindow()
 >>> fw.isMaximized # ‫تعيد القيمة True عند تكبير النافذة
   False
 >>> fw.isMinimized # تعيد القيمة‫ True عند تصغير النافذة
   False
 >>> fw.isActive # تعيد القيمة‫ True إذا كانت النافذة نشطة
   True
 >>> fw.maximize() # تكبير النافذة
   >>> fw.isMaximized
   True
 >>> fw.restore() # التراجع عن إجراء التصغير/التكبير
 >>> fw.minimize() # تصغير النافذة
   >>> import time
   >>> # ‫الانتظار 5 ثوانٍ أثناء تنشيط نافذة مختلفة:
 >>> time.sleep(5); fw.activate()
 >>> fw.close() # سيؤدي ذلك إلى إغلاق النافذة التي تكتب فيها

تحتوي السمات isMaximized ➊ و isMinimized ➋ و isActive ➌ على قيمٍ منطقية تشير إلى ما إذا كانت النافذة حاليًا في حالة التكبير أو التصغير أو التنشيط أم لا، بينما تغير التوابع maximize()‎ ➍ و minimize()‎ ➏ و activate()‎ ➐ و restore()‎ ➎ حالة النافذة، وسيعيد التابع restore() النافذة إلى حجمها وموضعها السابق بعد تكبير النافذة أو تصغيرها باستخدام التابعين maximize()‎ و minimize()‎. يغلق التابع close()‎ النافذة، ولكن كن حذرًا عند استخدام هذا التابع، لأنه قد يتجاوز أي مربعات حوار للرسائل التي تطلب منك حفظ عملك قبل الخروج من التطبيق.

يمكن العثور على التوثيق الكامل لميزة التحكم في النوافذ الخاصة بوحدة PyAutoGUI على موقعها الرسمي. يمكنك أيضًا استخدام هذه الميزات بصورة منفصلة عن الوحدة PyAutoGUI مع الوحدة PyGetWindow الذي يمكنك الاطلاع على توثيقها على موقعها الرسمي.

التحكم بلوحة المفاتيح

تحتوي الوحدة PyAutoGUI أيضًا على دوال لإرسال ضغطات مفاتيح افتراضية إلى حاسوبك، والتي تمكّنك من ملء الاستمارات أو إدخال نصٍ في التطبيقات.

إرسال سلسلة نصية من لوحة المفاتيح

ترسل الدالة pyautogui.write()‎ ضغطات مفاتيح افتراضية إلى الحاسوب، حيث يعتمد ما تفعله هذه الضغطات على النافذة النشطة والحقل النصي المُركَّز عليه، لذا قد ترغب أولًا في إرسال نقرة بالفأرة إلى الحقل النصي الذي تريده للتأكد من التركيز عليه.

لنستخدم لغة بايثون لكتابة النص "Hello, world!‎" في نافذة محرر الملفات. افتح أولًا نافذة جديدة في محرّر ملفاتك وَضَعها في الزاوية العلوية اليسرى من شاشتك بحيث تنقر وحدة PyAutoGUI في المكان المناسب للتركيز عليها، ثم أدخِل ما يلي في الصدفة التفاعلية:

>>> pyautogui.click(100, 200); pyautogui.write('Hello, world!')

لاحظ كيف أننا وضعنا أمرين على السطر نفسه، وفصلنا بينهما بفاصلة منقوطة، مما يمنع الصدفة التفاعلية من مطالبتك بالإدخال بين تشغيل هاتين التعليمتين، ويمنعك من التركيز على نافذة جديدة عن طريق الخطأ بين الاستدعائين click()‎ و write()‎ الذي يمكن أن يفسد مثالنا.

سترسل شيفرة بايثون أولًا نقرة افتراضية بالفأرة إلى الإحداثيات ‎(100, 200)‎، والتي يجب أن تنقر على نافذة محرّر الملفات لنقل التركيز إليها، وسيرسل استدعاء الدالة write()‎ النص "Hello, world!‎" إلى النافذة، مما يجعلها تبدو كما في الشكل التالي، وبالتالي أصبح لديك الآن شيفرة برمجية يمكن أن تكتب نيابةً عنك.

07 000001

استخدام وحدة PyAutogGUI للنقر على نافذة محرّر الملفات وكتابة النص "Hello, world!‎" فيها

ستكتب الدالة ‎write()‎‎ افتراضيًا السلسلة النصية الكاملة مباشرةً، ولكن يمكنك تمرير وسيطٍ ثانٍ اختياري لإضافة توقف قصير بين كل محرف والآخر، وهذا الوسيط هو عدد صحيح أو عشري يمثل عدد الثواني للتوقف مؤقتًا، فمثلًا سينتظر الاستدعاء pyautogui.write('Hello, world!', 0.25)‎ ربع ثانية بعد كتابة الحرف H، وربع ثانية أخرى بعد كتابة الحرف e، وإلخ. قد يكون تأثير الآلة الكاتبة التدريجي مفيدًا للتطبيقات الأبطأ التي لا يمكنها معالجة ضغطات المفاتيح بسرعة كافية للتماشي مع الوحدة PyAutoGUI. ستحاكي أيضًا الوحدة PyAutoGUI الضغط باستمرار على مفتاح SHIFT آليًا بالنسبة للمحارف A أو ! .

أسماء المفاتيح

لا يُعَد تمثيل كافة المفاتيح باستخدام محارف نصية مفردة أمرًا سهلًا مثل تمثيل المفتاح SHIFT أو مفتاح السهم الأيسر بمحرف واحد، لذا تمثل وحدة PyAutoGUI مفاتيح لوحة المفاتيح هذه بقيم سلاسل نصية قصيرة، فمثلًا نمثّل مفتاح ESC باستخدام السلسلة النصية 'esc' و نمثّل مفتاح ENTER باستخدام السلسلة النصية 'enter'.

يمكن تمرير قائمة بالسلاسل النصية لهذه المفاتيح إلى الدالة write()‎ بدلًا من تمرير وسيط سلسلة نصية واحدة، فمثلًا يضغط الاستدعاء التالي على المفتاح A ثم على المفتاح B ثم على مفتاح السهم الأيسر مرتين ويضغط أخيرًا على المفتاحين X و Y:

>>> pyautogui.write(['a', 'b', 'left', 'left', 'X', 'Y'])

يؤدي الضغط على مفتاح السهم الأيسر إلى تحريك مؤشر لوحة المفاتيح، لذا سينتج عن ذلك الخرج XYab. يوضّح الجدول الآتي السلاسل النصية لمفاتيح لوحة المفاتيح الخاصة بوحدة PyAutoGUI، والتي يمكنك تمريرها إلى الدالة write()‎ لمحاكاة الضغط على أيّ مجموعة من المفاتيح. يمكنك أيضًا الاطلاع على قائمة pyautogui.KEYBOARD_KEYS لرؤية جميع السلاسل النصية لمفاتيح لوحة المفاتيح المحتملة التي ستقبلها وحدة PyAutoGUI. تشير السلسلة النصية 'shift' إلى مفتاح SHIFT الأيسر وهي تكافئ السلسلة النصية 'shiftleft'، وينطبق الأمر نفسه على السلاسل النصية 'ctrl' و 'alt' و 'win' التي تشير جميعها إلى مفتاح الجهة اليسرى من لوحة المفاتيح.

يوضح الجدول التالي قيم سمات PyKeyboard:

السلسلة النصية لمفتاح لوحة المفاتيح معناها
'a' و 'b' و 'c' و 'A' و 'B' و 'C' و '1' و '2' و '3' و '!' و '@' و '#' وإلخ مفاتيح المحارف المفردة
'enter' (أو 'return' أو '‎\n') مفتاح ENTER
'esc' مفتاح ESC
'shiftleft' و 'shiftright' مفتاحا SHIFT الأيسر والأيمن
'altleft' و 'altright' مفتاحا ALT الأيسر والأيمن
'ctrlleft' و 'ctrlright' مفتاحا CTRL الأيسر والأيمن
'tab' (أو '‎\t') مفتاح TAB
'backspace' و 'delete' مفتاح BACKSPACE ومفتاح DELETE
'pageup' و 'pagedown' مفتاح PAGE UP ومفتاح PAGE DOWN
'home' و 'end' مفتاح HOME ومفتاح END
'up' و 'down' و 'left' و 'right' مفاتيح الأسهم للأعلى وللأسفل وإلى اليسار وإلى اليمين
'f1' و 'f2' و 'f3' وإلخ المفاتيح من F1 إلى F12
'volumemute' و 'volumedown' و 'volumeup' مفاتيح كتم الصوت وخفض مستوى الصوت ورفع مستوى الصوت. لا تحتوي بعض لوحات المفاتيح على هذه المفاتيح، ولكن سيبقى نظام تشغيل حاسوبك قادرًا على فهم محاكاة هذه الضغطات للمفاتيح
'pause' مفتاح PAUSE
'capslock' و 'numlock' و 'scrolllock' مفتاح CAPS LOCK ومفتاح NUM LOCK ومفتاح SCROLL LOCK
'insert' مفتاح INS أو INSERT
'printscreen' مفتاح PRTSC أو PRINT SCREEN
'winleft' و 'winright' مفتاح WIN الأيسر والأيمن على نظام ويندوز
'command' مفتاح Command على نظام ماك ‎ 01 000064
'option' مفتاح OPTION على نظام ماك

الضغط على لوحة المفاتيح وتحريرها

ترسل الدالتان pyautogui.keyDown()‎ و pyautogui.keyUp()‎ ضغطات مفاتيح افتراضية وتحريرها إلى الحاسوب مثل الدالتين mouseDown()‎ و mouseUp()‎، ونمرّر إلى هاتين الدالتين سلسلة نصية لمفاتيح لوحة المفاتيح (اطّلع على الجدول السابق) كوسيطٍ لها. توفّر وحدة PyAutoGUI الدالة pyautogui.press()‎ التي تستدعي هاتين الدالتين لمحاكاة ضغطة كاملة على المفاتيح.

شغّل الشيفرة البرمجية التالية التي ستكتب محرف إشارة الدولار $ الذي نحصل عليه من خلال الضغط على مفتاح SHIFT مع الضغط على الرقم 4:

>>> pyautogui.keyDown('shift'); pyautogui.press('4'); pyautogui.keyUp('shift')

تضغط التعليمة السابقة على مفتاح SHIFT، ثم تضغط على (وتحرر) الرقم 4، ثم تحرّر مفتاح SHIFT. إذا أردتَ كتابة سلسلة نصية في حقل نصي، فستكون الدالة write()‎ أكثر ملاءمة، ولكن ستكون الدالة press()‎ الطريقة الأبسط بالنسبة للتطبيقات التي تأخذ أوامرًا ذات مفتاح واحد.

مجموعات مفاتيح التشغيل السريع Hotkey أو الاختصارات

مفاتيح التشغيل السريع أو الاختصارات هي مجموعة من الضغطات على المفاتيح لاستدعاء بعض وظائف التطبيق، فمفتاح التشغيل السريع الشائع لنسخ تحديدٍ مثلًا هو CTRL-C في نظامي تشغيل ويندوز ولينكس أو ‎01 000064 -C في نظام تشغيل ماك. يضغط المستخدم مع الاستمرار على مفتاح CTRL، ثم يضغط على المفتاح C، ثم يحرّر المفتاحين C و CTRL، حيث يمكننا تطبيق ذلك باستخدام الدالتين keyDown()‎ و keyUp()‎ الخاصتين بالوحدة PyAutoGUI من خلال إدخال ما يلي:

pyautogui.keyDown('ctrl')
pyautogui.keyDown('c')
pyautogui.keyUp('c')
pyautogui.keyUp('ctrl')

يُعَد ذلك معقدًا إلى حدٍ ما، لذا استخدم الدالة pyautogui.hotkey()‎ بدلًا من ذلك، حيث تأخذ هذه الدالة عدة وسطاء تمثّل السلسلة النصية لمفاتيح لوحة المفاتيح، وتضغط عليها بالترتيب، ثم تحررها بالترتيب العكسي، إذ ستكون الشيفرة البرمجية الخاصية بمثال CTRL-C ببساطة كما يلي:

pyautogui.hotkey('ctrl', 'c')

تُعَد هذه الدالة مفيدة خاصةً لمجموعات مفاتيح التشغيل السريع الأكبر حجمًا، فمثلًا تعرض مجموعة مفاتيح التشغيل السريع Ctrl-Alt-Shift-S لوحة الأنماط Style في برنامج وورد Word، حيث يمكنك استخدام الاستدعاء hotkey('ctrl', 'alt', 'shift', 's')‎ فقط بدلًا من إجراء ثمانية استدعاءات لدوال مختلفة (أربعة استدعاءات للدالة keyDown()‎ وأربعة استدعاءات للدالة keyUp()‎).

إعداد سكربتات أتمتة واجهة المستخدم الرسومية

تُعَد سكربتات أتمتة واجهة المستخدم الرسومية طريقةً رائعة لأتمتة المهام المملة، ولكنها قد تكون صعبة التحقيق، حيث إذا كان هناك نافذة في مكان خاطئ على سطح المكتب أو ظهرت بعض النوافذ المنبثقة بطريقة غير متوقعة، فقد ينقر السكربت الخاص بك على الأشياء الخاطئة على الشاشة، لذا إليك بعض النصائح لإعداد سكربتات أتمتة واجهة المستخدم الرسومية:

  • استخدم دقة الشاشة نفسها في كل مرة تشغّل فيها السكربت حتى لا يتغير موضع النوافذ.
  • يجب تكبير نافذة التطبيق التي ينقر عليها السكربت الخاص بك بحيث تكون الأزرار والقوائم في المكان نفسه في كل مرة تشغّل فيها السكربت.
  • أضِف فترات توقف كافية أثناء انتظار تحميل المحتوى، إذ لا تريد أن يبدأ السكربت بالنقر قبل أن يصبح التطبيق جاهزًا.
  • استخدم الدالة locateOnScreen()‎ للعثور على الأزرار والقوائم التي يمكنك النقر عليها بدلًا من الاعتماد على إحداثيات XY. إن لم يتمكّن السكربت الخاص بك من العثور على الشيء الذي يريد النقر عليه، فأوقِف البرنامج بدلًا من السماح له بمواصلة النقر عشوائيًا.
  • استخدم الدالة getWindowsWithTitle()‎ للتأكّد من وجود نافذة التطبيق التي تعتقد أن السكربت الخاص بك ينقر عليها، واستخدم التابع activate()‎ لوضع تلك النافذة في المقدمة.
  • استخدم الوحدة logging التي تحدثنا عنها في مقالٍ سابق للاحتفاظ بملفٍ يسجّل ما فعله السكربت الخاص بك، وبالتالي إذا أوقفتَ السكربت في منتصف العملية، فيمكنك تعديله للمتابعة من مكان توقف هذا السكربت.
  • أضِف أكبر عدد ممكن من عمليات التحقق إلى السكربت الخاص بك، فمثلًا يمكن أن يفشل السكربت إذا ظهرت نافذة منبثقة غير متوقعة أو إذا فقدَ حاسوبك اتصاله بالإنترنت.
  • قد ترغب في الإشراف على السكربت عندما يبدأ لأول مرة للتأكد من أنه يعمل بصورة صحيحة.

قد ترغب أيضًا في التوقف مؤقتًا في بداية السكربت الخاص بك حتى يتمكّن المستخدم من إعداد النافذة التي سينقر عليها السكربت، حيث تحتوي وحدة PyAutoGUI على الدالة sleep()‎ التي تعمل بطريقة مماثلة للدالة time.sleep()‎، ولكنها توفّر عليك الاضطرار إلى إضافة التعليمة import time إلى السكربتات الخاصة بك، وتوجد أيضًا الدالة countdown()‎ التي تطبع أرقام العد التنازلي لمنح المستخدم إشارة مرئية إلى أن السكربت سيستأنف عمله قريبًا. أدخِل مثلًا ما يلي في الصدفة التفاعلية:

>>> import pyautogui
>>> pyautogui.sleep(3) # إيقاف البرنامج مؤقتًا لمدة 3 ثوانٍ
>>> pyautogui.countdown(10) # العد التنازلي لمدة 10 ثوانٍ
10 9 8 7 6 5 4 3 2 1
>>> print('Starting in ', end=''); pyautogui.countdown(3)
Starting in 3 2 1

يمكن أن تساعد هذه النصائح في جعل سكربتات أتمتة واجهة المستخدم الرسومية أسهل في الاستخدام وأكثر قدرة على الاستعادة من الظروف غير المتوقعة.

مراجعة لدوال وحدة PyAutoGUI

يغطي هذا المقال العديد من الدوال المختلفة، لذا سنوضّح فيما يلي مرجعًا موجزًا سريعًا لهذه الدوال:

  • moveTo(x, y)‎: تحرك مؤشر الفأرة إلى إحداثيات x و y المُحدَّدة.
  • move(xOffset, yOffset)‎: تحرك مؤشر الفأرة بالنسبة إلى موضعه الحالي.
  • dragTo(x, y)‎: تحرك مؤشر الفأرة أثناء الضغط المستمر على زر الفأرة الأيسر.
  • drag(xOffset, yOffset)‎: تحرّك مؤشر الفأرة نسبة إلى موضعه الحالي أثناء الضغط المستمر على زر الفأرة الأيسر.
  • click(x, y, button)‎: تحاكي النقر (بزر الفأرة الأيسر افتراضيًا).
  • rightClick()‎: تحاكي النقر بالزر الأيمن.
  • middleClick()‎: تحاكي النقر بالزر الأوسط.
  • doubleClick()‎: تحاكي النقر المزدوج على الزر الأيسر.
  • mouseDown(x, y, button)‎: تحاكي الضغط على الزر المُحدَّد في الموضع x, y.
  • mouseUp(x, y, button)‎: تحاكي تحرير الزر المُحدَّد في الموضع x, y.
  • scroll(units)‎: تحاكي عجلة التمرير في الفأرة، حيث نمرّر وسيطًا موجبًا للتمرير للأعلى، ونمرّر وسيطًا سالبًا للتمرير للأسفل.
  • write(message)‎: تكتب المحارف الموجودة في سلسلة الرسالة النصية المُحدَّدة.
  • write([key1, key2, key3])‎: تكتب سلاسل نصية لمفاتيح لوحة المفاتيح المُحدَّدة.
  • press(key)‎: تضغط على السلسلة النصية لمفتاحٍ محدَّد من لوحة المفاتيح.
  • keyDown(key)‎: تحاكي الضغط على مفتاح لوحة المفاتيح المُحدَّد.
  • keyUp(key)‎: تحاكي تحرير مفتاح لوحة المفاتيح المُحدَّد.
  • hotkey([key1, key2, key3])‎: تحاكي الضغط على السلاسل النصية لمفاتيح لوحة المفاتيح المُحدَّدة بالترتيب ثم تحرّرها بترتيب عكسي.
  • screenshot()‎: تعيد لقطة الشاشة بوصفها كائن Image. اطّلع على المقال السابق للحصول على معلومات حول كائنات Image.
  • getActiveWindow()‎ و getAllWindows()‎ و getWindowsAt()‎ و getWindowsWithTitle()‎: تعيد هذه الدوال كائنات Window التي يمكنها تغيير حجم نوافذ التطبيقات وإعادة تموضعها على سطح المكتب.
  • getAllTitles()‎: تعيد قائمةً بالسلاسل النصية لشريط عنوان كلّ نافذةٍ على سطح المكتب.

اختبارات كابتشا Captcha وأخلاقيات استخدام الحواسيب

تُعَد اختبارات كابتشا Captcha اختصارًا للعبارة الإنجليزية "Completely Automated Public Turing test to tell Computers and Humans Apart" أو "اختبار تورينج العام الآلي بالكامل للتمييز بين الحواسيب والبشر"، وهي الاختبارات الصغيرة التي تطلب منك كتابة حروف موجودة في صورة غير واضحة أو النقر على صور صنابير إطفاء الحرائق مثلًا. يسهُل على البشر اجتياز هذه الاختبارات، ولكن يكاد يكون من المستحيل على البرامج حلها بالرغم من أننا نجدها مزعجة. يمكنك أن ترى بعد قراءة هذا المقال مدى سهولة كتابة سكربت يمكنه التسجيل في مليارات حسابات البريد الإلكتروني المجانية مثلًا أو إغراق المستخدمين برسائل مزعجة، لذا تعمل اختبارات كابتشا على تخفيف ذلك من خلال المطالبة بخطوة لا يمكن إلا للبشر اجتيازها.

لا تطبق جميع مواقع الويب اختبارات كابتشا، وقد تكون عرضةً لإساءة الاستخدام من المبرمجين غير الأخلاقيين، إذ يُعَد تعلّم البرمجة مهارة قوية ومهمة، ولكن قد تميل إلى إساءة استخدام هذه القوة لتحقيق مكاسب شخصية أو حتى لمجرد التفاخر، فلا يُعَد الباب المفتوح مبررًا للتعدّي على ممتلكات الآخرين، لذا تقع مسؤولية برامجك على عاتقك الشخصي بوصفك مبرمجًا. لا يُعَد التحايل على الأنظمة لإحداث ضررٍ أو انتهاك الخصوصية أو الحصول على ميزة غير عادلة معيارًا للذكاء، لذا نأمل أن تركز على عملك دون الضرر بالآخرين.

تطبيق عملي: ملء الاستمارات آليًا

يُعَد ملء الاستمارات مهمةً روتينية مملةً جدًا، إذًا لنفترض مثلًا أن لديك كمية هائلة من البيانات في جدول بيانات، ويجب أن تعيد كتابتها في واجهة استمارة تطبيق آخر دون وجود شخص آخر لإنجاز ذلك نيابةً عنك. تحتوي بعض التطبيقات على ميزة الاستيراد التي تسمح لك برفع جدول بيانات يحتوي على المعلومات، ولكن قد لا توجد طريقة أخرى سوى النقر والكتابة دون اهتمام لساعات متواصلة في بعض الأحيان، لذا لنحاول إيجاد وسيلة لأتمتة هذه المهمة المملة.

استمارة هذا المشروع هي استمارة على مستندات جوجل Google Docs، والتي يمكنك العثور عليها على autbor.com، وتبدو كما يلي:

08 000096

الاستمارة المستخدمَة في هذا المشروع

إليك الخطوات العامة لما يجب أن يفعله برنامجك:

  1. النقر على الحقل النصي الأول من الاستمارة.
  2. التنقل عبر الاستمارة، وكتابة المعلومات في كل حقل.
  3. النقر على زر الإرسال Submit.
  4. تكرار العملية مع المجموعة التالية من البيانات.

وبالتالي يجب أن تطبّق شيفرتك البرمجية الخطوات التالية:

  1. استدعاء الدالة pyautogui.click()‎ للنقر على الاستمارة وزر الإرسال Submit.
  2. استدعاء الدالة pyautogui.write()‎ لإدخال النص في الحقول.
  3. معالجة الاستثناء KeyboardInterrupt حتى يتمكّن المستخدم من الضغط على الاختصار CTRL-C للإنهاء.

افتح نافذة جديدة في محرّرك لإنشاء ملف جديد واحفظه بالاسم formFiller.py.

الخطوة الأولى: معرفة الخطوات ملء الاستمارة

يجب أولًا معرفة ضغطات المفاتيح ونقرات الفأرة التي ستملأ الاستمارة قبل كتابة الشيفرة البرمجية. يمكن أن يساعدك التطبيق الذي يُشغّله استدعاء الدالة pyautogui.mouseInfo()‎ في معرفة إحداثيات الفأرة المُحدَّدة، ويجب معرفة إحداثيات الحقل النصي الأول فقط، ثم يمكنك الضغط على مفتاح TAB لنقل التركيز إلى الحقل التالي بعد النقر على الحقل الأول، مما يوفّر عليك الاضطرار إلى معرفة إحداثيات x و y للنقر على كل حقل.

إليك خطوات إدخال البيانات في الاستمارة:

  1. انقل تركيز لوحة المفاتيح على حقل الاسم Name بحيث يؤدي الضغط على المفاتيح إلى كتابة نص في الحقل.
  2. اكتب اسمًا، ثم اضغط على مفتاح TAB.
  3. اكتب خوفك الأكبر في الحقل Greatest Fear ثم اضغط على مفتاح TAB.
  4. اضغط على مفتاح السهم للأسفل عددًا صحيحًا من المرات لتحديد مصدر قواك السحرية Wizard Power Source، إذ ستضغط مرة واحدة لخيار العصا السحرية wand ومرتين لخيار التعويذة amulet وثلاث مرات لخيار الكرة البلورية crystal ball وأربع مرات لخيار المال money، ثم اضغط على مفتاح TAB. لاحظ أنه يجب أن تضغط على مفتاح السهم للأسفل مرة أخرى لكل خيار في نظام ماك macOS، وقد تحتاج إلى الضغط على مفتاح ENTER أيضًا بالنسبة لبعض المتصفحات.
  5. اضغط على مفتاح السهم الأيمن لتحديد إجابة سؤال RoboCop، واضغط عليه مرة واحدة للخيار 2 أو مرتين للخيار 3 أو ثلاث مرات للخيار 4 أو أربع مرات للخيار 5 أو اضغط على مفتاح المسافة لتحديد الخيار 1 المُحدَّد افتراضيًا، ثم اضغط على مفتاح TAB.
  6. اكتب تعليقًا إضافيًا في الحقل Additional Comments، ثم اضغط على مفتاح TAB.
  7. اضغط على مفتاح ENTER للنقر على زر الإرسال Submit.
  8. سينقلك المتصفح إلى صفحة أخرى بعد إرسال الاستمارة، حيث يجب اتباع رابط في هذه الصفحة للعودة إلى صفحة الاستمارة.

قد تعمل المتصفحات الأخرى على أنظمة تشغيل مختلفة بطريقة مختلفة قليلًا عن الخطوات التي ذكرناها، لذا تأكد من أن هذه المجموعات من ضغطات المفاتيح تعمل على حاسوبك قبل تشغيل البرنامج.

الخطوة الثانية: إعداد الإحداثيات

حمّل مثال الاستمارة التي نزّلتها (الشكل السابق) في المتصفح من خلال الانتقال إلى الرابط autbor.com، واجعل شيفرتك البرمجية كما يلي:

#! python3
# formFiller.py - ملء الاستمارة آليًا

import pyautogui, time

# منح المستخدم فرصةً لإنهاء السكربت

# الانتظار حتى تحميل صفحة الاستمارة

# ‫ملء حقل الاسم Name

# ‫ملء حقل مخاوفك الكبرى Greatest Fear(s)‎

# ملء حقل مصدر قواك السحرية‫ Source of Wizard Powers

# ‫ملء الحقل RoboCop

# ‫ملء حقل التعليقات الإضافية Additional Comments

# الضغط على زر الإرسال‫ Submit

# الانتظار حتى تحميل صفحة الاستمارة

# النقر على رابط إرسال رد آخر

تحتاج الآن البيانات التي تريد إدخالها فعليًا في هذه الاستمارة، حيث قد تأتي هذه البيانات في العالم الحقيقي من جدول بيانات أو ملف نص عادي أو من موقع ويب، وقد تتطلب شيفرة برمجية إضافية لتحميلها في البرنامج، ولكننا سنكتب كل هذه البيانات ضمن متغير في مثالنا، لذا أضِف ما يلي إلى برنامجك:

#! python3
# formFiller.py - ملء الاستمارة آليًا

--snip--

formData = [{'name': 'Alice', 'fear': 'eavesdroppers', 'source': 'wand',
            'robocop': 4, 'comments': 'Tell Bob I said hi.'},
            {'name': 'Bob', 'fear': 'bees', 'source': 'amulet', 'robocop': 4,
            'comments': 'n/a'},
            {'name': 'Carol', 'fear': 'puppets', 'source': 'crystal ball',
            'robocop': 1, 'comments': 'Please take the puppets out of the
            break room.'},
            {'name': 'Alex Murphy', 'fear': 'ED-209', 'source': 'money',
            'robocop': 5, 'comments': 'Protect the innocent. Serve the public
            trust. Uphold the law.'},
           ]

--snip

تحتوي القائمة formData على أربعة قواميس لأربعة أسماء مختلفة، ويحتوي كل قاموس على أسماء الحقول النصية كمفاتيحٍ له والردود كقيمٍ له. أخيرًا، نضبط المتغير PAUSE الخاص بوحدة PyAutoGUI للانتظار لمدة نصف ثانية بعد كل استدعاء دالة، ونذكّر المستخدم بالنقر على المتصفح لجعله النافذة النشطة. أضِف ما يلي إلى برنامجك بعد تعليمة إسناد قيمٍ إلى القائمة formData:

pyautogui.PAUSE = 0.5
print('Ensure that the browser window is active and the form is loaded!')

الخطوة الثالثة: البدء في كتابة البيانات

سنكرّر حلقة for على كلٍّ من القواميس الموجودة في قائمة formData، ونمرّر القيم الموجودة في القاموس إلى دوال وحدة PyAutoGUI التي ستكتب فعليًا في الحقول النصية.

أضِف الشيفرة البرمجية التالية إلى برنامجك:

#! python3
# formFiller.py - ملء الاستمارة آليًا

--snip--

for person in formData:
    # منح المستخدم فرصةً لإنهاء السكربت
    print('>>> 5-SECOND PAUSE TO LET USER PRESS CTRL-C <<<')
   time.sleep(5)

--snip

يحتوي السكربت على توقف مؤقت لمدة خمس ثوانٍ ➊ كميزة أمانٍ صغيرة، مما يمنح المستخدم فرصةً للضغط على Ctrl-C (أو تحريك مؤشر الفأرة إلى الزاوية العلوية اليسرى من الشاشة لرفع استثناء FailSafeException) لإيقاف تشغيل البرنامج في حالة أنه يعمل شيئًا غير متوقع. أضِف ما يلي بعد الشيفرة البرمجية التي تنتظر إعطاء الصفحة وقتًا للتحميل:

#! python3
# formFiller.py - ملء الاستمارة آليًا

--snip--

   print('Entering %s info...' % (person['name']))
   pyautogui.write(['\t', '\t'])

     # ‫ملء حقل الاسم Name
   pyautogui.write(person['name'] + '\t')

     # ملء حقل مخاوفك الكبرى‫ Greatest Fear(s)‎
   pyautogui.write(person['fear'] + '\t')

--snip

نضيف استدعاء الدالة print()‎ من حينٍ لآخر لعرض حالة البرنامج في نافذته الطرفية لإعلام المستخدم بما يحدث ➊.

حصلت الاستمارة على وقتها الكافي للتحميل، لذا نستدعي الدالة pyautogui.write(['\t', '\t'])‎ للضغط على مفتاح TAB مرتين والتركيز على حقل الاسم Name ➋، ثم نستدعي الدالة write()‎ مرة أخرى لإدخال السلسلة النصية في person['name']‎ ➌. نضيف المحرف ‎'\t'‎ إلى نهاية السلسلة النصية التي نمرّرها إلى الدالة write()‎ لمحاكاة الضغط على مفتاح TAB، مما ينقل تركيز لوحة المفاتيح إلى الحقل التالي وهو Greatest Fear(s)‎. يؤدي استدعاءٌ آخر للدالة write()‎ إلى كتابة السلسلة النصية في person['fear']‎ ضمن هذا الحقل ثم ينتقل إلى الحقل التالي في الاستمارة ➍.

الخطوة الرابعة: التعامل مع قوائم التحديد وأزرار الاختيار

تُعَد القائمة المنسدلة لسؤال "القوى السحرية Wizard Powers" وأزرار الاختيار الخاصة بحقل RoboCop أصعب في التعامل من الحقول النصية، حيث يمكنك النقر على هذه الخيارات باستخدام الفأرة من خلال معرفة إحداثيات x و y لكل خيار ممكن، ولكن من الأسهل استخدام مفاتيح الأسهم في لوحة المفاتيح لإجراء التحديد بدلًا من ذلك.

أضِف ما يلي إلى برنامجك:

#! python3
# formFiller.py - ملء الاستمارة آليًا

--snip--

     # ملء حقل مصدر قواك السحرية‫ Source of Wizard Powers
   if person['source'] == 'wand':
       pyautogui.write(['down', '\t'] , 0.5)
     elif person['source'] == 'amulet':
         pyautogui.write(['down', 'down', '\t'] , 0.5)
     elif person['source'] == 'crystal ball':
         pyautogui.write(['down', 'down', 'down', '\t'] , 0.5)
     elif person['source'] == 'money':
         pyautogui.write(['down', 'down', 'down', 'down', '\t'] , 0.5)

     # ملء الحقل‫ RoboCop
   if person['robocop'] == 1:
       pyautogui.write([' ', '\t'] , 0.5)
     elif person['robocop'] == 2:
         pyautogui.write(['right', '\t'] , 0.5)
     elif person['robocop'] == 3:
         pyautogui.write(['right', 'right', '\t'] , 0.5)
     elif person['robocop'] == 4:
         pyautogui.write(['right', 'right', 'right', '\t'] , 0.5)
     elif person['robocop'] == 5:
         pyautogui.write(['right', 'right', 'right', 'right', '\t'] , 0.5)

--snip

تذكر أنك كتبتَ شيفرة برمجية لمحاكاة الضغط على مفتاح TAB بعد ملء حقل المخاوف الكبرى Greatest Fear(s)‎، وبالتالي سيؤدي الضغط على مفتاح السهم للأسفل إلى الانتقال إلى العنصر التالي في قائمة التحديد بعد التركيز على القائمة المنسدلة. يجب أن يرسل برنامجك عددًا من ضغطات مفاتيح السهم للأسفل قبل الانتقال إلى الحقل التالي اعتمادًا على القيمة الموجودة فيperson['source']‎، حيث إذا كانت قيمة مفتاح 'source' الموجودة في قاموس هذا المستخدم هي 'wand' ➊، فسنحاكي الضغط على مفتاح السهم للأسفل مرة واحدة (لتحديد القيمة Wand) والضغط على مفتاح TAB ➋. إذا كانت القيمة الموجودة في مفتاح 'source' هي 'amulet'، فسنحاكي الضغط على مفتاح السهم للأسفل مرتين والضغط على مفتاح TAB، وينطبق الشيء نفسه بالنسبة للإجابات المُحتمَلة الأخرى. يضيف الوسيط 0.5 في استدعاءات الدالة write()‎ توقفًا مؤقتًا لمدة نصف ثانية بين المفاتيح حتى لا يتحرك البرنامج بسرعة كبيرة في الاستمارة.

يمكن تحديد أزرار الاختيار الخاصة بسؤال RoboCop باستخدام مفاتيح الأسهم إلى اليمين، أو إذا أردتَ تحديد الخيار الأول ➌، فاضغط على على شريط المسافة فقط ➍.

الخطوة الخامسة: إرسال الاستمارة ثم الانتظار

يمكنك ملء حقل التعليقات الإضافية Additional Comments باستخدام الدالة write()‎ من خلال تمرير person['comments']‎ كوسيطٍ لها. يمكنك كتابة مفتاح ‎'\t'‎ إضافي لنقل تركيز لوحة المفاتيح إلى الحقل التالي أو إلى زر الإرسال Submit. سيؤدي استدعاء الدالة pyautogui.press('enter')‎ إلى محاكاة الضغط على مفتاح ENTER وإرسال الاستمارة بعد التركيز على زر الإرسال Submit، ثم سينتظر برنامجك خمس ثوانٍ حتى تحميل الصفحة التالية.

ستحتوي الصفحة الجديدة بعد تحميلها على رابط إرسال ردٍ آخر الذي سيوجّه المتصفح إلى صفحة استمارة جديدة فارغة، حيث خزّنا إحداثيات هذا الرابط بوصفها مجموعةً في المتغير submitAnotherLink في الخطوة الثانية، لذا مرّر هذه الإحداثيات إلى الدالة pyautogui.click()‎ للنقر على هذا الرابط.

يمكن لحلقة for الخارجية الخاصة بالسكربت الاستمرار إلى التكرار التالي وإدخال معلومات الشخص التالي في الاستمارة عندما تكون الاستمارة الجديدة جاهزة.

أكمِل برنامجك بإضافة الشيفرة البرمجية التالي:

#! python3
# formFiller.py - ملء الاستمارة آليًا

--snip--

    # ‫ملء حقل التعليقات الإضافية Additional Comments
    pyautogui.write(person['comments'] + '\t')

    # الضغط على زر الإرسال‫ Submit من خلال الضغط على مفتاح Enter
    time.sleep(0.5) # Wait for the button to activate.
    pyautogui.press('enter')

    # الانتظار حتى تحميل صفحة الاستمارة
    print('Submitted form.')
    time.sleep(5)

    # النقر على رابط إرسال رد آخر
    pyautogui.click(submitAnotherLink[0], submitAnotherLink[1])

سيُدخِل البرنامج المعلومات الخاصة بكل شخص بعد انتهاء حلقة for الرئيسية، حيث يوجد في مثالنا أربعة أشخاص للإدخال فقط، ولكن إذا كان لديك 4000 شخص، فستوفر كتابة برنامج لإنجاز ذلك عليك الكثير من الوقت والكتابة.

عرض مربعات الرسائل

تميل جميع البرامج التي كتبناها حتى الآن إلى استخدام خرجٍ يحتوي على نصٍ عادي باستخدام الدالة print()‎ ودخلٍ يحتوي على نصٍ عادي باستخدام الدالة input()‎، ولكن ستستخدم برامج PyAutoGUI سطح المكتب بأكمله، إذ يُحتمَل فقدان النافذة النصية التي يعمل فيها برنامجك سواء كانت نافذة المحرّر Mu أو نافذة طرفية Terminal عندما ينقر برنامج PyAutoGUI الخاص بك ويتفاعل مع النوافذ الأخرى، مما يصعّب الحصول على الدخل والخرج من المستخدم عند إخفاء نوافذ المحرّر Mu أو نافذة الطرفية تحت نوافذ أخرى. يمكن حل هذه المشكلة باستخدام وحدة PyAutoGUI التي تقدّم مربعات رسائل منبثقة لتقديم إشعارات للمستخدم وتلقي الدخل منه، إذ توجد أربع دوال لمربعات الرسائل وهي:

  • pyautogui.alert(text)‎: تعرض النص text وتحتوي على زر موافقة OK واحد. +pyautogui.confirm(text)‎: تعرض النص text وتحتوي على زر موافقة OK وزر إلغاء Cancel، وتعرض إما 'OK' أو 'Cancel' اعتمادًا على الزر الذي نقرنا عليه.
  • pyautogui.prompt(text)‎: تعرض النص text وتحتوي على حقل نصي ليكتب المستخدم فيه، والذي تعيده كسلسلة نصية.
  • pyautogui.password(text)‎: تماثل الدالة prompt()‎، ولكنها تعرض علامات نجمية على النص المُدخَل حتى يتمكّن المستخدم من إدخال معلومات حساسة مثل كلمة المرور.

تحتوي هذه الدوال أيضًا على معاملٍ ثانٍ اختياري يقبل قيمة سلسلة نصية لاستخدامها بوصفها عنوانًا في شريط العنوان الخاص بمربع الرسالة. لن تعود هذه الدوال حتى ينقر المستخدم على الزر الموجود عليها، لذلك يمكن استخدامها أيضًا لإدخال فترات توقف مؤقت في برامج PyAutoGUI الخاصة بك. أدخِل مثلًا ما يلي في الصدفة التفاعلية:

>>> import pyautogui
>>> pyautogui.alert('This is a message.', 'Important')
'OK'
>>> pyautogui.confirm('Do you want to continue?') # اضغط على زر الإلغاء
'Cancel'
>>> pyautogui.prompt("What is your cat's name?")
'Zophie'
>>> pyautogui.password('What is the password?')
'hunter2'

تبدو مربعات الرسائل المنبثقة التي تنتجها السطور السابقة كما يلي:

09 000043

النوافذ من أعلى اليسار إلى أسفل اليمين هي: النوافذ التي تنشئها الدوال alert()‎ و confirm()‎ و prompt()‎ وpassword()‎

يمكن استخدام هذه الدوال لتقديم إشعارات أو طرح أسئلة على المستخدم أثناء تفاعل باقي البرنامج مع الحاسوب من خلال الفأرة ولوحة المفاتيح. اطّلع على التوثيق الكامل عبر الإنترنت للوحدة PyMsgBox على موقعها الرسمي.

مشاريع للتدريب

حاول كتابة البرامج التي تؤدي المهام التي سنوضّحها فيما يلي لكسب خبرة عملية أكبر.

برنامج لإبقاء الحالة "مشغول" على برنامج المراسلة الفورية

تحدّد العديد من برامج المراسلة الفورية ما إذا كنت في وضع السكون أو كنت بعيدًا عن حاسوبك من خلال اكتشاف عدم وجود حركة للفأرة خلال فترة زمنية معينة مثل 10 دقائق. قد تكون بعيدًا عن حاسوبك ولكنك لا تريد أن يرى الآخرون حالة المراسلة الفورية الخاصة بك وهي في وضع السكون، لذا اكتب برنامجًا لتحريك مؤشر الفأرة قليلًا كل 10 ثوانٍ، حيث يجب أن تكون الحركة صغيرة وغير متكررة بدرجة كافية حتى لا تعترض طريقك إذا أردتَ استخدام حاسوبك أثناء تشغيل السكربت.

استخدام الحافظة Clipboard لقراءة حقل نصي

يمكنك إرسال ضغطات المفاتيح إلى الحقول النصية في التطبيق باستخدام الدالة pyautogui.write()‎، ولكن لا يمكنك استخدام وحدة PyAutoGUI وحدها لقراءة النص الموجود فعليًا ضمن الحقل النصي، لذا يمكن أن تساعد الوحدة Pyperclip في ذلك. استخدم الوحدة PyAutoGUI للحصول على نافذة محرّر نصوص مثل المحرّر Mu أو المفكرة Notepad، وإحضارها إلى مقدمة الشاشة من خلال النقر عليها، ثم النقر داخل الحقل النصي، وإرسال مفتاح التشغيل السريع CTRL-A أو ‎01 000064 -A لتحديد الكل وإرسال مفتاح التشغيل السريع Ctrl-C أو ‎01 000064 -C للنسخ إلى الحافظة، ويمكن لسكربت بايثون بعد ذلك قراءة نص الحافظة من خلال تشغيل التعليمتين import pyperclip و pyperclip.paste()‎.

اكتب برنامجًا يتبع هذا الإجراء لنسخ النص من الحقول النصية في النافذة، لذا استخدم الدالة pyautogui.getWindowsWithTitle('Notepad')‎ (أو أي محرّر نصوص تختاره) للحصول على كائن Window. يمكن لسمات top و left لكائن Window أن تخبرك بمكان هذه النافذة، وسيضمن التابع activate()‎ وجودها في مقدمة الشاشة. يمكنك بعد ذلك النقر على الحقل النصي الرئيسي لمحرّر النصوص من خلال إضافة 100 أو 200 بكسل مثلًا إلى قيم السمات top و left باستخدام التابع pyautogui.click()‎ لنقل تركيز لوحة المفاتيح إلى هذا الحقل، ثم استدعِ الدالتين pyautogui.hotkey('ctrl', 'a')‎ و pyautogui.hotkey('ctrl', 'c')‎ لتحديد النص بأكمله ونسخه إلى الحافظة. أخيرًا، استدعِ الدالة pyperclip.paste()‎ لاسترداد النص من الحافظة ولصقه في برنامج بايثون. يمكنك بعد ذلك استخدام هذه السلسلة النصية كما تريد، ولكن مرّرها إلى الدالة print()‎ حاليًا.

لاحظ أن دوال النافذة الخاصة بوحدة PyAutoGUI تعمل فقط على نظام ويندوز بدءًا من الإصدار 1.0.0 من وحدة PyAutoGUI، ولن تعمل على نظام ماك macOS أو لينكس.

بوت المراسلة الفورية

تستخدم برامج المراسلة الفورية بروتوكولاتٍ خاصة تصعّب كتابة وحدات بايثون التي يمكنها التفاعل مع هذه البرامج، ولكن لا يمكن لهذه البروتوكولات الخاصة منعك من كتابة أداة أتمتة لواجهة المستخدم الرسومية.

يحتوي تطبيق واتس أب Whatsapp على شريط بحث يتيح لك إدخال اسم مستخدم في قائمة أصدقائك وفتح نافذة مراسلة عند الضغط على مفتاح ENTER، حيث ينتقل تركيز لوحة المفاتيح إلى النافذة الجديدة آليًا، وتمتلك تطبيقات المراسلة الفورية الأخرى طرقًا مشابهة لفتح نوافذ الرسائل الجديدة. اكتب برنامجًا يرسل رسالة إشعار آليًا إلى مجموعة مختارة من الأشخاص في قائمة أصدقائك، وقد يضطر برنامجك إلى التعامل مع حالات استثنائية مثل ظهور نافذة الدردشة في إحداثيات مختلفة على الشاشة، أو ظهور مربعات التأكيد التي تقاطع رسائلك. يجب على برنامجك التقاط لقطات شاشة لتوجيه تفاعل واجهة المستخدم الرسومية واعتماد طرقٍ لاكتشاف متى لا تُرسَل ضغطات المفاتيح الافتراضية.

ملاحظة: قد ترغب في إعداد بعض الحسابات التجريبية الوهمية حتى لا ترسل رسائل غير مرغوب فيها إلى أصدقائك الحقيقيين عن طريق الخطأ أثناء كتابة هذا البرنامج.

الخلاصة

تتيح لك أتمتة واجهة المستخدم الرسومية باستخدام وحدة pyautogui التفاعل مع التطبيقات الموجودة على حاسوبك من خلال التحكم في الفأرة ولوحة المفاتيح، حيث يُعَد هذا النهج مرنًا بما يكفي لفعل أيّ شيء يمكن للمستخدم تطبيقه، ولكن يتمثّل جانبه السلبي في أن هذه البرامج لا تستطيع رؤية ما تنقر عليه أو تكتبه. حاول التأكد من أن برامج أتمتة واجهة المستخدم الرسومية عند كتابتها ستتعطّل بسرعة عند إعطائها تعليمات سيئة، إذ قد يكون تعطل البرنامج أمرًا مزعجًا، ولكنه أفضل بكثير من استمرار البرنامج مع وجود الخطأ.

يمكنك تحريك مؤشر الفأرة على الشاشة ومحاكاة نقرات الفأرة وضغطات المفاتيح واختصارات لوحة المفاتيح باستخدام وحدة PyAutoGUI التي يمكنها أيضًا التحقق من الألوان على الشاشة، ويمكنها أن تزوّد برنامج أتمتة واجهة المستخدم الرسومية الخاص بك بفكرة كافية عن محتويات الشاشة لمعرفة خروجه عن المسار الصحيح أم لا، ويمكنك إعطاء الوحدة PyAutoGUI لقطة شاشة والسماح لها بمعرفة إحداثيات المنطقة التي تريد النقر عليها.

يمكنك الجمع بين جميع ميزات PyAutoGUI لأتمتة أيّ مهمة متكررة على حاسوبك. قد تكون مشاهدة مؤشر الفأرة يتحرك من تلقاء نفسه ورؤية النص يظهر على الشاشة آليًا أمرًا مملًا للغاية، ولكن يوجد شعور معين بالرضا يأتي من رؤية كيف أنقذك ذكاؤك من إنجاز المهام المملة.

ترجمة -وبتصرُّف- للمقال Controlling the Keyboard and Mouse with GUI Automation لصاحبه Al Sweigart.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...