مكتبة Playwright – بديل مايكروسوفت لأتمتة متصفحات الإنترنت

مكاتب بايثون Playwright لأتمتة الصفحات :
مكاتب بايثون بلايورايت : تنوعت أنشطة مايكروسوفت مؤخرًا فيما يخص دعم نظام تشغيل لينكس وعدد من المشاريع المفتوحة المصدر سواء كانت تمتلكها مثل vscode، أو التي لا تمتلكها، مثل لينكس بحد ذاته. ولكننا اليوم لدينا شيء جديد ومختلف، قد لا يكون مفتوح المصدر، ولكنه مجاني ويتمتع بالقوة بنفس الوقت. إنها مكتبة بايثون جديدة مقدمة من مايكروسوفت في أتمتة متصفحات الويب، وتُعد هذه المكتبة الجديدة المنافس الحديث والأقوى لمكتبة سيلينيوم -والتي قد تتفوق عليها قريبا بجدارة.
نتحدث اليوم في بايثونات عن مكتبة جديدة وواعدة، إنها مكتبة بلايرايت Playwright من مايكروسوفت.
أهلا بكم في مقال جديد، ومميز كالعادة من مدونة بايثونات، المدونة العربية الأولى المتخصصة في لغة البرمجة العظيمة بايثون.
أتاحت مايكروسوفت المكتبة للاستخدام عبر لغات عديدة مثل لغة البرمجة بايثون ولغة سي شارب ولغة جافا سكريبت. في هذا المقال، سنستخدم المكتبة من أجل تجريف بعض البيانات في موقع https://quotes.toscrape.com/js/، كما وسنستعرض بعض المزايا التي تقدمها المكتبة والتي تفيدنا في أتمتة عملية التجريف.
تثبيت المكتبة :
أولًا، لنثبت المكتبة :
ولذلك، أمامنا خياران، إما عن طريق pip أو pipenv. حتى نضرب عصفورين بحجر واحد، سنستخدم هذه المرة pipenv لتنصيب المكتبة وفي نفس الوقت لعمل بيئة افتراضية معزولة. ننشئ مجلد جديد باسم مناسب، ومن ثم نقوم بالولوج إليه عبر سطر الأوامر ومن ثم نكتب الأمر التالي:
[pastacode lang=”bash” manual=”Pipenv%20shell” message=”” highlight=”” provider=”manual”/]
يقوم الأمر السابق بعمل بيئة افتراضية كاملة. نثبت المكتبات التالية لمشروعنا والتي من ضمنها مكتبة playwright:
[pastacode lang=”bash” manual=”Pipenv%20install%20playwright%20pandas” message=”” highlight=”” provider=”manual”/]
و بعد التنصيب نكتب الأمر التالي والذي يجب تنفيذه لمرة واحدة من أجل عمل المكتبة الجديدة playwright:
[pastacode lang=”python” manual=”Playwright%20install” message=”” highlight=”” provider=”manual”/]
هذا الأمر سيقوم بتنصيب ملفات ومسوقات Drivers سنحتاجها للتحكم بالمتصفحات التي لدينا، سواء كانت كروميوم، فايرفوكس، أو متصفح ويب كيت.
تجريف صفحة جافا سكريبت :
سنجرف نسخة جافا سكريبت من الصفحة المستهدفة، والتي تقوم ديناميكيا بتوليد مكوناتها، وبالتالي يصعب تجريفها بالطريقة العادية عبر كتابة المحددات Selectors لمكونات الصفحة في HTML، لأنه وبكل بساطه لن تظهر للسكريبت.
هنا سنعمل على أتمته المتصفح، والذي سيرى شفرة الـ html كاملة ومن خلال ذلك سنجرف باستخدام xpath . لتعلم المزيد من لغة xpath selectors يمكنك الإطلاع علي الرابط التالي:
[pastacode lang=”python” manual=”from%20playwright.sync_api%20import%20sync_playwright%0Aimport%20os%0Aimport%20pandas%20as%20pd%0A%0Adef%20main()%3A%0A%20%20%20%20%23%20sync_playwright%20is%20a%20context%20manager%20type%2C%20so%20use%20the%20’with’%0A%20%20%20%20with%20sync_playwright()%20as%20p%3A%0A%20%20%20%20%20%20%20%20%23%20setting%20your%20script%20to%20run%20as%20an%20iphone%20device%0A%20%20%20%20%20%20%20%20p.devices%5B’iPhone%2012%20Pro’%5D%0A%20%20%20%20%20%20%20%20%23%20by%20default%20the%20browser%20runs%20in%20the%20background%2C%20by%20setting%20headless%3D%20False%0A%20%20%20%20%20%20%20%20%23%20it%20will%20show%20on%20the%20screen%0A%20%20%20%20%20%20%20%20browser%20%3D%20p.chromium.launch(headless%3DFalse)%0A%20%20%20%20%20%20%20%20%23%20creating%20a%20new%20page%20instance%0A%20%20%20%20%20%20%20%20page%20%3D%20browser.new_page()%0A%20%20%20%20%20%20%20%20%23%20setting%20our%20custom%20headers%20for%20our%20browser%20on%20our%20iphone%20device%0A%20%20%20%20%20%20%20%20page.set_content(%22%7B%20userAgent%3A%20’Mozilla%2F5.0%20(Windows%20NT%2010.0%3B%20Win64%3B%20×64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F83.0.4103.116%20Safari%2F537.36’%20%7D%22)%0A%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%23%20%D9%81%D8%AA%D8%AD%20%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9%20%D8%A7%D9%84%D9%85%D8%B7%D9%84%D9%88%D8%A8%D8%A9%0A%20%20%20%20%20%20%20%20page.goto(‘https%3A%2F%2Fquotes.toscrape.com%2Fjs%2F’)%0A%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%23%20%D8%AA%D8%AD%D8%AF%D9%8A%D8%AF%20%D9%88%D9%82%D8%AA%20%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B8%D8%A7%D8%B1%20%D8%A8%D8%A7%D9%84%D9%85%D9%84%D9%84%D9%8A%20%D8%AB%D8%A7%D9%86%D9%8A%D8%A9%0A%20%20%20%20%20%20%20%20page.wait_for_timeout(3000)%20%23%20time%20in%20millisecs%0A%0A%20%20%20%20%20%20%20%20%23%20%D8%B7%D8%A8%D8%A7%D8%B9%D8%A9%20%D8%B9%D9%86%D9%88%D8%A7%D9%86%20%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9%20%0A%20%20%20%20%20%20%20%20print(page.title())%0A%0A%20%20%20%20%20%20%20%20%23%20%D9%84%D9%84%D8%AD%D8%B5%D9%88%D9%84%20%D8%B9%D9%84%D9%89%20%D8%A7%D9%84%D8%B4%D9%81%D8%B1%D8%A9%20%D8%A7%D9%84%D9%85%D8%B5%D8%AF%D8%B1%D9%8A%D8%A9%20%D9%84%D9%84%D8%B5%D9%81%D8%AD%D8%A9%0A%20%20%20%20%20%20%20%20page_source%20%3D%20page.content()%20%23%20page%20source%0A%0A%0A%20%20%20%20%20%20%20%20%23%D8%A7%D8%B9%D8%AA%D8%A8%D8%B1%D9%86%D8%A7%20%D8%A3%D9%86%20%D9%83%D9%84%20%D9%82%D8%B3%D9%85%20%D9%8A%D8%AD%D9%88%D9%8A%20%D8%A7%D9%84%D9%85%D9%82%D9%88%D9%84%D8%A9%20%D9%88%20%D8%A8%D8%A7%D9%82%D9%8A%20%D8%A7%D9%84%D9%85%D8%B9%D9%84%D9%88%D9%85%D8%A7%D8%AA%20%D9%83%D8%A8%D8%B7%D8%A7%D9%82%D8%A9%0A%20%20%20%20%20%20%20%20%23%20query_selecor_all()%20%D8%AA%D9%82%D9%88%D9%85%20%D8%A8%D8%AC%D9%85%D8%B9%20%D8%AC%D9%85%D9%8A%D8%B9%20%D8%A7%D9%84%D8%A8%D8%B7%D8%A7%D9%82%D8%A7%D8%AA%20%2C%20query_selecor()%20%D8%AA%D8%B1%D8%AC%D8%B9%20%D9%81%D9%82%D8%B7%20%D8%A3%D9%88%D9%84%20%D8%A8%D8%B7%D8%A7%D9%82%D8%A9%0A%20%20%20%20%20%20%20%20%23%D8%AA%D9%82%D8%A8%D9%84%20%D8%A7%D9%84%D8%AF%D8%A7%D9%84%D8%A9%20xpath%20%D8%A3%D9%88%20css%20selectors%20%D8%A8%D8%B4%D9%83%D9%84%20%D8%A3%D9%88%D8%AA%D9%88%D9%85%D8%A7%D8%AA%D9%8A%D9%83%D9%8A%0A%20%20%20%20%20%20%20%20cards%20%3D%20page.query_selector_all(%22%2F%2Fdiv%5B%40class%3D’quote’%5D%22)%0A%0A%20%20%20%20%20%20%20%20%23%20%D9%82%D8%A7~%D9%85%D8%A9%20%D9%84%D8%AC%D9%85%D8%B9%20%D9%82%D9%88%D8%A7%D9%85%D9%8A%D8%B3%20%D8%AA%D8%AD%D9%88%D9%8A%20%D9%85%D8%B9%D9%84%D9%88%D9%85%D8%A7%D8%AA%20%D8%A7%D9%84%D8%A8%D8%B7%D8%A7%D9%82%D8%A7%D8%AA%0A%20%20%20%20%20%20%20%20data_list%20%3D%20%5B%5D%0A%0A%20%20%20%20%20%20%20%20%23%20%D8%A7%D9%84%D8%AD%D8%B5%D9%88%D9%84%20%D8%B9%D9%84%D9%89%20%D8%AA%D9%81%D8%A7%D8%B5%D9%8A%D9%84%20%D8%A7%D9%84%D8%A8%D8%B7%D8%A7%D9%82%D8%A7%D8%AAh%0A%20%20%20%20%20%20%20%20%23%20%D9%88%20%D8%AC%D9%85%D8%B9%D9%87%D8%A7%20%D9%81%D9%8A%20%D9%82%D9%88%D8%A7%D9%85%D9%8A%D8%B3%20%D8%AB%D9%85%20%D8%A7%D8%B6%D8%A7%D9%81%D8%AA%D9%87%D8%A7%20%D9%84%D9%84%D9%82%D8%A7%D8%A6%D9%85%D8%A9%0A%20%20%20%20%20%20%20%20for%20card%20in%20cards%3A%0A%0A%20%20%20%20%20%20%20%20%20%20%20data_list.append(%7B%0A%20%20%20%20%20%20%20%20%20%20%20%22quote%22%20%3A%20%20card.query_selector(%22%2F%2Fspan%5B%40class%3D’text’%5D%22).inner_text()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%22author%22%20%3A%20%20card.query_selector(%22%2F%2Fspan%2Fsmall%5B%40class%3D’author’%5D%22).inner_text()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%22tags%22%20%3A%20(%22%2C%22).join(%5Btag.inner_text()%20for%20tag%20in%20card.query_selector_all(%22%2F%2Fdiv%5B%40class%3D’tags’%5D%2Fa%5B%40class%3D’tag’%5D%22)%5D)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%7D)%0A%20%0A%20%20%20%20%20%20%20%20%23%20%D8%AA%D8%AD%D9%88%D9%8A%D9%84%20%D8%A7%D9%84%D9%82%D8%A7%D8%A6%D9%85%D8%A9%20%D8%AF%D8%A7%D8%AA%D8%A7%20%D9%81%D8%B1%D9%8A%D9%85%20%0A%20%20%20%20%20%20%20%20df%20%3D%20pd.DataFrame(data_list)%0A%0A%20%20%20%20%20%20%20%20%23%20%D8%B7%D8%A8%D8%A7%D8%B9%D8%A9%20%D8%A7%D9%84%D8%AF%D8%A7%D8%AA%D8%A7%20%D9%81%D8%B1%D9%8A%D9%85%0A%20%20%20%20%20%20%20%20print(df)%0A%0A%20%20%20%20%20%20%20%20%23%20%D8%A7%D9%84%D9%84%D8%B9%D8%A8%20%D9%84%D8%AA%D8%AC%D8%B1%D8%A8%D8%A9%20%D8%A8%D8%B9%D8%B6%20%D8%A7%D9%84%D9%85%D8%B2%D8%A7%D9%8A%D8%A7%20%D8%A7%D9%84%D8%A3%D8%AE%D8%B1%D9%89%0A%20%20%20%20%20%20%20%20login%20%3D%20page.query_selector(‘%2F%2Fa%5B%40href%3D%22%2Flogin%22%5D’).click()%20%23%20clicking%0A%20%20%20%20%20%20%20%20username%20%20%3D%20page.query_selector(‘%2F%2Finput%5B%40type%3D%22text%22%5D’).type(‘nasserooooo’)%20%23%20filling%20fields%0A%20%20%20%20%20%20%20%20password%20%3D%20page.query_selector(‘%2F%2Finput%5B%40type%3D%22password%22%5D’).type(‘passwooooorjjjjj’)%0A%20%20%20%20%20%20%20%20page.query_selector(‘%2F%2Finput%5B%40type%3D%22submit%22%5D’).click()%0A%0A%20%20%20%20%20%20%20%20%23%20saving%20our%20scraped%20data%20in%20a%20csv%20file%0A%20%20%20%20%20%20%20%20df.to_csv(‘C%3A%5C%5CUsers%5C%5C00106%5C%5CDesktop%5C%5Cj_farah%5C%5Cquotes_first_page.csv’)%0A%0A%20%20%20%20%20%20%20%20page.wait_for_timeout(10000)%20%23%20time%20in%20millisecs%0A%20%20%20%20%20%20%20%20browser.close()%20%23%20closing%20the%20browser%0A%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20os.system(‘cls’)%0A%20%20%20%20main()%0A” message=”” highlight=”” provider=”manual”/]
من المميزات الجميلة في مكتبة playwright أنها تتيح للمستخدم توليد شفرة برمجية لجميع اللغات التي تدعمها عن طريق تسجيل ما يقوم به المستخدم في المتصفح. في سطر الأوامر أكتب الأمر التالي وسيفتح لك متصفح من قبل المكتبة وكذلك صفحة الكود الذي يتم توليده في الوقت الحقيقي كلما تفاعلت مع المتصفح ومكونات الصفحة:
[pastacode lang=”bash” manual=”playwright.exe%20codegen%20www.pythonat.com” message=”” highlight=”” provider=”manual”/]
نلاحظ أنه كلما تفاعلنا مع الصفحة من حيث الضغط على أي شيء أو أدخال شيء ستقوم المكتبة بتسجيله ككود بايثون أو أي لغة تدعمها في محرر النصوص الجانبي كما في الصورة. أي أنه يقوم بتسجيل وكتابة ماكرو بشكل أوتوماتيكي كما في فوتوشوب. جميل جدا أليس كذلك ؟
لنقم بمثال عملي آخر، لنكتب في سطر الأوامر التالي :
[pastacode lang=”bash” manual=”Playwright%20codegen” message=”” highlight=”” provider=”manual”/]
ستجد نافذتي المتصفح المحتكم به من قبل playwright ونافذة inspector والتي ستقوم بتسجيل تحركاتك وتفاعلك مع المتصفح الجديد وتحويلها إلى شفرة مصدرية يمكننا استخدامها والتعديل والإضافة عليها لعمل برنامج كامل.
و الآن في المتصفح الجديد إذهب لمدونتك المفضلة بايثونات وتجول فيها كما تشاء وشاهد كيف تسجل المكتبة تفاعلك مع المتصفح بنجاح كشفرة مصدرية بلغة بايثون:
في شاشة inspector يمكننا اختبار الـ selectors في مستطيل الإدخال فيه وكذلك عند نقر زر explore ويمكننا تحديد أهم عناصر الصفحة باستخدام الفأرة.
في النهاية أعتقد أن هذه المكتبة هي بديل مُعتبر لمكتبة سيلينيوم من حيث سهولة الاستخدام والتعلم.
كما أنني وجدت أنها قد تغنيني عن العمل بمكتبة سيلينيوم ومكتبة requests-html.
على سبيل التغيير، انصح بتجربتها، وشاركونا رأيكم في التعليقات أو عبر منصات التواصل الاجتماعي.
اقرأ ايضاً دمج الأمن السيبراني في منظومة الأمن القومي