آموزش Web Scraping با Selenium
۶ اسفند ۱۳۹۹
Selenium ابزاری است که به شما در اجرای تستهای خودکار برنامههای وب کمک میکند. اگرچه هدف اصلی این مقاله، استفاده از Selenium برای Web Scraping با استفاده از اسکریپت Python است اما شما میتوانید در زمینههای مختلفی از مزیتهای این ابزار بهرهمند شوید.
تفاوت Selenium با دیگر ابزارهای Web Scraping مانند BeautifulSoup در این است که میتواند به محتوای رندر شده با JavaScript دسترسی داشته باشد. علاوهبراین ابزار Selenium در زمانی مفید است که شما میخواهید علاوه بر جمعآوری دادهها از صفحههای وب، بهنوعی با صفحه ارتباط برقرار کنید. مثلا روی دکمهها کلیک کنید یا از دادههای مشخص شدهای در فیلدها استفاده کنید.
هدف برنامهی نهایی ما، استخراج نوسانهای نرخ دلار از وبسایت investing.com است.
تجزیه و تحلیل URL
در این بخش، URL وبسایت هدف را تجزیه و تحلیل میکنیم. در این آدرس از وبسایت investing.com نوسانهای نرخ دلار بهنسبت یورو نمایش داده میشود. همچنین در این صفحه میتوانید تاریخ معینی را تعیین کرده و نوسانهای این دو ارز را در بازهی خاصی از زمان مشاهده کنید.
برای مشاهدهی سایر ارزها بهنسبت نوسانهای دلار میتوانید مقدار eur
را با ارز دلخواه خود در URL فوق جایگزین کنید.
Web Scraping با Selenium
بهتر است قبل از شروع توسعهی پروژه یک محیط مجازی (Virtual environment) ایجاد کنیم که در مقالهی آموزش نصب و استفاده از Virtual environment در Python عمیقتر به این موضوع پرداختهایم.
پس از ایجاد محیط مجازی و active کردن آن، وابستگیهای پروژه را با اجرای دستورهای زیر نصب میکنیم:
pip install selenium
pip install pandas
pip install lxml
حال یک فایل با نام main.py
در محیط مجازی ایجاد کرده و به توسعهی برنامه میپردازیم:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from time import sleep
import pandas
در این مرحله بایستی یک فانکشن که دادههای زیر را بهعنوان ورودی دریافت میکند، توسعه دهیم:
- لیستی از کدهای ارزها
- تاریخ شروع بازهی زمانی معین
- تاریخ پایان بازهی زمانی معین
- یک مقدار Boolean برای زمانی که بخواهید خروجی برنامه را در یک فایل
.csv
دریافت کنید
ایده به این شکل است که دادههای مختلفی از هر ارز را جمعآوری کنیم بنابراین یک لیست خالی را برای ذخیرهی دادهها آماده خواهیم کرد:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from time import sleep
import pandas
def get_currencies(currencies, start, end, export_csv=True):
frames = []
با فانکشن فوق میتوانیم لیستی از ارزها را دریافت کرده و با پیمایش آنها، دادههای مربوط به هر ارز را استخراج کنیم. برای هر ارز موجود در این لیست باید یک URL داینامیک داشته باشیم، یک DriverObject را نمونهسازی کرده و سپس از آن برای دریافت دادههای صفحه استفاده کنیم.
سپس بایستی پنجرهی باز شدهی مرورگر را Maximize کنیم. البته نتیجهی این کار فقط با فعال بودن گزینهی option.headless = False
قابل مشاهده است:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from time import sleep
import pandas
def get_currencies(currencies, start, end, export_csv=True):
frames = []
for currency in currencies:
# Opening the connection and grabbing the page
chrome_driver_path = ''
my_url = f'https://investing.com/currencies/usd-{currency.lower()}-historical-data'
option = Options()
option.headless = False
option.executable_path = chrome_driver_path
driver = webdriver.Chrome(options=option)
driver.get(my_url)
driver.maximize_window()
در کدهای بالا بایستی مقدار متغیر chrome_driver_path
را تعیین کنید اما قبل از بایستی ChromeDriver دانلود کرده باشید. برای مثال ChromeDriver ما در مسیر زیر قرار دارد:
C:/liara/selenium-scrapper/pys/chromedriver.exe
بنابراین مقدار متغیر chrome_driver_path
را به شکل زیر تعیین میکنیم:
chrome_driver_path = 'C:/liara/selenium-scrapper/pys/chromedriver.exe'
برای دریافت نوسانهای ارز در یک بازهی زمانی معین از برخی قابلیتهای جالب Selenium برای تعامل با وبسایت استفاده میکنیم. باید برای پیادهسازی این بخش بر روی گزینهی تاریخ کلیک کرده، قسمتهای مورد نیاز را با دادههای تعریف شده پر کنیم و در نهایت این فیلتر اعمال شود.
حال برای تعیین کردن بازهی زمانی معین بایستی فیلتر تاریخ را به شکل زیر انتخاب کرده و بر روی آن کلیک کنیم:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from time import sleep
import pandas
def get_currencies(currencies, start, end, export_csv=True):
frames = []
for currency in currencies:
# Opening the connection and grabbing the page
chrome_driver_path = 'C:/liara/selenium-scrapper/pys/chromedriver.exe'
my_url = f'https://investing.com/currencies/usd-{currency.lower()}-historical-data'
option = Options()
option.headless = False
option.executable_path = chrome_driver_path
driver = webdriver.Chrome(options=option)
driver.get(my_url)
driver.maximize_window()
# Clicking on the date button
date_button = driver.find_element_by_id('flatDatePickerCanvasHol')
date_button.click()
اکنون باید فیلدهای مربوط به Start Date را پر کنیم:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from time import sleep
import pandas
def get_currencies(currencies, start, end, export_csv=True):
frames = []
for currency in currencies:
# Opening the connection and grabbing the page
chrome_driver_path = 'C:/liara/selenium-scrapper/pys/chromedriver.exe'
my_url = f'https://investing.com/currencies/usd-{currency.lower()}-historical-data'
option = Options()
option.headless = False
option.executable_path = chrome_driver_path
driver = webdriver.Chrome(options=option)
driver.get(my_url)
driver.maximize_window()
# Clicking on the date button
date_button = driver.find_element_by_id('flatDatePickerCanvasHol')
date_button.click()
# Sending the start date
start_bar = driver.find_element_by_id('startDate')
start_bar.clear()
start_bar.send_keys(start)
با استفاده از clear
تمام دادههای پیشفرض این فیلد حذف شده و با استفاده از send_keys
، دادههای جدید را در این فیلد قرار میدهیم. همچنین این روند را نیز بایستی برای End Date تکرار کنیم:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from time import sleep
import pandas
def get_currencies(currencies, start, end, export_csv=True):
frames = []
for currency in currencies:
# Opening the connection and grabbing the page
chrome_driver_path = 'C:/liara/selenium-scrapper/pys/chromedriver.exe'
my_url = f'https://investing.com/currencies/usd-{currency.lower()}-historical-data'
option = Options()
option.headless = False
option.executable_path = chrome_driver_path
driver = webdriver.Chrome(options=option)
driver.get(my_url)
driver.maximize_window()
# Clicking on the date button
date_button = driver.find_element_by_id('flatDatePickerCanvasHol')
date_button.click()
# Sending the start date
start_bar = driver.find_element_by_id('startDate')
start_bar.clear()
start_bar.send_keys(start)
# Sending the end date
end_bar = driver.find_element_by_id('endDate')
end_bar.clear()
end_bar.send_keys(end)
سپس بایستی بر روی دکمهی Apply کلیک کنید تا فیلترها اعمال شوند. همچنین از sleep
استفاده میکنیم تا برنامهی ما برای چند ثانیه متوقف شده و صفحهی جدید کاملا بارگیری شود:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from time import sleep
import pandas
def get_currencies(currencies, start, end, export_csv=True):
frames = []
for currency in currencies:
# Opening the connection and grabbing the page
chrome_driver_path = 'C:/liara/selenium-scrapper/pys/chromedriver.exe'
my_url = f'https://investing.com/currencies/usd-{currency.lower()}-historical-data'
option = Options()
option.headless = False
option.executable_path = chrome_driver_path
driver = webdriver.Chrome(options=option)
driver.get(my_url)
driver.maximize_window()
# Clicking on the date button
date_button = driver.find_element_by_id('flatDatePickerCanvasHol')
date_button.click()
# Sending the start date
start_bar = driver.find_element_by_id('startDate')
start_bar.clear()
start_bar.send_keys(start)
# Sending the end date
end_bar = driver.find_element_by_id('endDate')
end_bar.clear()
end_bar.send_keys(end)
# Clicking on the apply button
apply_button = driver.find_element_by_id('applyBtn')
apply_button.click()
sleep(5)
اگر option.headless
را برابر با False
قرار داده باشید میتوانید تمام فرایند اجرای برنامه را مشاهده کنید. حال زمان آن است که از فانکشن pandas.read_html
برای انتخاب کردن جدول مورد نظرمان در صفحهی وب استفاده کنیم. این فانکشن source code صفحه را دریافت میکند و پس از آن میتوانید از ChromeDriver فعلی خارج شوید:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from time import sleep
import pandas
def get_currencies(currencies, start, end, export_csv=True):
frames = []
for currency in currencies:
# Opening the connection and grabbing the page
chrome_driver_path = 'C:/liara/selenium-scrapper/pys/chromedriver.exe'
my_url = f'https://investing.com/currencies/usd-{currency.lower()}-historical-data'
option = Options()
option.headless = False
option.executable_path = chrome_driver_path
driver = webdriver.Chrome(options=option)
driver.get(my_url)
driver.maximize_window()
# Clicking on the date button
date_button = driver.find_element_by_id('flatDatePickerCanvasHol')
date_button.click()
# Sending the start date
start_bar = driver.find_element_by_id('startDate')
start_bar.clear()
start_bar.send_keys(start)
# Sending the end date
end_bar = driver.find_element_by_id('endDate')
end_bar.clear()
end_bar.send_keys(end)
# Clicking on the apply button
apply_button = driver.find_element_by_id('applyBtn')
apply_button.click()
sleep(5)
# Getting the tables on the page and quiting
dataframes = pandas.read_html(driver.page_source)
driver.quit()
print(f'{currency} scraped.')
مدیریت Exceptionها در Selenium
فرایند جمعآوری دادهها در بخش قبل تمام شد اما بایستی Exceptionهای احتمالی را درنظر بگیریم. بههمین منظور از try
استفاده خواهیم کرد تا اگر برنامهی ما با مشکلی روبرو شد قادر باشیم در بخش except
آن را مدیریت کنیم. سناریو ما بهصورت زیر است:
- ChromeDriver بهمنظور استفادهی بهینه از memory، بسته شود.
- در زمان ایجاد خطا یک پیام در Console چاپ شود.
- پس از آن برنامه برای ده ثانیه متوقف شود.
- برنامه مجددا اجرا شود.
بایستی این روند را مرتبا تا زمانی که دادههای مربوط به هر ارز دریافت شود، تکرار کنیم:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from time import sleep
import pandas
def get_currencies(currencies, start, end, export_csv=True):
frames = []
for currency in currencies:
try:
# Opening the connection and grabbing the page
chrome_driver_path = 'C:/liara/selenium-scrapper/pys/chromedriver.exe'
my_url = f'https://investing.com/currencies/usd-{currency.lower()}-historical-data'
option = Options()
option.headless = False
option.executable_path = chrome_driver_path
driver = webdriver.Chrome(options=option)
driver.get(my_url)
driver.maximize_window()
# Clicking on the date button
date_button = driver.find_element_by_id('flatDatePickerCanvasHol')
date_button.click()
# Sending the start date
start_bar = driver.find_element_by_id('startDate')
start_bar.clear()
start_bar.send_keys(start)
# Sending the end date
end_bar = driver.find_element_by_id('endDate')
end_bar.clear()
end_bar.send_keys(end)
# Clicking on the apply button
apply_button = driver.find_element_by_id('applyBtn')
apply_button.click()
sleep(5)
# Getting the tables on the page and quiting
dataframes = pandas.read_html(driver.page_source)
driver.quit()
print(f'{currency} scraped.')
except:
driver.quit()
print(f'Failed to scrape {currency}. Trying again in 10 seconds.')
sleep(10)
continue
تا به اینجا تمام صفحهی وب را در متغیری با نام dataframes
ذخیره کردهایم. حال بایستی جدول مورد نظر را از بقیهی کدهای موجود در صفحه، جدا کنیم:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from time import sleep
import pandas
def get_currencies(currencies, start, end, export_csv=True):
frames = []
for currency in currencies:
try:
# Opening the connection and grabbing the page
chrome_driver_path = 'C:/liara/selenium-scrapper/pys/chromedriver.exe'
my_url = f'https://investing.com/currencies/usd-{currency.lower()}-historical-data'
option = Options()
option.headless = False
option.executable_path = chrome_driver_path
driver = webdriver.Chrome(options=option)
driver.get(my_url)
driver.maximize_window()
# Clicking on the date button
date_button = driver.find_element_by_id('flatDatePickerCanvasHol')
date_button.click()
# Sending the start date
start_bar = driver.find_element_by_id('startDate')
start_bar.clear()
start_bar.send_keys(start)
# Sending the end date
end_bar = driver.find_element_by_id('endDate')
end_bar.clear()
end_bar.send_keys(end)
# Clicking on the apply button
apply_button = driver.find_element_by_id('applyBtn')
apply_button.click()
sleep(5)
# Getting the tables on the page and quiting
dataframes = pandas.read_html(driver.page_source)
driver.quit()
print(f'{currency} scraped.')
except:
driver.quit()
print(f'Failed to scrape {currency}. Trying again in 10 seconds.')
sleep(10)
continue
# Selecting the correct table
for dataframe in dataframes:
if dataframe.columns.tolist() == ['Date', 'Price', 'Open', 'High', 'Low', 'Change %']:
frames.append(dataframe)
اکنون اگر مقدار export_csv
برابر با True
باشد، بایستی دادههای خروجی را با استفاده از dataframe.to_csv
در یک فایل .csv
ذخیره کنیم:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from time import sleep
import pandas
def get_currencies(currencies, start, end, export_csv=True):
frames = []
for currency in currencies:
try:
# Opening the connection and grabbing the page
chrome_driver_path = 'C:/liara/selenium-scrapper/pys/chromedriver.exe'
my_url = f'https://investing.com/currencies/usd-{currency.lower()}-historical-data'
option = Options()
option.headless = False
option.executable_path = chrome_driver_path
driver = webdriver.Chrome(options=option)
driver.get(my_url)
driver.maximize_window()
# Clicking on the date button
date_button = driver.find_element_by_id('flatDatePickerCanvasHol')
date_button.click()
# Sending the start date
start_bar = driver.find_element_by_id('startDate')
start_bar.clear()
start_bar.send_keys(start)
# Sending the end date
end_bar = driver.find_element_by_id('endDate')
end_bar.clear()
end_bar.send_keys(end)
# Clicking on the apply button
apply_button = driver.find_element_by_id('applyBtn')
apply_button.click()
sleep(5)
# Getting the tables on the page and quiting
dataframes = pandas.read_html(driver.page_source)
driver.quit()
print(f'{currency} scraped.')
except:
driver.quit()
print(f'Failed to scrape {currency}. Trying again in 10 seconds.')
sleep(10)
continue
# Selecting the correct table
for dataframe in dataframes:
if dataframe.columns.tolist() == ['Date', 'Price', 'Open', 'High', 'Low', 'Change %']:
frames.append(dataframe)
# Exporting the .csv file
if export_csv:
dataframe.to_csv('currency.csv', index=False)
print(f'{currency}.csv exported.')
return frames
حال برای اجرای برنامه میتوانیم این فانکشن را فراخوانی کرده و فایل main.py
را با دستور python main.py
اجرا کنیم:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from time import sleep
import pandas
def get_currencies(currencies, start, end, export_csv=True):
frames = []
for currency in currencies:
try:
# Opening the connection and grabbing the page
chrome_driver_path = 'C:/liara/selenium-scrapper/pys/chromedriver.exe'
my_url = f'https://investing.com/currencies/usd-{currency.lower()}-historical-data'
option = Options()
option.headless = False
option.executable_path = chrome_driver_path
driver = webdriver.Chrome(options=option)
driver.get(my_url)
driver.maximize_window()
# Clicking on the date button
date_button = driver.find_element_by_id('flatDatePickerCanvasHol')
date_button.click()
# Sending the start date
start_bar = driver.find_element_by_id('startDate')
start_bar.clear()
start_bar.send_keys(start)
# Sending the end date
end_bar = driver.find_element_by_id('endDate')
end_bar.clear()
end_bar.send_keys(end)
# Clicking on the apply button
apply_button = driver.find_element_by_id('applyBtn')
apply_button.click()
sleep(5)
# Getting the tables on the page and quiting
dataframes = pandas.read_html(driver.page_source)
driver.quit()
print(f'{currency} scraped.')
except:
driver.quit()
print(f'Failed to scrape {currency}. Trying again in 10 seconds.')
sleep(10)
continue
# Selecting the correct table
for dataframe in dataframes:
if dataframe.columns.tolist() == ['Date', 'Price', 'Open', 'High', 'Low', 'Change %']:
frames.append(dataframe)
# Exporting the .csv file
if export_csv:
dataframe.to_csv('currency.csv', index=False)
print(f'{currency}.csv exported.')
return frames
print(get_currencies(['eur'], '01/13/2021', '02/13/2021'))
منبع: https://www.freecodecamp.org/news/how-to-code-a-scraping-bot-with-selenium-and-python