Selenium

6.1 Selenium 是什么

Selenium 是一个用于Web应用程序测试的工具。

Selenium 测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Firefox,Safari,Chrome,Opera等。

但是,我们只是想使用 Selenium 来模拟正常用户访问浏览器。我们也无需兼容很多浏览器,选一个常用的,比如 Chrome浏览器。

##

官方文档:

https://www.selenium.dev/documentation/en/

6.2 Selenium 安装

1
2
3
4
5
6
7
8
9
10
11
# 第一步
# 安装 selenium 驱动
pip3 install selenium

# 第二步
# 确定本地电脑安装的Chrome浏览器版本,或者去下载安装最新版 Chrome
# 83.0.4103.116
# 第三步
# 下载和 Chrome 浏览器 版本相同的 chromedriver,至少前两位版本号要相同,比如 83.0
# 下载地址。下载很慢。
https://chromedriver.storage.googleapis.com/index.html

6.3 检验是否安装成功

打开百度

1
2
3
from selenium import webdriver
browser = webdriver.Chrome('/Users/gaoshuaipeng/chromedriver/chromedriver83')
browser.get('https://baidu.com')

打开百度 等待5s后关闭

1
2
3
4
5
6
7
import time
from selenium import webdriver
browser = webdriver.Chrome('/Users/gaoshuaipeng/chromedriver/chromedriver83')
browser.get('https://baidu.com')

time.sleep(5)
browser.quit()

无界面运行,简单了解一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/env python3
'''
根据chrome浏览器2017年发布的新特性,
需要unix版本的chrome版本高于57,
windows版本的chrome版本高于58,
才能使用无界面运行.
'''

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time


chrome_opt = Options() # 创建参数设置对象.
chrome_opt.add_argument('--headless') # 无界面化.
chrome_opt.add_argument('--disable-gpu') # 配合上面的无界面化.
chrome_opt.add_argument('--window-size=1366,768') # 设置窗口大小, 窗口大小会有影响.

# 创建Chrome对象并传入设置信息.
browser = webdriver.Chrome('/Users/gaoshuaipeng/chromedriver/chromedriver83', chrome_options=chrome_opt)


# 操作这个对象.
browser.get('https://www.baidu.com') # get方式访问百度.
time.sleep(2)
print(driver.page_source) # 打印加载的page code, 证明(prove) program is right.
browser.quit() # 使用完, 记得关闭浏览器, 不然chromedriver.exe进程为一直在内存中.

Selenium启动项(参数设置)

1
2
3
4
5
6
7
8
9
10
11
12
import time
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

chrome_opt = Options()
chrome_opt.add_argument('--windows-size=800,600') # 设置浏览器窗口大小.

browser = webdriver.Chrome('/Users/gaoshuaipeng/chromedriver/chromedriver83',chrome_opt)
browser.get('https://baidu.com')

time.sleep(5)
browser.quit()

禁用浏览器弹窗

1
2
3
4
5
6
prefs = {  
'profile.default_content_setting_values' : {
'notifications' : 2
}
}
options.add_experimental_option('prefs',prefs)

chromedriver

一般可以放在环境文件中,但是有时候为了方便部署项目,或者为了容易打包,我们可以将chromedriver.exe放到我们的项目目录中,然后在初始化Chrome Webdriver对象时,传入chromedriver.exe的路径。

1
2
3
4
5
from selenium import webdriver


driver = webdriver.Chrome(executable_path='chromedriver.exe')
driver.quit()

6.4 Driver对象常见操作

  • get(url): 在当前浏览器会话中访问传入的url地址, driver.get(‘https://www.baidu.com‘).
  • close(): 关闭浏览器当前窗口。
  • quit(): 退出webdriver并关闭所有窗口。
  • refresh(): 刷新当前页面。
  • title: 获取当前页的标题。
  • page_source: 获取当前页渲染后的源代码。
  • current_url: 获取当前页面的url。
  • window_handles: 获取当前会话中所有窗口的句柄。

6.5 Driver查找单个元素

  • find_element_by_xpath 通过Xpath查找
  • find_element_by_class_name 通过class属性查找
  • find_element_by_css_selector 通过css选择器查找
  • find_element_by_id 通过id查找
  • find_element_by_link_text 通过链接文本查找
  • find_element_by_name 通过name属性进行查找
  • find_element_by_partial_link_text 通过链接文本的部分匹配查找
  • find_element_by_tag_name 通过标签名查找

6.6 查找多个元素

把上述方法中的 element 替换为 elements

6.7 操作Cookie

  • add_cookie(cookie_dict) : 给当前会话添加一个cookie。
    • cookie_dict: 一个字典对象,必须要有”name”和”value”两个键,可选的键有:“path”, “domain”, “secure”, “expiry” 。
    • 用法:
1
2
3
driver.add_cookie({‘name’ : ‘foo’, ‘value’ : ‘bar’})
driver.add_cookie({‘name’ : ‘foo’, ‘value’ : ‘bar’, ‘path’ : ‘/’})
driver.add_cookie({‘name’ : ‘foo’, ‘value’ : ‘bar’, ‘path’ : ‘/’, ‘secure’:True})
  • get_cookie(name): 按name获取单个Cookie,没有则返回None。

  • get_cookies(): 获取所有Cookie,返回的是一组字典。

  • delete_all_cookies(): 删除所有Cookies。

  • delete_cookie(name): 按name删除指定cookie。

6.8 截屏

  • get_screenshot_as_base64(): 获取当前窗口的截图保存为一个base64编码的字符串。
  • get_screenshot_as_file(filename): 获取当前窗口的截图保存为一个png格式的图片,filename参数为图片的保存地址,最后应该以.png结尾。如果出现IO错误,则返回False。
    • 用法: driver.get_screenshot_as_file(‘/Screenshots/foo.png’)
  • get_screenshot_as_png(): 获取当前窗口的截图保存为一个png格式的二进制字符串。

6.9 获取窗口信息

  • get_window_position(windowHandle=’current’): 获取当前窗口的x,y坐标。

  • get_window_rect(): 获取当前窗口的x,y坐标和当前窗口的高度和宽度。

  • get_window_size(windowHandle=’current’): 获取当前窗口的高度和宽度。

6.10 Driver切换操作

  • switch_to_frame(frame_reference): 将焦点切换到指定的子框架中
  • switch_to_window(window_name): 切换窗口

6.11 Driver执行JS代码

  • execute_async_script(script, *args) : 在当前的window/frame中异步执行JS代码。

    • script:是你要执行的JS代码。

    • *args:是你的JS代码执行要传入的参数。
      用法:

      1
      2
      3
      script = “var callback = arguments[arguments.length - 1]; ”
      script2 = “window.setTimeout(function(){ callback(‘timeout’) }, 3000);”
      driver.execute_async_script(script + script2)
  • execute_script(script, *args): 在当前的window/frame中同步执行JS代码。

    script:是你要执行的JS代码。
    args:是你的JS代码执行要传入的参数。

6.12 Webelement

前面有讲到使用find等方法来查找单个或多个元素对象, 其结果返回一个Webelement对象.

Webelement常用方法

  • clear(): 清空对象中的内容.
  • click(): 单击对象.
  • get_attribute(name): 优先返回完全匹配属性名的值,如果不存在,则返回属性名中包含name的值。
  • screenshot(filename): 获取当前元素的截图,保存为png,最好用绝对路径.
  • send_keys(value): 给对象元素输入数据, 如在百度中搜索’哔哩哔哩’.
  • submit(): 提交表单.

6.12.1 Webelement常用属性

  • text: 获取当前元素的文本内容.
  • tag_name: 获取当前元素的标签名.
  • size: 获取当前元素的大小.
  • screenshot_as_png: 将当前元素截屏并保存为png格式的二进制数据.
  • screenshot_as_base64: 将当前元素截屏并保存为base64编码的字符串.
  • rect: 获取一个包含当前元素大小和位置的字典.
  • parent: 获取当前元素的父节点.
  • location: 当前元素的位置.
  • id: 当前元素的id值,主要用来selenium内部使用,可以用来判断两个元素是否是同一个元素.

6.12.2 Webelement中的keys

1
2
3
4
5
# 要使用按键值, 需要导入下面keys.
from selenium.webdriver.common.keys import Keys


elem.send_keys(Keys.CONTROL, 'c')

更多的key

https://blog.csdn.net/One_of_them/article/details/82560880

6.13 连续操作

一般来说我们与页面的交互可以使用Webelement的方法来进行点击等操作。但是,有时候我们需要一些更复杂的动作,类似于拖动,双击,长按等等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
from selenium.webdriver import ActionChains
from selenium import webdriver

driver = webdriver.Chrome() # 创建webdriver对象.

element = driver.find_element_by_name("source") # 查找单一元素对象.
target = driver.find_element_by_name("target") # 同上.

actions = ActionChains(driver) # 创建动作链对象.

# 在element元素上点击抓起,移动到target元素上松开放下。 类似鼠标.
actions.drag_and_drop(element, target)
actions.perform() # 执行动作.


**在调用各种动作方法后,这些方法并不会马上执行当你调用perform()时,这些动作才会依次开始执行**

### 6.13.1 常用的Action-Chains方法

- click(on_element=None) : 左键单击传入的元素,如果不传入的话,点击鼠标当前位置。
- context_click(on_element=None): 右键单击。
- double_click(on_element=None) : 双击。
- click_and_hold(on_element=None): 点击并抓起
- drag_and_drop(source, target) : 在source元素上点击抓起,移动到target元素上松开放下。
- drag_and_drop_by_offset(source, xoffset, yoffset):在source元素上点击抓起,移动到相对于source元素偏移xoffset和yoffset的坐标位置放下。
- send_keys(*keys_to_send): 将键发送到当前聚焦的元素。
- send_keys_to_element(element, *keys_to_send): 将键发送到指定的元素。
- reset_actions(): 清除已经存储的动作。


## 6.14 页面等待

在selenium操作浏览器的过程中,每一次请求`url`,`selenium`都会等待页面加载完毕以后,才会将操作权限再次交给我们的程序。



但是,由于`ajax`和各种`JS代码`的**异步加载**问题,所以我们在使用`selenium`的时候常常会遇到操作的元素还没有加载出来,就会引发报错。为了解决这个问题,`Selenium`提供了几种等待的方法,让我们可以等待元素加载完毕后,再进行操作。

### 6.14.1 显式等待

​```python
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.Chrome()
driver.get("http://somedomain/url_that_delays_loading")

try:
# 创建wait对象.
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)

finally:
driver.quit()

在10秒内,默认每0.5秒检查一次元素是否存在,存在则将元素赋值给element这个变量。如果超过10秒这个元素仍不存在,则抛出超时异常。

6.15.5 隐式等待

1
2
3
4
5
6
from selenium import webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(10) # 单位是秒
driver.get("http://somedomain/url_that_delays_loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")

webdriver中进行find_element这一类查找操作时,如果找不到元素,则会默认的轮询等待一段时间。

6.17 预期条件

常见的检查条件。

  • title_is: 判断title,返回布尔值.

    1
    WebDriverWait(driver,10).until(EC.title_is(u"百度一下,你就知道"))
  • title_contains: 判断title,返回布尔值.

    1
    WebDriverWait(driver,10).until(EC.title_contains(u"百度一下"))
  • presence_of_element_located: 判断元素对象是否被加载到dom树里; 并不代表该元素一定可见, 如果定位到就返回Webelement.

    1
    WebDriverWait(driver,10).until(EC.presence_of_element_located((By.ID,'some')))
  • visibility_of_element_located: 判断元素对象是否被加载到dom里并且可见, 一般在对象可能会被其他元素对象遮挡的情况下使用.

    1
    WebDriverWait(driver,10).until(EC.visibility_of_element_located((By.ID,'some')))
  • visibility_of: 判断元素是否可见,如果可见就返回这个元素.

    1
    WebDriverWait(driver,10).until(EC.visibility_of(driver.find_element(by=By.ID,value='some')))
  • presence_of_all_elements_located: 判断是否至少有1个元素存在dom树中,如果定位(找)到就返回列表.

    1
    WebDriverWait(driver,10).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR,'some')))
  • visibility_of_any_elements_located: 判断是否至少有一个元素在页面中可见,如果定位到就返回列表.

    1
    WebDriverWait(driver,10).until(EC.visibility_of_any_elements_located((By.CSS_SELECTOR,'some')))
  • text_to_be_present_in_element: 判断指定的元素中是否包含了预期的字符串,返回布尔值.

    1
    WebDriverWait(driver,10).until(EC.text_to_be_present_in_element((By.XPATH,"some"),u'设置'))
  • text_to_be_present_in_element_value: 判断指定元素的属性值中是否包含了预期的字符串,返回布尔值.

    1
    WebDriverWait(driver,10).until(EC.text_to_be_present_in_element_value((By.CSS_SELECTOR,'some'),u'百度一下'))
  • frame_to_be_available_and_switch_to_it: 判断该frame是否可以switch进去,如果可以的话,返回True并且switch进去,否则返回False.

    1
    WebDriverWait(driver,10).until(EC.frame_to_be_available_and_switch_to_it(some))
  • invisibility_of_element_located: 判断某个元素在是否存在于dom或不可见,如果可见返回False,不可见返回这个元素.

    1
    WebDriverWait(driver,10).until(EC.invisibility_of_element_located((By.CSS_SELECTOR,'some')))
  • element_to_be_clickable: 判断某个元素中是否有可见并且是enable(可点击)的.

    1
    WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"some"))).click()
  • staleness_of: 等待某个元素从dom树中移除.

    1
    WebDriverWait(driver,10).until(EC.staleness_of(driver.find_element(By.ID,'some')))
  • element_to_be_selected: 判断某个元素是否被选中了,一般用在下拉列表.

    1
    WebDriverWait(driver,10).until(EC.element_to_be_selected(driver.find_element(By.XPATH,"some")))
  • element_located_to_be_selected: 判断元素是否被选中, 传入一个元组对象.
    暂没找到例子.

  • element_selection_state_to_be: 判断某个元素的选中状态是否符合预期.

    1
    WebDriverWait(driver,10).until(EC.element_selection_state_to_be(driver.find_element(By.XPATH,"some"),True))
  • element_located_selection_state_to_be: 判断某个元素的选中状态是否符合预期.

    1
    WebDriverWait(driver,10).until(EC.element_located_selection_state_to_be((By.XPATH,"some"),True))
  • alert_is_present: 判断页面上是否存在alert(Js弹窗),如果有就切换到alert并返回alert的内容.

    1
    WebDriverWait(driver,10).until(EC.alert_is_present())
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    '''
    示意代码, 不完整.
    '''

    from selenium import webdriver
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.common.by import By


    driver = webdriver.Chrome()

    wait = WebDriverWait(driver, 10)
    # 等待直到元素可以被点击
    element = wait.until(EC.element_to_be_clickable((By.ID, 'someid')))

6.18 Selenium 异常处理

demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def get_url(driver,url,num_retries = 5):
try:
driver.get(url)
# 切换成frame
driver.switch_to_frame("g_iframe")
# 休眠3秒,等待加载完成!
time.sleep(3)
html = driver.page_source
driver.close()
return html
except Exception as e:
if num_retries > 0:
time.sleep(5)
print(url)
print('Requests fail, retry!')
return get_url(driver = driver,url = url,num_retries = num_retries-1)
else:
print("Error:%s"%e)
return

视频课程

西瓜视频 https://www.ixigua.com/6850851809594966535/