是一个测试自动化的浏览器工具。爬虫主要用到Selenium的WebDriver,可以模拟真实用户操作浏览器。

官方文档

python库

 

1. 基本应用

安装

$ pip install selenium

导入库

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By

加载浏览器

支持的浏览器有

Browser Maintainer Versions Supported
Chrome Chromium All versions
Firefox Mozilla 54 and newer
Edge Microsoft 84 and newer
Internet Explorer Selenium 6 and newer
Opera Opera Chromium / Presto 10.5 and newer
Safari Apple 10 and newer

这里使用了Chrome,可以自定义chrome浏览器的配置,然后加载到浏览器参数中

chrome_options = Options()
chrome_options.add_argument('--headless')       ##无界面执行
chrome_options.add_argument('user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"')
driver = webdriver.Chrome(chrome_options=chrome_options)
driver.get(<url>)

 

2. 保存与读取cookies

前提条件是浏览器窗口要在该域名中,所以一般都会先执行driver.get("http://www.example.com")再进行cookies的操作

添加cookies至浏览器:

# Adds the cookie into current browser context
driver.add_cookie({"name": "key", "value": "value"})

 

从浏览器获取cookies:

获取指定名称

driver.get_cookie("foo")

获取所有

driver.get_cookies()

 

删除在浏览器中的cookies:

删除指定

# Delete a cookie with name 'test1'
driver.delete_cookie("test1")

删除所有

#  Deletes all cookies
driver.delete_all_cookies()

 

除此之外,还能利用json文件读取和写入cookies文件

  1. 保存cookies到json文件

    cookies = driver.get_cookies()
    jsonCookies = json.dumps(cookies)  # 通过json将cookies写入文件
    with open('topcashbacktest.json', 'w') as f:
    f.write(jsonCookies)
    
    
  2. 读取cookies文件

    f = open("topcashbacktest.json", "r+", encoding='utf-8')
    cookie = f.read()
    cookie = json.loads(cookie)
    for c in cookie:
    if 'expiry' in c:
        del c['expiry']
        driver.add_cookie(c)
    
    • 如果出现expiry错误则删除expiry键值

 

3. 如何定位元素

有两种写法:

  1. 不同的查找方式有不同的函数名

    to locate single element in a page:

    • findelementby_id
    • findelementby_name
    • findelementby_xpath
    • findelementbylinktext
    • findelementbypartiallink_text
    • findelementbytagname
    • findelementbyclassname
    • findelementbycssselector

    To find multiple elements (these methods will return a list):

    • findelementsby_name
    • findelementsby_xpath
    • findelementsbylinktext
    • findelementsbypartiallink_text
    • findelementsbytagname
    • findelementsbyclassname
    • findelementsbycssselector
  2. 不同的查找方式相同函数名,只是改变其参数

    find_element

    find_elements

    使用例子:

    from selenium.webdriver.common.by import By
    
    driver.find_element(By.XPATH, '//button[text()="Some text"]')
    driver.find_elements(By.XPATH, '//button')
    

    解析:

    导入By类;

    在函数中根据想查找的方式使用不同的By类,其中类的各个方法名称定义为:

    • ID = "id"
    • XPATH = "xpath"
    • LINK_TEXT = "link text"
    • PARTIALLINKTEXT = "partial link text"
    • NAME = "name"
    • TAG_NAME = "tag name"
    • CLASS_NAME = "class name"
    • CSS_SELECTOR = "css selector"

各定位方式说明:

Locator Description
class name Locates elements whose class name contains the search value (compound class names are not permitted)
css selector Locates elements matching a CSS selector
id Locates elements whose ID attribute matches the search value
name Locates elements whose NAME attribute matches the search value
link text Locates anchor elements whose visible text matches the search value
partial link text Locates anchor elements whose visible text contains the search value. If multiple elements are matching, only the first one will be selected.
tag name Locates elements whose tag name matches the search value
xpath Locates elements matching an XPath expression

 

可以在上一个搜索情况下再收窄元素

cheese = driver.find_element_by_id("cheese")        ##根据id定位
cheddar = cheese.find_elements_by_id("cheddar")     ##在原来的搜索结果上收窄搜索

 

4. 如何填表单

填充输入框:

username = driver.find_element(By.XPATH, '//input[@id="txtEmail"]')
username.clear()
username.send_keys(u'<yourEmail>')
pas = driver.find_element(By.XPATH,'//input[@id="ctl00_GeckoOneColPrimary_Login_txtPassword"]')
pas.clear()
pas.send_keys(u'<yourPassword>')

 

针对表单其他标签有其他方法,

  • select标签。使用Select类更加高效,方法如下:

    from selenium.webdriver.support.ui import Select
    
    select = Select(driver.find_element_by_name('name'))
    select.select_by_index(index)
    select.select_by_visible_text("text")
    select.select_by_value(value)
    
  • 提交submit。有两种方法:

    1. 找到提交的button,使用click()

      # Assume the button has the ID "submit" :)
      driver.find_element_by_id("submit").click()
      
    2. 直接定位在该表单,使用submit()

      element.submit()
      

 

5. 如何切换句柄

首先,需要先获取句柄

获取当前window句柄:

this_window = driver.current_window_handle

获取当前浏览器的所有句柄:

all_windows = driver.window_handles

 

在切换句柄时,可以使用以下两种方式提供参数:

  1. 想跳转到的window的handle值
  2. 想跳转到的windows在windows_handles中的索引号

 

在selenium中通过driver.switch_to.window()方式切换句柄。

所以,根据上述的参数方式可分为:

driver.switch_to.window(desired_window_handle)
driver.switch_to.window(driver.window_handles[desired_window_handle_index])

 

常见问题:

  1. 网页元素无法定位selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element:...

    出错原因1:元素未加载完成

    解决方法:

    使用WebDriverWait(driver,x)函数实现等待X秒的功能,在X秒期间,每隔500毫秒扫描一次变化。

    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("http://somedomain/url_that_delays_loading")
    try:
       element = WebDriverWait(driver, 10).until(
           EC.presence_of_element_located((By.ID, "myDynamicElement"))
       )
    finally:
       ...
    

     

    出错原因2:xpath或cssSelector定位错误

    解决方法:

    利用chrome的开发者工具,然后在console输入命令验证能否定位。

    xpath验证:$x("the xpath you got from chrome")

    cssSelector验证:$$("the selector you got from chrome")

     

    出错原因3:需要定位的元素在iframe框架中

    解决方法:

    先定位该iframe元素

    iframe = driver.find_element_by_xpath("//iframe[@name='...']")
    

    然后切换框架

    driver.switch_to.frame(iframe)
    

    然后在框架下定位想要的元素

    desired_element = driver.find_element_by_xpath("//....")
    
    • 所有的操作完成后,记得切换回到主框架

      driver.switch_to.default_content()
      

     

  2. 在同一个浏览器新建tab(window)

    打开的方式一般有两种,一种是使用浏览器(系统和浏览器的不同可能会有差异)的键盘快捷键打开,另一种是使用JavaScript打开。

    这里使用JavaScript方式打开。

    driver.execute_script("window.open('')")
    
    • 注意点:

      新建了tab后,selenium需要切换句柄才能真正在该新建的窗口中进行操作。虽然浏览器已经切换到新的窗口,但实际selenium还停留在原来的句柄那。

     

  3. 如何切换到想到的window窗口

    可通过for loop的方式遍历。前提条件是要知道该window窗口的句柄值。

    for window_handle in driver.window_handles:
       if window_handle != original_window:
           driver.switch_to.window(window_handle)
           break
    

     

  4. 如何bypass Google recaptcha

    根据StackOverflow的解答,给chromeDriver增加属性--disable-blink-features=AutomationControlled

    python代码:

    from selenium.webdriver.chrome.options import Options
    
    chrome_options = Options()
    chrome_options.add_argument("--disable-blink-features=AutomationControlled")
    
    driver = webdriver.Chrome(chrome_options=chrome_options)
    

     

  5. 如何缓存cookies

    给chromeDriver增加属性--user-data-dir= the_detionary_path_you_want_to_save

    python代码:

    from selenium.webdriver.chrome.options import Options
    
    chrome_options = Options()
    chrome_options.add_argument("--user-data-dir= chrome_data")
    
    driver = webdriver.Chrome(chrome_options=chrome_options)
    
    • 缓存的数据存在该项目根目录(或者执行工具目录)中,文件名为chrome_data

There are 0 comments