Selenium WebDriver
lastmod 2025-12-26created 2016-06-3048 edits
Selenium automates browsers. That's it! What you do with that power is entirely up to you. Primarily, it is for automating web applications for testing purposes, but is certainly not limited to just that. Boring web-based administration tasks can (and should!) also be automated as well.
Selenium has the support of some of the largest browser vendors who have taken (or are taking) steps to make Selenium a native part of their browser. It is also the core technology in countless other browser automation tools, APIs and frameworks.
How to install
[python] Scraping with Selenium
Drivers
Chrome
Gecko
Setting the MOZ_HEADLESS=1 environment variable starts it in Headless mode.
Selecting DOM elements
If the element is not found, selenium.common.exceptions.NoSuchElementException is raised
Extracting the first element
| Name | Description |
| find_element_by_id(id) | Extracts one element by the id attribute |
| find_element_by_name(name) | Extracts one element by the name attribute |
| find_element_by_css_selector(query) | Extracts one element by CSS selector |
| find_element_xpath(query) | Extracts one element by specifying an xpath |
| find_element_by_tag_name(name) | Extracts one element whose tag name matches name |
| find_element_by_link_text(text) | Extracts an element by link text |
| find_element_by_partial_link_text(text) | Extracts one element by text contained in the link's child elements |
| find_element_by_class_name(name) | Extracts one element whose class name matches name |
Extracting all elements
| Name | Description |
| find_elements_by_name | |
| find_elements_by_xpath | |
| find_elements_by_link_text | |
| find_elements_by_partial_link_text | |
| find_elements_by_tag_name | |
| find_elements_by_class_name | |
| find_elements_by_css_selector |
Manipulating elements
| Method/Property | Description |
| clear() | Clears the text |
| click() | Clicks the element |
| get_attribute(name) | Extracts the value of the element's attribute matching name |
| is_displayed() | Checks whether the element is displayed on screen |
| is_enabled() | Checks whether the element is enabled |
| is_selected() | Checks whether an element such as a checkbox is selected |
| screenshot(filename) | Screenshot |
| send_keys(value) | Types keys |
| submit() | Submits the input form |
| value_of_css_property(name) | Extracts the value of the CSS property matching name |
| id | id |
| location | Location of the element |
| parent | Parent element |
| rect | Returns a dictionary with size and location information |
| screenshot_as_base64 | Extracts the screenshot as base64 |
| screenshot_as_png | Extracts the screenshot as PNG-format binary |
| size | Size of the element |
| tag_name | Tag name |
| text | Inner text of the element |
Entering special keys in send_key()
from selenium.Webdriver.common.keys import Keys
ARROW_DOWN / ARROW_LEFT / ARROW_RIGHT / ARROW_UP
BACKSPACE / DELETE / HOME / END /INSERT /
ALT / COMMAND / CONTROL / SHIFT
ENTER / ESCAPE /SPACE / TAB
F1 / F2 / F3 ............./ F12
Driver operations
| Method | Description |
| add_cookie( cookie_dict) | Sets a cookie value in dictionary format |
| back() / forward() | Previous page / next page |
| close() | Closes the browser |
| current_url | Current url |
| delete_all_cookies() | Removes all cookies |
| delete_cookie(name) | Removes the cookie matching name |
| execute( command, params) | Executes a browser-specific command |
| execute_async_script( script, *args) | Executes asynchronous JavaScript |
| execute_script( script, *args) | Executes synchronous JavaScript |
| get(url) | Loads a web page |
| get_cookie( name) | Extracts a specific cookie value |
| get_cookies() | Extracts all cookie values in dictionary format |
| get_log(type) | Extracts logs (type: browser/driver/client/server) |
| get_screenshot_as_base64() | Extracts a screenshot in base64 format |
| get_screenshot_as_file(filename) | Saves a screenshot to a file |
| get_screenshot_as_png() | Extracts the screenshot binary in PNG format |
| get_window_position(windowHandle='current') | Extracts the browser's position |
| get_window_size( windowHandle='current') | Extracts the browser's size |
| implicitly_wait(sec) | Waits until processing finishes, with the maximum wait time given in seconds |
| quit() | Quits the driver and closes the browser |
| save_screenshot(filename) | Saves a screenshot |
| set_page_load_timeout( time_to_wait) | Sets the page load timeout |
| set_script_timeout(time_to_wait) | Sets the script timeout |
| set_window_position(x,y,windowHandle='current') | Sets the browser position |
| set_window_size(width, height, windowHandle='current') | Sets the browser size |
| title | Extracts the current title |
sleep vs implicitly_wait vs set_page_load_timeout
- (Python) Difference between driver.implicitly_wait and time.sleep
- How to set page load timeout in Selenium? - GeeksforGeeks
To cut to the chase:
-
driver.implicitly_wait(10)- moves on immediately if the web page loads within 10 seconds, or waits 10 seconds. -
time.sleep(10)- waits 10 seconds. -
driver.set_page_load_timeout(10)- a 10-second timeout for fully loading the page. On timeout, it raisesselenium.common.TimeoutException.
Waiting for specific conditions
You can use the WebDriverWait and expected_conditions modules to wait until a specific condition is met.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox()
# 웹 페이지로 이동
driver.get("https://example.com")
# 최대 10초 동안 대기하며, title이 "Example Domain"이 될 때까지 대기
wait = WebDriverWait(driver, 10)
wait.until(EC.title_is("Example Domain"))
GeckoDriver Example
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
import time
# FireFox binary path (Must be absolute path)
FIREFOX_BINARY = FirefoxBinary('/opt/firefox/firefox')
# FireFox PROFILE
PROFILE = webdriver.FirefoxProfile()
PROFILE.set_preference("browser.cache.disk.enable", False)
PROFILE.set_preference("browser.cache.memory.enable", False)
PROFILE.set_preference("browser.cache.offline.enable", False)
PROFILE.set_preference("network.http.use-cache", False)
PROFILE.set_preference("general.useragent.override","Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:72.0) Gecko/20100101 Firefox/72.0")
# FireFox Options
FIREFOX_OPTS = Options()
FIREFOX_OPTS.log.level = "trace" # Debug
FIREFOX_OPTS.headless = True
GECKODRIVER_LOG = '/geckodriver.log'
class Scraper:
def __init__(self):
ff_opt = {
firefox_binary=FIREFOX_BINARY,
firefox_profile=PROFILE,
options=FIREFOX_OPTS,
service_log_path=GECKODRIVER_LOG
}
self.DRIVER = webdriver.Firefox(**ff_opt)
def scrape(self, link):
try:
self.DRIVER.get(link)
time.sleep(5) # just in case
html = self.DRIVER.page_source
return html
except Exception as e:
print(e)
Run it as follows:
Switching iframe context
iframe = driver.find_elements_by_tag_name('iframe')[0]
driver.switch_to.default_content()
driver.switch_to.frame(iframe)
driver.find_elements_by_tag_name('iframe')[0]
switch_to_default_content() will return you to the top of the document. What was happening is you switched into the first iframe, switched back to the top of the document, then tried to find the second iframe. Selenium can't find the second iframe, because it's inside of the first iframe.
If you remove the second switch_to_default_content() you should be fine:
Screenshot example
- Stackoverflow: How do I generate a png file w/ selenium/phantomjs from a string?
- Python Selenium + PhantomJS on AWS EC2 Ubuntu Instance - Headless Browser Automation
driver = webdriver.PhantomJS(service_args=['--ssl-protocol=any'])
## Or chrome driver:
# driver = webdriver.Chrome();
driver.implicitly_wait(10)
driver.set_window_size(1024, 768)
driver.get('http://www.python.org/')
if driver.save_screenshot('out.png'):
print 'success.'
driver.quit()
NAVER Fortuen example
Example of fetching Naver's daily fortune (horoscope).
driver.get('https://search.naver.com/search.naver?sm=tab_hty.top&where=nexearch&oquery=%EC%98%A4%EB%8A%98%EC%9D%98+%EC%9A%B4%EC%84%B8&ie=utf8&query=%EC%98%A4%EB%8A%98%EC%9D%98+%EC%9A%B4%EC%84%B8')
fortune = driver.execute_script("return document.getElementById('_fortune_birthCondition');")
selector_date = driver.execute_script("return arguments[0].getElementsByClassName('_selectorText')[0];", fortune)
driver.execute_script("arguments[0].setAttribute('datetime', '{}');".format(date), selector_date)
driver.execute_script("arguments[0].innerHTML = '{}';".format(date), selector_date)
# Check fortune.
driver.execute_script("arguments[0].getElementsByClassName('btn_chs _submit')[0].click();", fortune)
# Check result.
luck_result = driver.execute_script("return arguments[0].getElementsByClassName('luck_result _fortune_birthResult')[0];", fortune)
story0 = driver.execute_script("return arguments[0].getElementsByClassName('luck_story _storyList')[0];", luck_result)
content0 = driver.execute_script("return arguments[0].getElementsByClassName('_luckContent')[0].getElementsByTagName('p')[0].innerHTML;", story0)
result = 'Total luck: {}\n\n'.format(content0)
OR:
driver.set_window_size(1200, 1000)
driver.get('https://search.naver.com/search.naver?sm=tab_hty.top&where=nexearch&oquery=%EC%98%A4%EB%8A%98%EC%9D%98+%EC%9A%B4%EC%84%B8&ie=utf8&query=%EC%98%A4%EB%8A%98%EC%9D%98+%EC%9A%B4%EC%84%B8')
elem = driver.find_elements_by_tag_name('html')
print elem[0].text
if is_female:
driver.execute_script("document.getElementsByClassName('_genderTarget')[1].click()");
else:
driver.execute_script("document.getElementsByClassName('_genderTarget')[0].click()");
driver.execute_script("document.getElementById('srch_txt').value = '{}'".format(date))
driver.execute_script("document.getElementsByClassName('contents03')[0].getElementsByClassName('img_btn')[0].click()")
luck_result = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CLASS_NAME, "infor _luckText"))
)
title = driver.execute_script("return document.getElementsByClassName('infor _luckText')[0].getElementsByTagName('dd')[0].getElementsByTagName('strong')[0].innerHTML")
body = driver.execute_script("return document.getElementsByClassName('infor _luckText')[0].getElementsByTagName('dd')[0].getElementsByTagName('p')[0].innerHTML")
result = '{}\n{}'.format(title, body)
with BeautifulSoup
from selenium import webdriver
from bs4 import BeautifulSoup
# setup Driver|Chrome : 크롬드라이버를 사용하는 driver 생성
driver = webdriver.Chrome('/Users/beomi/Downloads/chromedriver')
driver.implicitly_wait(3) # 암묵적으로 웹 자원을 (최대) 3초 기다리기
# Login
driver.get('https://nid.naver.com/nidlogin.login') # 네이버 로그인 URL로 이동하기
driver.find_element_by_name('id').send_keys('naver_id') # 값 입력
driver.find_element_by_name('pw').send_keys('mypassword1234')
driver.find_element_by_xpath(
'//*[@id="frmNIDLogin"]/fieldset/input'
).click() # 버튼클릭하기
driver.get('https://order.pay.naver.com/home') # Naver 페이 들어가기
html = driver.page_source # 페이지의 elements모두 가져오기
soup = BeautifulSoup(html, 'html.parser') # BeautifulSoup사용하기
notices = soup.select('div.p_inr > div.p_info > a > span')
for n in notices:
print(n.text.strip())
ChromeDriver Selenium for Dockerfile
- Setting up a Selenium and Chrome browser runtime environment in Docker
- Installing Google Chrome (chrome) from the command line on Ubuntu Linux
Complete example:
FROM python:3.8
MAINTAINER yourname <[email protected]>
COPY . /decanbot
WORKDIR /decanbot
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get -qq update && \
ln -fs /usr/share/zoneinfo/Asia/Seoul /etc/localtime && \
apt-get install -y tzdata && \
dpkg-reconfigure --frontend noninteractive tzdata && \
apt-get install -y --no-install-recommends software-properties-common curl unzip
RUN curl -s "https://dl.google.com/linux/linux_signing_key.pub" | apt-key add - && \
add-apt-repository "deb [arch=amd64] https://dl.google.com/linux/chrome/deb/ stable main"
RUN apt-get -qq update && \
apt-get install -y --no-install-recommends google-chrome-stable && \
export CHROME_DRIVER_VERSION=$(curl -sS "https://chromedriver.storage.googleapis.com/LATEST_RELEASE") && \
export CHROME_DRIVER_URL="https://chromedriver.storage.googleapis.com/${CHROME_DRIVER_VERSION}/chromedriver_linux64.zip" && \
mkdir -p /decanbot/storage/driver && \
curl -sS -o /decanbot/storage/driver/chromedriver_linux64.zip "${CHROME_DRIVER_URL}" && \
unzip /decanbot/storage/driver/chromedriver_linux64.zip chromedriver -d /decanbot/storage/driver/ && \
pip3 install -U pip && \
pip3 install -r requirements.txt
ENTRYPOINT ["python3", "-m", "decanbot"]
GeckoDriver Selenium for Dockerfile
FROM python:3.9
ENV DEBIAN_FRONTEND noninteractive
ENV GECKODRIVER_VER v0.29.0
ENV FIREFOX_VER 87.0
RUN set -x \
&& apt update \
&& apt upgrade -y \
&& apt install -y \
firefox-esr \
&& pip install \
requests \
selenium \
# Add latest FireFox
RUN set -x \
&& apt install -y \
libx11-xcb1 \
libdbus-glib-1-2 \
&& curl -sSLO https://download-installer.cdn.mozilla.net/pub/firefox/releases/${FIREFOX_VER}/linux-x86_64/en-US/firefox-${FIREFOX_VER}.tar.bz2 \
&& tar -jxf firefox-* \
&& mv firefox /opt/ \
&& chmod 755 /opt/firefox \
&& chmod 755 /opt/firefox/firefox
# Add geckodriver
RUN set -x \
&& curl -sSLO https://github.com/mozilla/geckodriver/releases/download/${GECKODRIVER_VER}/geckodriver-${GECKODRIVER_VER}-linux64.tar.gz \
&& tar zxf geckodriver-*.tar.gz \
&& mv geckodriver /usr/bin/
COPY ./app /app
WORKDIR /app
CMD python ./main.py
Troubleshooting
The process started from chrome location /usr/bin/google-chrome is no longer running, so ChromeDriver is assuming that Chrome has crashed
You need to pass the following options.
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
DevToolsActivePort file doesn't exist
- Fixing the DevToolsActivePort file doesn't exist error · MOONGCHI
- Stackoverflow - WebDriverException: unknown error: DevToolsActivePort file doesn't exist while trying to initiate Chrome Browser
- How to fix the DevToolsActivePort file doesn't exist error
If the following error is printed:
selenium.common.exceptions.WebDriverException: Message: unknown error: DevToolsActivePort file doesn't exist
Try adding --single-process to the Chrome driver options. If that doesn't work, add --disable-dev-shm-usage.
timeout: Timed out receiving message from renderer
- Stackoverflow - python - Selenium gives "Timed out receiving message from renderer" for all websites after some execution time - Stack Overflow
- Stackoverflow - How to disable java script in Chrome Driver Selenium Python - Stack Overflow
- Stackoverflow - Python: Disable images in Selenium Google ChromeDriver - Stack Overflow
Using the driver.get("https://...") function, a timeout error can occur while loading a page.
2022-06-12 16:18:50.864 1/140558718469952 decanbot ERROR driver.get(url='https://...') -> timeout: Timed out receiving message from renderer: 59.458
(Session info: headless chrome=102.0.5005.115)
concurrent.futures.process._RemoteTraceback:
"""
Traceback (most recent call last):
File "/decanbot/decanbot/web/mana.py", line 129, in _get_last_numbers_from_update_page
driver.get(url)
File "/usr/local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 442, in get
self.execute(Command.GET, {'url': url})
File "/usr/local/lib/python3.8/site-packages/selenium/webdriver/remote/webdriver.py", line 430, in execute
self.error_handler.check_response(response)
File "/usr/local/lib/python3.8/site-packages/selenium/webdriver/remote/errorhandler.py", line 247, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message: timeout: Timed out receiving message from renderer: 59.458
(Session info: headless chrome=102.0.5005.115)
Stacktrace:
#0 0x558ee5eb2f33 <unknown>
#1 0x558ee5bfd118 <unknown>
#2 0x558ee5be8008 <unknown>
#3 0x558ee5be6c0f <unknown>
#4 0x558ee5be719c <unknown>
#5 0x558ee5bf55ff <unknown>
#6 0x558ee5bf6162 <unknown>
#7 0x558ee5c0424d <unknown>
#8 0x558ee5c0766a <unknown>
#9 0x558ee5be75c6 <unknown>
#10 0x558ee5c03f54 <unknown>
#11 0x558ee5c646e8 <unknown>
#12 0x558ee5c50e63 <unknown>
#13 0x558ee5c2682a <unknown>
#14 0x558ee5c27985 <unknown>
#15 0x558ee5ef74cd <unknown>
#16 0x558ee5efb5ec <unknown>
#17 0x558ee5ee171e <unknown>
#18 0x558ee5efc238 <unknown>
#19 0x558ee5ed6870 <unknown>
#20 0x558ee5f18608 <unknown>
#21 0x558ee5f18788 <unknown>
#22 0x558ee5f32f1d <unknown>
#23 0x7f726b340ea7 <unknown>
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/concurrent/futures/process.py", line 239, in _process_worker
r = call_item.fn(*call_item.args, **call_item.kwargs)
File "/decanbot/decanbot/web/mana.py", line 132, in _get_last_numbers_from_update_page
raise NetworkConnectionError(f"driver.get(url='{url}') -> {e.msg}")
decanbot.web.mana.NetworkConnectionError: driver.get(url='https://...') -> timeout: Timed out receiving message from renderer: 59.458
(Session info: headless chrome=102.0.5005.115)
"""
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/decanbot/decanbot/core/mixin/context_timer.py", line 34, in timer_main
await self.on_timer()
File "/decanbot/decanbot/core/mixin/context_timer.py", line 53, in on_timer
await self.on_mana_crawling()
File "/decanbot/decanbot/core/mixin/context_timer.py", line 59, in on_mana_crawling
manas = await self.mana.get_last_numbers_from_update_page(
File "/decanbot/decanbot/web/mana.py", line 211, in get_last_numbers_from_update_page
return await loop.run_in_executor(
decanbot.web.mana.NetworkConnectionError: driver.get(url='https://...') -> timeout: Timed out receiving message from renderer: 59.458
(Session info: headless chrome=102.0.5005.115)
If you keep getting timeouts even though nothing is particularly wrong, either increase the timeout
service = Service(executable_path=self.chromedriver_path)
driver = Chrome(options=self.options, service=service)
driver.set_page_load_timeout(60.0) # 60초 !!
or, if you don't need scripts, you can Disable JavaScript or turn off image loading. (These are factors that increase loading time)
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument("--disable-javascript") # JavaScript Disable
prefs = {"profile.managed_default_content_settings.images": 2} # Image Loading Diable
chrome_options.add_experimental_option("prefs", prefs)
driver = webdriver.Chrome(chrome_options=chrome_options)
If that still doesn't solve it, check the other options. I removed the single-process option.
self.options.add_argument("disable-gpu")
self.options.add_argument("no-sandbox")
self.options.add_argument("disable-dev-shm-usage")
# self.options.add_argument("single-process")
if not developer:
self.options.add_argument("headless")
WebDriverException : "Process unexpectedly closed with status 255"
If you haven't changed the log path, check the $(pwd)/geckodriver.log file at the default path. There is most likely a shared library that failed to load. See Firefox#Troubleshooting. Briefly:
apt-get update
apt-get install -y wget bzip2 libxtst6 packagekit-gtk3-module libx11-xcb-dev libdbus-glib-1-2 libxt6 libpci-dev
See also
- Web crawler
- Python
- WebDriver
- Beautiful Soup
- PhantomJS
- Chrome
- FireFox
- Web crawler
- Helium - an easier-to-use Selenium-Python
- Autotab - a tool that turns complex web tasks into APIs
- Playwright - Playwright enables reliable end-to-end testing for modern web apps.
- Stagehand - AI-based open-source browser automation framework
- Simplex - automating browser workflows with code and natural language
- Vibium - a browser automation tool for AI and humans
Favorite site
- Selenium web site
- Python - Using Web Driver & Selenium
- Using selenium PhantomJS
- Using PhantomJS
- UI testing with Selenium
- Selenium Tutorial: Web Scraping with Selenium and Python
- JavaScript Injection with Selenium, Puppeteer, and Marionette in Chrome and Firefox
- For web automation, use Playwright instead of Selenium | GeekNews (Selenium vs Playwright)