常用Selenium代码整理及Tips

(一)判断元素是否存在

self.driver.find_element(By.ID, 'name').size != 0

(二)智能延时/等待指定节点加载

当需要获取的元素节点是由 JavaScript 动态生成时,需要让获取节点的代码“等一等”再运行 通过 time.sleep(5)这种方式,当需要等待网络请求比较多时,会导致完成一次运行需要等待很久,如下是一些代码及使用场景

每次点击事件后都应该添加智能延时代码,它会等待时间为0~5秒

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Firefox()
driver.get("http://www.example.com/")
driver.find_element(By.ID, "submit").click()
driver.implicitly_wait(5)

一般来讲,稍稍设置大一些的等待时间即可加载出相应节点的数据,有一种更为确定的方法,可以在指定的时间内等待,直到我们需要的节点加载出来,相比于 implicitly_wait 它更加的精确,节省时间,因为它不必等待我们不关心的节点加载

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://www.example.com/")
wait = WebDriverWait(self.driver, 10)
wait.until(
    EC.presence_of_element_located((By.ID, "submit"))
).click()

如上的写法是针对于获取到节点就点击的,如果一个登陆表单时动态加载的,并且里面的元素也是动态加载的,那么首先需要先获取登陆表单,然后在表单的基础上再选择节点,示例代码段如下

# 等待登录页加载完成
wait = WebDriverWait(driver, WAIT_TIME)
formElement = wait.until(
    EC.presence_of_element_located((By.CSS_SELECTOR, ".sign-in-form"))
)
# 填写邮箱与密码登陆
emailElement = formElement.find_element(By.ID, 'email')
emailElement.send_keys(username)
passwordEmement = formElement.find_element(By.ID, 'password')
passwordEmement.send_keys(password)
# 点击登陆
formElement.find_element(By.CSS_SELECTOR, '[type="button"]').click()
driver.implicitly_wait(WAIT_TIME)

(三)元素个数(Elements Counts)

一些情况下,获取元素下子节点的数量有助于帮助程序判断节点的状态,简化代码,而且有时数量信息也是很重要的数据

counts = self.driver.find_elements(By.CLASS_NAME, 'img')
print len(counts)

为了这个问题,我Google了有一会,有说需要使用xpath才能返回列表的,有的是java的代码,尝试好久,最后我才在一个问题下边猛然的发现我的方法少了一个s,是find_elements_by_xxx() 而不是find_element_by_xxx()

(四)处理iframe的情况

driver.switch_to_frame(self, frame_reference) 这个方法已经废弃

新的函数如下:

def frame_switch(css_selector):
    driver.switch_to.frame(driver.find_element_by_css_selector(css_selector))

def frame_switch(name):
  driver.switch_to.frame(driver.find_element_by_name(name))

处理完iframe,回到之前的界面

driver.switch_to.default_content()

(五)Firefox与Chrome的driver差异

当写完Login()函数后,加载其它函数,比如或许用户详情页的时候,Firefox Driver或自动带上Cookies,Chrome Driver 不会自动加载Cookies,所以使用Chrome比Firefox需要多两行代码,手动加载Cookies

# 登陆后获取cookies
cookies = driver.get_cookies()

# 在加载新的页面后倒入Cookies
for cookie in cookies:
    driver.add_cookie(cookie)

如果有些网站的Cookies有效期很长,那么可以将Cookies保存到文件

# 保存Cookies到文件
import pickle
import selenium.webdriver 

driver = selenium.webdriver.Firefox()
driver.get("http://www.google.com")
pickle.dump( driver.get_cookies() , open("cookies.pkl","wb"))


# 从文件加载Cookies
import pickle
import selenium.webdriver 

driver = selenium.webdriver.Firefox()
driver.get("http://www.google.com")
cookies = pickle.load(open("cookies.pkl", "rb"))
for cookie in cookies:
    driver.add_cookie(cookie)

(六)滚动加载

有些数据一页展示不完,当侧边栏向下拉或者鼠标滚动的时候才会继续加载数据,这种模式在瀑布流的图片展示站点非常常见,不过也很好解决

# 回到顶部
js="var q=document.body.scrollTop=0"
driver.execute_script(js)

# 拉到底部
js="var q=document.body.scrollTop=10000"
driver.execute_script(js)

在网上搜索的时候有这样的写法document.documentElement.scrollTop=10000,我在测试的时候发现body的写法是工作的,这可能跟网站/浏览器 有一定关系,在测试的时候哪种能工作就用哪种吧