Python حرفه‌ای: کار با Selenium - بخش اول

Professional Python: Working with Selenium - Part 1

14 فروردین 1400
درسنامه درس 38 از سری پایتون حرفه‌ای
Python حرفه ای: کار با Selenium - بخش اول (قسمت 38)

automation چیست؟

یکی از کارهایی که می توانید با پایتون انجام دهید، testing یا automation است. اگر یک شرکت داشته باشیم که برنامه ای را برای مردم ساخته است، باید مطمئن شویم که این برنامه بدون مشکل اجرا می شود. ما در فصلی از این دوره آموزشی به سراغ نوشتن unit test می رویم اما بحث testing ای که در اینجا از آن صحبت می کنیم، متفاوت است. ما انسان هستیم بنابراین با وب سایت ها کارهای انسانی می کنیم؛ به طور مثال از صفحات تاچ اسکرین استفاده می کنیم یا یک صفحه را اسکرول می کنیم. شرکت های بزرگ معمولا افرادی را استخدام می کنند که در این دست از تست ها و اتوماسیون (automation) به آن ها کمک کنند. هدف automation شبیه سازی رفتار انسان است و مختص پلتفرم خاصی مانند اندروید یا وب یا ویندوز و غیره نیست بلکه در تمام پلتفرم های موجود مطرح است. automation یکی از راه های testing نرم افزار است چرا که با آن می توانید هزاران کاربر را در سیستم خود شبیه سازی کنید اما در غیر از آن باید چندین نفر را برای نوشتن تست در کدها استخدام کنید.

آشنایی با Selemium و نصب آن

یکی از شاخه های اتوماسیون، browser automation نام دارد. در browser automation هدف ما شبیه سازی رفتار یک کاربر با مرورگر خود است. به زبان ساده تر با استفاده از کدها به مرورگر می گوییم که چه کاری انجام داده و چه رفتار از خود نشان بدهد. یکی از بهترین برنامه های موجود در پایتون برای انجام این کار Selenium است. طبیعتا برای استفاده از Selenium باید آن را نصب کنیم اما مثل همیشه دو راه برای نصب آن داریم. راه اول نصب سراسری آن با اجرای pip install است اما راه دوم که از نظر من بهتر است، استفاده از یک virtual environment است. ابتدا یک پوشه جدید به نام Selenium را ایجاد کنید و ترمینال خود را درون این مسیر باز نمایید. اگر می خواهید از روش نصب سراسری پیش بروید هیچ مشکلی نیست و فقط باید دستور زیر را اجرا کنید تا Selenium برایتان نصب شود:

pip install selenium

اما اگر می خواهید مثل من از virtual environment ها استفاده نمایید باید ابتدا با دستور زیر یک virtual environment را بسازید:

python3 -m venv my-venv

عبارت my-venv همان نام virtual environment ما است بنابراین شما می توانید هر نام دیگری را برایش انتخاب کنید. اجرای این دستور چند لحظه طول می کشد و سپس virtual environment برایتان ساخته می شود (یک پوشه جدید به نام my-venv را مشاهده خواهید کرد). حالا باید این virtual environment را فعال کنیم یا وارد آن بشویم. برای انجام این کار دستور زیر را اجرا می کنیم:

. my-venv/bin/activate

با انجام این کار عبارت my-env در کنار قسمت prompt ترمینال شما ظاهر می شود و متوجه می شوید که وارد virtual environment شده اید. حالا که درون virtual environment هستیم می توانیم دستور زیر را اجرا کنیم:

pip install selenium

با این کار selenium برایمان نصب شده است.

تشخیص پکیج selenium در vscode

در این قسمت باید ویرایشگر کد خود را در پوشه Selenium باز کرده و یک فایل جدید به نام automation.py را در آن ایجاد کنید. اولین کاری که در این فایل انجام می دهیم وارد کردن پکیج selenium است:

from selenium import webdriver

در صورتی که از Visual Studio Code استفاده می کنید احتمالا مشکلی خواهید داشت. virtual environment به صورت خودکار برایتان تشخیص داده نشده است و هنوز از حالت سراسری پایتون استفاده می کنید. از آنجایی که ما Selenium را فقط در virtual environment خود نصب کرده ایم طبیعتا در حالت سراسری در دسترس نبوده و visual studio code نصب بودن پکیجی به نام selenium را تشخیص نمی دهد. برای حل این مشکل به قسمت پایین و سمت چپ visual studio code نگاهی بیندازید. این قسمت interpreter path یا مسیر مفسر پایتون را به شما نشان می دهد که به صورت پیش فرض روی پایتون 3.8 یا 3.9 است (بسته به نسخه ای که نصب کرده اید). اگر روی آن کلیک کنید مسیرهای مختلفی برای مفسر پایتون را مشاهده خواهید کرد که یکی از آن ها my-env (همان virtual environment ما) است. با انتخاب این گزینه یک پوشه جدید به نام vscode. در پوشه Selenium ایجاد می شود که درون آن فایلی به نام settings.json  وجود دارد. محتوای این فایل به شکل زیر است:

{

    "python.pythonPath": "my-venv/bin/python"

}

همانطور که مشخص است حالا visual studio code می داند که باید از چه مسیری به عنوان مفسر پایتون استفاده کند. از این به بعد مشکلی در تشخیص پکیج selenium نخواهید داشت.

نصب driver های selenium

همانطور که می دانید هر مرورگری ظاهر و interface خاص خودش را دارد، قابلیت های خاص خودش را دارد، توانایی ها و محدودیت های خاص خودش را دارد، و الی آخر. Selenium برای اینکه بتواند با این خصوصیت ها و توانایی های مرورگر ها کار کند نیاز به یک driver خاص برای هر کدام از آن ها دارد. هر مرورگر متفاوت است بنابراین selenium برای هر کدام از مرورگر های موجود مانند کروم یا فایرفاکس، یک درایور جداگانه دارد که باید آن را نصب کنیم. من لیستی از درایورهای موجود را برایتان قرار می دهم:

من در این آموزش از گوگل کروم استفاده می کنیم بنابراین به صفحه درایور کروم می روم اما شما می توانید از هر درایور دیگری نیز استفاده کنید. توجه داشته باشید که اگر به لینک درایور کروم رفتید، آخرین نسخه موجود را دانلود نکنید! چرا؟ آخرین نسخه موجود beta بوده و stable نیست؛ برنامه های beta برنامه هایی هستند که هنوز تست نشده و ممکن است دارای خطا هایی جزئی باشند (نسخه آزمایشی) اما برنامه های stable (به معنی «پایدار») تست شده هستند و نسخه نهایی می باشند. برای مطمئن شدن از این موضوع می توانید به صفحه اصلی (https://sites.google.com/a/chromium.org/chromedriver/home) بروید و به قسمت All versions available in Downloads نگاهی بیندازید. در زمان نگارش این مقاله ما گزینه های زیر را می بینیم:

All versions available in Downloads

Latest stable release: ChromeDriver 88.0.4324.96

Latest beta release: ChromeDriver 89.0.4389.23

همانطور که می بینید نسخه ۸۹ این درایور هنوز در حالت beta است. طبیعتا این نسخه ها بر اساس نسخه های گوگل کروم است بنابراین اگر از درایور 88 استفاده می کنید باید مثل من نسخه 88 گوگل کروم را نصب داشته باشید. اگر دوست ندارید گوگل کروم را نصب کنید مشکلی نیست، می توانید از درایور beta استفاده کنید گرچه ممکن است به خطاهایی برخورد کنید. من شخصا گوگل کروم 88 را دارم بنابراین درایور stable (پایدار) را نصب می کنم تا مشکلی نداشته باشیم. با کلیک روی درایور پایدار به صفحه ای مانند https://chromedriver.storage.googleapis.com/index.html?path=88.0.4324.96/ منتقل می شوید، البته بسته به اینکه در چه زمانی این مقاله را مطالعه می کنید، نسخه درایور برای شما متفاوت خواهد بود. محتویات این صفحه متنی و به شکل زیر هستند:

[DIR]       Parent Directory                 -

[DIR]       chromedriver_linux64.zip 2021-01-20 19:13:52         5.42MB 

40537b052b77c418f05abc1428ecc3c3

[DIR]       chromedriver_mac64.zip   2021-01-20 19:13:53         7.76MB 

b91266f2468907e6c3e58220182cf19f

[DIR]       chromedriver_mac64_m1.zip           2021-01-20 19:13:55         6.99MB 

dd6f6ae34fa210b1993fb159d24ce330

[DIR]       chromedriver_win32.zip    2021-01-20 19:13:57         5.36MB 

9f5e7741994b46b1acca15d779cfe7ad

[DIR]       notes.txt                2021-01-20 19:01:19         0.00MB 

cbd16414ef0a8fc16a461d9d9dfa6b51

اگر به این نوشته ها دقت کنید متوجه می شوید که هر لینک برای یک سیستم عامل خاص طراحی شده است. بسته به اینکه از چه سیستم عاملی استفاده می کنید، گزینه مناسب برای خودتان را انتخاب کنید. فایل دانلود شده را از حالت فشرده خارج کنید و سپس فایل اصلی درایور را در پوشه Selenium و در کنار automation.py قرار بدهید.

در مرحله بعدی وارد فایل automation.py شده و یک نمونه یا instance از مرورگر را ایجاد می کنیم:

from selenium import webdriver




chrome_browser = webdriver.Chrome('./chromedriver')

همانطور که مشخص است این کار با پاس دادن آدرس فایل درایور (chromedriver) انجام می شود. با استفاده از این روش هیچ نیازی به پیکربندی اضافه نخواهیم داشت و کاربران ویندوز نیز می توانند از همین روش استفاده کنند. اگر از کاربران ویندوز هستید فرض کنید که فایل درایور (فایلی که پسوند exe دارد) را در مسیر /Users/yourname/Desktop/foundations/chromedriver قرار داده اید. در این حالت می توانید با روش بالا و به شکل زیر آن را آدرس دهی کنید:

driver_path = '/Users/yourname/Desktop/foundations/chromedriver'

chrome_browser = webdriver.Chrome(executable_path=driver_path)

روش دیگر برای کاربران ویندوز این است که فایل درایور را در PATH سیستم خود قرار بدهند. چطور؟ باید ابتدا به مسیر زیر در کنترلر پنل سیستم خود بروید:

Control Panel -> System and Security Settings -> System

در آنجا گزینه ای به نام Advanced system settings را خواهید دید که باید روی آن کلیک کنید. با این کار پنجره ای برایتان باز می شود که در آن دکمه ای به نام Environment Variables وجود دارد. با کلیک روی آن پنجره دیگری باز می شود که دو قسمت است و در قسمتی از آن نوشته شده است: System Variables. در آنجا به دنبال گزینه ای به نام path بگردید. روی آن کلیک کنید تا وارد حالت ویرایش شویم. در آنجا آدرس فایل chromedriver.exe را به این رشته اضافه می کنیم. یادتان نرود که قبل از اضافه کردن رشته جدید، در انتهای رشته قبلی علامت نقطه ویرگول انگلیسی (;) را قرار دهید. مثلا انتهای رشته من بدین شکل در آمده است (خود فایل chromedriver.exe را در مسیر ذکر نکنید):

C:\Program Files\nodejs\;C:\Windows\ChromeDriverFolder

این فرآیند در ویندوز ۱۰ راحت تر است و فقط کافی است رشته C:\Windows\ChromeDriverFolder را به عنوان یک ردیف جدید اضافه کنید. اگر این کار را انجام بدهید دیگر نیازی به پاس دادن آدرس فایل به webdriver.chrome ندارید و می توانید آن را به شکل زیر اجرا کنید:

from selenium import webdriver




chrome_browser = webdriver.Chrome()

کاربران لینوکس و مک نیز می توانند این کار را انجام بدهند. برای انجام این کار، ساده ترین حالت این است که فایل درایور را در /usr/bin یا /usr/local/bin قرار بدهید تا فایل درایور به PATH شما اضافه شود (البته می توانید از bashrc. نیز این کار را انجام بدهید) اما من پیشنهاد می دهم که همه کاربران (ویندوز، لینوکس و مک) از همان روش ساده تر استفاده کنید. یعنی فایل chromedriver.exe را در کنار automation.py قرار بدهید و مثل ما کد زیر را بنویسید:

from selenium import webdriver




chrome_browser = webdriver.Chrome('./chromedriver')

در صورتی که از کاربران ویندوز بوده و به خطا برخورد کردید، پسوند exe. را نیز به انتهای مسیر پاس داده شده به webdriver.chrome اضافه کنید. حالا اگر کد بالا را اجرا نمایید، گوگل کروم به صورت خودکار برایتان باز می شود و پیامی را دریافت می کنید که می گوید chrome is being controlled by automated test softwarre که یعنی کروم توسط نرم افزارهای اتوماسیون تست کنترل می شود. حالا بیایید کمی با دستور های دیگر Selenium آشنا شویم.

تست کردن Selenium

برای تست اولیه بیایید کروم را تمام صفحه کنیم. برای اینکار می گوییم:

from selenium import webdriver




chrome_browser = webdriver.Chrome('./chromedriver')




chrome_browser.maximize_window()

با اجرای این کد کروم برایتان باز شده و سپس صفحه maximize می شود (تمام صفحه می شود) بنابراین مطمئن می شویم که selenium را به صورت صحیح پیکربندی کرده ایم.

از اینجا به بعد باید یک هدف داشته باشیم که دستورات خود را روی آن اجرا کنیم. من وب سایت seleniumeasy.com/test را به شما پیشنهاد می دهم. این وب سایت (آدرس test/ آن) برای تست کردن کدهای selenium ایجاد شده است تا بتوانیم کدهای خودمان را روی انواع صفحات HTML تست کنیم. اگر به منوی سمت چپ صفحه در این وب سایت نگاه کنید انواع و اقسام عناصر HTML را مشاهده می کنید. من برای تست اول خودمان از مسیر seleniumeasy.com/test/basic-first-form-demo.html استفاده می کنم. این مسیر درون خودش دو فیلد ساده از فرم های HTML را دارد بنابراین برای شروع کار مناسب است.

اولین قدم برای انجام این کار رفتن به صفحه مورد نظر است. این کار با دستور get انجام می شود:

from selenium import webdriver




chrome_browser = webdriver.Chrome('./chromedriver')




chrome_browser.maximize_window()




chrome_browser.get(

    'https://www.seleniumeasy.com/test/basic-first-form-demo.html')

اگر کد بالا را اجرا نمایید، گوگل کروم در مسیر مشخص شده باز خواهد شد بنابراین این قدم اول است. حالا چطور می توانیم درون فرم ها مقدار خاصی را بنویسیم؟ Selenium برای تعامل با صفحات HTML از ساختار HTML آن صفحه استفاده می کند بنابراین برای هدف گرفتن عنصر خاصی در صفحه ابتدا باید روشی برای هدف قرار دادن کد HTML آن را داشته باشیم. چطور این کار را انجام بدهیم؟ به راحتی روی یک عنصر در سایت مورد نظر کلیک راست کرده و گزینه inspect را انتخاب کنید. با انجام این کار صفحه developer tools باز می شود و می توانید آن عنصر را مشاهده کنید. به طور مثال <title> این صفحه به شکل زیر است:

<title>Selenium Easy Demo - Simple Form to Automate using Selenium</title>

حالا می خواهیم بدانیم آیا نوشته بالا در تگ <title> این صفحه موجود است یا خیر. برای انجام این کار به شکل زیر عمل می کنیم:

from selenium import webdriver




chrome_browser = webdriver.Chrome('./chromedriver')




chrome_browser.maximize_window()




chrome_browser.get(

    'https://www.seleniumeasy.com/test/basic-first-form-demo.html')




print('Selenium Easy Demo - Simple Form to Automate using Selenium' in chrome_browser.title)

با اجرای کد بالا عبارت True برایمان چاپ می شود بنابراین می فهمیم که این نوشته در تگ title وجود داشته است. توجه داشته باشید که این مقدار ممکن است در آینده تغییر کند (صاحبان سایت <title> را تغییر دهند) بنابراین به جای کپی کردن کد بالا، متن title را خودتان استخراج کنید. البته استفاده از print کمی آزار دهنده است بنابراین من از دستور assert در زبان پایتون استفاده می کنم:

from selenium import webdriver




chrome_browser = webdriver.Chrome('./chromedriver')




chrome_browser.maximize_window()




chrome_browser.get(

    'https://www.seleniumeasy.com/test/basic-first-form-demo.html')




assert 'D Demo - Simple Form to Automate using Selenium' in chrome_browser.title

من از عمد رشته title را بهم ریخته ام (D Demo در ابتدای رشته اصلی نیست) تا خطا بگیرم. کلیدواژه assert یک expression را بررسی می کند و در صورتی که آن expression صحیح (True) نباشد، یک خطای assertionError را پرتاب می کند. با اجرای کد بالا خطایی شبیه به خطای زیر را می گیریم:

y-venv/bin/python" "/media/amir/Development/Roxo Academy/Python/Selenium/automation.py"

Traceback (most recent call last):

  File "/media/amir/Development/Roxo Academy/Python/Selenium/automation.py", line 10, in <module>

    assert 'D Demo - Simple Form to Automate using Selenium' in chrome_browser.title

AssertionError

همانطور که می بینید خطای AssertionError را دریافت کرده ایم.

هدف قرار دادن عناصر با selector ها

در Selenium روش های مختلفی برای هدف قرار دادن عناصر مختلف، روش های مختلفی وجود دارد. منظور ما از selector ها همان selector های CSS است (در selenium برای هر کدام از این selector ها یک متد جداگانه داریم). به طور مثال در صفحه فرم خودمان عنصری به شکل زیر را داریم:

<div class="panel-heading">Single Input Field</div>

همانطور که می بینید این عنصر کلاسی به نام  panel-heading دارد بنابراین می توانیم با متد find_element_by_class_name به این عنصر دسترسی داشته باشیم:

from selenium import webdriver




chrome_browser = webdriver.Chrome('./chromedriver')




chrome_browser.maximize_window()




chrome_browser.get(

    'https://www.seleniumeasy.com/test/basic-first-form-demo.html')




panel_heading = chrome_browser.find_element_by_class_name('panel-heading')




print(panel_heading)

با اجرای کد بالا نتیجه زیر را در کنسول مرورگر خود دریافت خواهید کرد:

<selenium.webdriver.remote.webelement.WebElement (session="6efc151162adbf7e88ec9fa9515a7a50", element="a5b3e6ab-6cbd-42bd-966e-e8117ab47ac5")>

این یک شیء webElement است و ما می توانیم هر کاری را با آن انجام بدهیم. من چند مثال از انواع عناصر HTML و روش دسترسی به آن ها را برایتان ذکر می کنم.

دسترسی با ID

فرض کنید عنصری با id زیر وجود داشته باشد:

<input id=”q” type=”text” />

برای هدف قرار گرفتن این عنصر باید به شکل زیر عمل کنیم:

element = chrome_browser.find_element_by_id(“q”)

دسترسی با Name

فرض کنید عنصری با خصوصیت name در فرم وجود داشته باشد:

<input id=”q” name=”search” type=”text” />

برای هدف قرار دادن این عنصر به شکل زیر عمل می کنیم:

element = chrome_browser.find_element_by_name(“search”)

دسترسی با Class

فرض کنید عنصری با کلاس زیر در کدهایمان وجود داشته باشد:

<div class=”username” style=”display: block;”>…</div>

برای هدف قرار دادن این عنصر به شکل زیر عمل می کنیم:

element = chrome_browser.find_element_by_class_name(“username”)

دسترسی با نام تگ

فرض کنید عنصری با تگ زیر در کدهایمان وجود داشته باشد:

<div class=”username” style=”display: block;”>…</div>

برای هدف قرار دادن این عنصر به شکل زیر عمل می کنیم:

element = chrome_browser.find_element_by_tag_name(“div”)

دسترسی با متن لینک

فرض کنید عنصری با متن زیر در کدهایمان وجود داشته باشد:

<a href=”#”>Refresh</a>

برای هدف قرار دادن این عنصر به شکل زیر عمل می کنیم:

element = chrome_browser.find_element_by_link_text(“Refresh”)

دسترسی با قسمتی از متن لینک

فرض کنید عنصری با متن زیر در کدهایمان وجود داشته باشد:

<a href=”#”>Refresh Here</a>

برای هدف قرار دادن این عنصر به شکل زیر عمل می کنیم:

element = chrome_browser.find_element_by_partial_link_text(“Refresh”)

تفاوت این روش و روش قبل این است که در find_element_by_link_text باید تمام متن درون لینک را داشته باشیم اما با find_element_by_partial_link_text فقط بخشی از متن را داریم.

دسترسی با سلکتورهای CSS

فرض کنید کد HTML ای را به شکل زیر داشته باشیم:

<form id=”testform” action=”submit” method=”get”>




<input class=”username” type=”text” />

<input class=”password” type=”password” />




</form>

برای هدف قرار دادن این عنصر به شکل زیر عمل می کنیم:

element = chrome_browser.find_element_by_css_selector(“form#testform>input.username”)

تنظیمات اولیه اجرای مرورگر

در هنگام اجرای مرورگر توسط selenium می توانیم options را نیز وارد اسکریپت کرده و تنظیمات مختلفی را به آن بدهیم. به نمونه کد زیر توجه کنید:

from selenium import webdriver

from selenium.webdriver.chrome.options import Options




options = Options()

options.add_argument("--headless")

options.add_argument("--start-maximized")

options.add_argument("--disable-notifications")

options.add_argument("--incognito")




driver = webdriver.Chrome(chrome_options=options, executable_path="Path to driver")

گزینه headless برای باز کردن مرورگر در حالت headless است. در حالت عادی زمانی که کدهایمان را اجرا می کنیم یک نمونه از مرورگر برایمان باز می شود اما حالت headless یعنی رابط گرافیکی مرورگر را باز نمی کنیم بلکه مرورگر را از طریق کدها هدایت می کنیم. مزیت این روش اینجاست که نیازی به بارگذاری رابط گرافیکی نداریم بنابراین همه چیز بسیار سریع تر انجام می شود (CPU و RAM کمتر اشغال می شوند). این مسئله باعث می شود که عملیات scraping سریع تر انجام شود اما در عین حال ممکن است وب سایت مقصد بتواند عملیات scraping را راحت تر تشخیص دهد و شما با بلاک کند.

گزینه start-maximized به مرورگر می گوید که از همان ابتدا به صورت تمام صفحه باز شود تا مثل مثالی که برایتان آورده ام این کار را با اجرای یک دستور اضافه انجام ندهیم. مرورگر فایرفاکس به صورت پیش فرض تمام صفحه باز می شود بنابراین نیازی به این دستور نداریم اما ما در این بخش با کروم کار می کنیم.

گزینه disable-notifications به معنی غیر فعال کردن notification ها (اعلان ها) است. این گزینه فقط روی کروم کار می کند. برای غیر فعال کردن اعلان ها در فایرفاکس باید از کد زیر استفاده کنید:

firefoxOptions.set_preference(“dom.webnotifications.serviceworker.enabled”, false);

firefoxOptions.set_preference(“dom.webnotifications.enabled”, false);

گزینه incognito نیز مرورگر را در حالت incognito (ناشناس) باز می کند.

من برای واضح بودن استفاده از این گزینه ها، آن ها را به صورت جداگانه صدا زده ام اما شما می توانید همه آن ها را در یک دستور صدا بزنید:

from selenium import webdriver

from selenium.webdriver.chrome.options import Options




options = Options()

options.add_argument("--incognito","--start-maximized","--headless")

driver = webdriver.Chrome(chrome_options=options, executable_path="Path to driver")

فعال کردن دانلود خودکار

برای فعال کردن دانلود خودکار (بدون پرسیدن از شما برای مشخص کردن آدرس دانلود) باید ابتدا نوع مرورگر مورد استفاده خود را بدانید. اگر از گوگل کروم استفاده می کنید فعال کردن دانلود خودکار به شکل زیر انجام می شود:

from selenium import webdriver




options = webdriver.ChromeOptions()

options.add_argument("download.default_directory=X")




driver = webdriver.Chrome(chrome_options=options, executable_path="Path to chrome driver")

آرگومانی به نام download.default_directory وجود دارد که یک مسیر پیش فرض را برای دانلود مشخص می کند بنابراین با اضافه کردن این آرگومان مشکل را حل می کنیم. طبیعتا در کد بالا و به جای X باید آدرس مورد نظر خودتان را قرار بدهید.

اگر از فایرفاکس استفاده می کنید، فعال کردن دانلود خودکار نیاز به نوشتن کد بیشتری دارد:

from selenium import webdriver

from selenium.webdriver.firefox.options import Options




firefoxOptions = Options()

firefoxOptions.set_preference("browser.download.folderList",2)

firefoxOptions.set_preference("browser.download.manager.showWhenStarting", False)

firefoxOptions.set_preference("browser.download.dir","/data")

firefoxOptions.set_preference("browser.helperApps.neverAsk.saveToDisk", "application/octet-stream,application/vnd.ms-excel")




firefoxdriver = webdriver.Firefox(firefox_options=firefoxOptions, executable_path="Path to firefox driver")

اولین قسمت خصوصیت  browser.download.folderList است که ما آن را روی عدد 2 گذاشته ایم.  این عدد مشخص کننده مسیر دانلود ها است و می توانید به جای 2 یکی از مقادیر زیر باشد:

  • عدد 0 یعنی فایل ها روی دسکتاپ کاربر دانلود می شوند.
  • عدد 1 یعنی فایل ها درون پوشه Downloads کاربر دانلود می شوند.
  • عدد 2 یعنی فایل ها روی دسکتاپ کاربر دانلود می شوند.

خصوصیت بعدی browser.download.manager.showWhenStarting است که می گوید آیا در هنگام دانلود، دانلود منیجر خود فایرفاکس را نشان بدهد یا خیر؟ ما false را انتخاب کرده ایم. خصوصیت browser.download.dir مسیر دانلود را مشخص می کند که من پوشه ای به نام data/ را انتخاب کرده ام. خصوصیت browser.helperApps.neverAsk.saveToDisk نیز مشخص می کند برای چه نوع فایل هایی عملیات ذخیره فایل روی هارد دیسک را به صورت خودکار انجام بدهد و از شما چیزی نپرسد. مقادیر که من به این خصوصیت پاس داده ام MIME Type های آن فایل ها هستند. چند MIME Type مشهور به شکل زیر هستند:

  • فایل txt یا متنی: text/plain
  • فایل های پی دی اف: application/pdf
  • فایل های CSV اکسل: application/csv
  • فایل های xlsx اکسل: application/vnd.ms-excel
  • فایل های docx ورد: application/vnd.openxmlformats-officedocument.wordprocessingml.document

دسترسی به جزئیات مرورگر در لحظه

برای مشاهده title در مرورگر از driver.title استفاده می کنیم. در این حالت driver نام متغیری است که درایور خود را در آن ذخیره کرده اید بنابراین آن را بر اساس نام متغیر خود تغییر دهید (ما در مثال های قبلی نامش را chrome_browser گذاشته بودیم). خصوصیت window_handles نیز به شما اجازه می دهد به پنجره مرورگر دسترسی داشته باشید. این خصوصیت در واقع لیستی از پنجره های باز می باشد بنابراین می توانیم با یک ایندکس و مانند لیست ها از آن استفاده کنیم:

driver.window_handles[0]

خصوصیت driver.current_url نیز به شما URL فعلی را می دهد. برخی اوقات نیز می خواهید تمام سورس کد صفحه را دانلود کنید. در این حالت خصوصیت driver.page_source سورس کد صفحه را به شما خواهد داد.

رفتن به URL ای خاص

همانطور که از مثال های قبلی نیز مشاهده کردید برای رفتن به یک URL خاص باید از متد get استفاده نمایید:

driver.get(“http://google.com”)

برای رفتن به صفحه قبل و بعد نیز از متد های back و forward استفاده می کنیم:

driver.back()

driver.forward()

و نهایتا برای refresh کردن صفحه از متدی با همین نام استفاده می کنیم:

driver.refresh()

تعامل با فرم های HTML

برای کلیک کردن روی یک عنصر خاص، ابتدا با روش های ذکر شده در بخش های قبلی آن عنصر را دریافت کره و سپس از متدی به نام click استفاده می کنیم:

button.click()

برای دریافت مقدار خاصی از attribute های یک عنصر نیز از متد get_attribute استفاده می کنیم:

button.get_attribute()

برای تشخیص اینکه آیا یک تصویر یا لینک یا دکمه در حال نمایش است یا خیر متد زیر را داریم:

element.is_displayed()

و برای بررسی فعال بودن عناصر نیز می توانیم از is_enabled استفاده کنیم:

element.is_enabled()

فیلدهای متنی نیز دو متد مخصوص خودشان را دارند. فرض کنید کد HTML زیر را داشته باشیم:

<input type="text" name="passwd" id="passwd-id" />

ابتدا باید این عنصر را هدف قرار دهیم تا به آن دسترسی داشته باشیم. این کار با هر کدام از دستور های زیر انجام می شود. من سه روش مختلف برای گرفتن یک عنصر را آورده ام تا هر سه را به شما یادآوری کنم.

element = driver.find_element_by_id("passwd-id")

element = driver.find_element_by_name("passwd")

element = driver.find_element_by_xpath("//input[@id='passwd-id']")

در مرحله بعدی می توانیم با استفاده از متد send_keys متن مورد نظر خودمان را درون این فیلد متنی بنویسیم:

element.send_keys("some text")

در ضمن اگر می خواهید فشار دادن دکمه ها را شبیه سازی کنید باید از کلاس keys در این دستور استفاده نمایید:

element.send_keys(" and some", Keys.ARROW_DOWN)

در ضمن می توانید از متد clear برای پاک کردن محتویات درون این فیلدهای متنی استفاده کنید:

element.clear()

برای کار با checkbox ها و radio button ها نیز متد is_selected و click را داریم که به ترتیب فعال بودن (تیک دار بودن) یا نبودن این عناصر را بررسی کرده و روی آن کلیک می کنند:

element.click()

element.is_selected()

البته روش کار برای عناصر select متفاوت است چرا که در <select> انواع و اقسام <option> ها را داریم بنابراین برای انتخاب آن ها باید ابتدا آن select را با هر روشی که دوست دارید هدف بگیرید و سپس برای انتخاب یک گزینه خاص یکی از دستورات زیر را به کار ببرید:

select = Select(driver.find_element_by_id(""))




select.select_by_index(1)

select.select_by_value("") # مقدار مورد نظر را در این بخش پاس بدهید

select.select_by_visible_text("") # متن نمایش داده شده را به این بخش پاس بدهید

همانطور که از نام این گزینه ها مشخص است select_by_index گزینه <option> را بر اساس ایندکس انتخاب می کند، select_by_value این کار را بر اساس مقدار <option> انجام می دهد و نهایتا select_by_visible_text نیز این کار را بر اساس متن مشاهده شده انجام می دهد. طبیعتا برای استفاده از select نیاز به import کردن ماژول زیر داریم:

from selenium.webdriver.support.ui import Select

از آنجایی که شاید این کار کمی پیچیده تر از بخش های دیگر فرم ها باشد من یک کد نمونه را برایتان می نویسم:

# وارد کردن ماژول ها

from selenium import webdriver

from selenium.webdriver.support.ui import Select

import time




# استفاده از درایور کروم

driver=webdriver.Chrome()




# رفتن به وب سایت مورد نظر

driver.get("https://fs2.formsite.com/meherpavan/form2/index.html?1537702596407")




# پیدا کردن عنصر مورد نظر

x = driver.find_element_by_id('RESULT_RadioButton-9')

drop=Select(x)




# انتخاب گزینه بر اساس رشته متنی آن گزینه

drop.select_by_visible_text("Afternoon")

time.sleep(4)

driver.close()

گرفتن اسکرین شات از صفحه مرورگر

خوشبختانه selenium گرفتن اسکرین شات از صفحه مرورگر را بسیار ساده کرده است. برای انجام این کار از روش زیر استفاده می کنیم:

from selenium import webdriver




driver = webdriver.Firefox(executable_path='[Browser Driver Path]')

driver.get('[URL to Open]')




driver.get_screenshot_as_file('sample_screenshot_2.png')

من از یک متد برای گرفتن اسکرین شات استفاده کرده ام اما در اصل selenium سه متد مختلف برای این کار ارائه می کند:

  • متد save_screenshot
  • متد get_screenshot_as_file
  • متد get_screenshot_as_png

دو متد اول برای گرفتن اسکرین شات با فرمت PNG استفاده می شوند بنابراین اگر نامی با پسوند jpg به آن بدهید، محتوای فایل خوانده نخواهد شد و چنین خطایی را دریافت می کنید:

/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py:907: UserWarning: name used for saved screenshot does not match file type. It should end with a `.png` extension type. It should end with a `.png` extension, UserWarning

متد سوم اسکرین شات را به صورت png گرفته اما به صورت باینری برمی گرداند. مزیت این کار چیست؟ با انجام این کار تصویر به صورت باینری در مموری (RAM) قرار می گیرد بنابراین می توانیم قبل از ذخیره کردنش، تغییراتی را روی آن اعمال کنیم. من یک مثال در این باره را برایتان آماده کرده ام:

from selenium import webdriver

import StringIO

from PIL import Image




driver = webdriver.Firefox(executable_path='[Browser Driver Path]')

driver.get('[URL to Open]')




driver.find_element_by_id('username').send_keys('admin')

driver.find_element_by_id('password').send_keys('admin')

driver.find_element_by_id('login').click()




screenshot = driver.get_screenshot_as_png()




size = (0, 0, 680, 400)

image = Image.open(StringIO.StringIO(screenshot))

region = image.crop(size)

region.save('sample_screenshot_3.jpg', 'JPEG', optimize=True, quality=95)

ما در این مثال ماژول های مورد نیازمان را وارد کرده ایم و از کتابخانه PIL نیز استفاده کرده ایم. اگر یادتان باشد قبلا با این کتابخانه کار کرده ایم. در مرحله بعدی درایور فایرفاکس را اجرا کرده ام اما شما می توانید از کروم یا هر درایور دیگری استفاده کنید. من آدرس خاصی را در کد بالا قرار نداده ام اما طبیعتا شما باید به جای [URL to Open] در کد بالا آدرس خودتان را اضافه کنید. در مرحله بعدی فرم لاگین را انتخاب کرده و هم برای رمز عبور و هم برای نام کاربری از کلمه admin استفاده کرده ایم و سپس روی دکمه login کلیک کرده ایم.

بخش جالب ماجرا پس از صدا زدن driver.get_screenshot_as_png شروع می شود. من ابتدا سایز مورد نظر برای اسکرین شات را در یک tuple به نام size مشخص کرده ام. در مرحله بعدی تصویر را در مموری باز می کنیم و قسمت های مورد نظرمان را crop می نماییم. نهایتا با صدا زدن متد save می توانیم تصویر را در سیستم ذخیره کنیم.

یک مثال دیگر گرفتن اسکرین شات از لوگوی وب سایت stackoverflow است:

from selenium import webdriver

from PIL import Image

from io import BytesIO




fox = webdriver.Firefox()

fox.get('http://stackoverflow.com/')







element = fox.find_element_by_id('hlogo') # مشخص کردن قسمت مورد نظر از صفحه برای گرفتن اسکرین شات

location = element.location

size = element.size

png = fox.get_screenshot_as_png() # با این کار از کل صفحه اسکرین شات گرفته ایم

fox.quit()




im = Image.open(BytesIO(png)) # با استفاده از کتابخانه پیل تصویر را در مموری باز می کنیم




left = location['x']

top = location['y']

right = location['x'] + size['width']

bottom = location['y'] + size['height']







im = im.crop((left, top, right, bottom)) # نقاط کراپ را مشخص می کنیم

im.save('screenshot.png') # تصویر کراپ شده را روی دیسک ذخیره می کنیم

امیدوارم این دو مثال نحوه صحیح گرفتن اسکرین شات را به شما نشان داه باشد.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری پایتون حرفه‌ای توصیه می‌کند:
نویسنده شوید

دیدگاه‌های شما (1 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

علیرضا کریمی
17 فروردین 1400
سلام خسته نباشید وبا تشکر از مطالب خوبتون. کار با سلنیوم قسمت دوم دارد؟ کی قسمت دومش قرار داده میشه؟ ممنون.

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.