Python_Selenium使用

前言

网络上有着很多这种类型的使用说明以及教程,但终归不是自己的。
遇到不会的时候还得不断的重复去百度,这样导致效率低下。
最终还是想着结合网上的教程,给自己归纳总结一部分库的使用,方便自己回顾。

selenium (from selenium import webdriver)

1、安装
2、基本使用
  • Selenium是一个用于Web应用程序测试的工具。
  • Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Firefox,Safari,Chrome,Opera等。
  • Selenium 可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。同时也可以获取页面的源代码,可以获取页面渲染后的元素,做到可见即可爬
'''
    功能如下:
    	自动弹出一个Chrome浏览器,浏览器首先会跳转至百度,然后输入Python,回车,等待3秒,自动关闭浏览器。
'''
import time

from selenium import webdriver
from selenium.webdriver.common.by import By  # 显示等待中使用By进行定位元素
from selenium.webdriver.common.keys import Keys  # 可以实现键盘回车的功能
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait


browser = webdriver.Chrome()  # 声明Chrome浏览器对象
try:
    browser.get('https://www.baidu.com')  # get()方法请求网页
    input_item = browser.find_element(By.ID, 'kw')  # 定位到百度输入框,find_element()方法获取单个元素节点
    input_item.send_keys('Python')  # send_keys()方法向input框中填入字符串
    input_item.send_keys(Keys.ENTER)  # 模拟键盘回车
    wait = WebDriverWait(browser, 10)  # 显示等待,指定加载的最长时间
    wait.until(EC.presence_of_element_located((By.ID, "content_left")))  # 等待内容节点,直到出现进行下一步
    print(browser.current_url)  # 获取当前浏览器中url
    print(browser.page_source)  # 获取当前url的网页源代码
finally:
    time.sleep(3)  # 等待3s
    browser.quit()  # 退出浏览器
3、声明浏览器对象
  • 在使用Selenium之前肯定要先声明浏览器对象,以下代码完成了浏览器对象的初始化并赋值给browser对象,接下来就是调用browser对象,让其执行一系列的人为操作。
'''
    功能如下:
        声明浏览器对象
'''

from selenium import webdriver
browser = webdriver.Chrome()
browser = webdriver.Firefox()
browser = webdriver.Edge()
browser = webdriver.Safari()
4、访问页面
  • get():请求网页,参数:url网址
'''
    功能如下:
        输入一个网址,通过selenium进行访问页面
'''

from selenium import webdriver
browser = webdriver.Chrome()  # 创建浏览器对象
browser.get("https://www.baidu.com")  # get() 方法访问页面
print(browser.page_source)  # 获取网页源代码
browser.quit()  # 退出浏览器
5、查找节点

更多请查看:英文文档中文文档

5.1 查找单个节点
  • find_element():返回的是WebElement类型,这个方法需要导入这个包from selenium.webdriver.common.by import By
    find_element_by_XXX:这个方法不需要额外添加依赖包
方法1方法2
find_element_by_idfind_element(By.ID, “”)
find_element_by_namefind_element(By.NAME, “”)
find_element_by_xpathfind_element(By.XPATH, “”)
find_element_by_link_textfind_element(By.LINK_TEXT, “”)
find_element_by_partial_link_textfind_element(By.PARTIAL_LINK_TEXT, “”)
find_element_by_tag_namefind_element(By.TAG_NAME, “”)
find_element_by_class_namefind_element(By.CLASS_NAME, “”)
find_element_by_css_selectorfind_element(By.CSS_SELECTOR, “”)

单独拿一个id做案例,代码使用参考如下:

'''
    功能如下:
        实现查找节点中id方法的案例
    案例网站:【豆瓣电影排行榜】https://movie.douban.com/chart

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

def fun_one():
    '''
    使用 find_element_by_xxx类型
    :return:
    '''
    icp1 = browser.find_element_by_id('icp')
    icp2 = browser.find_element_by_xpath('//span[@id="icp"]')
    icp3 = browser.find_element_by_css_selector('#icp')
    print("方法一:")
    print(icp1)
    print(icp2)
    print(icp3)


def fun_two():
    '''
    使用 find_element()类型
    :return:
    '''
    icp1 = browser.find_element(By.ID, 'icp')
    icp2 = browser.find_element(By.XPATH, '//span[@id="icp"]')
    icp3 = browser.find_element(By.CSS_SELECTOR, '#icp')
    print("方法二:")
    print(icp1)
    print(icp2)
    print(icp3)

if __name__ == '__main__':
    browser = webdriver.Chrome()
    browser.get('https://movie.douban.com/chart')
    wait = WebDriverWait(browser, 15)
    wait.until(EC.presence_of_element_located((By.ID, "content")))
    fun_one()  # 方法一:find_element_by_xxx类型
    fun_two()  # 方法二:find_element()类型
    browser.quit()

# 最后运行的结果如下
#方法一:
#<selenium.webdriver.remote.webelement.WebElement (session="65c0086ed6faf3c3c2b63e349de342d0", element="c62310d9-a5aa-4b66-9ed0-fd9ea0a178c0")>
#<selenium.webdriver.remote.webelement.WebElement (session="65c0086ed6faf3c3c2b63e349de342d0", element="c62310d9-a5aa-4b66-9ed0-fd9ea0a178c0")>
#<selenium.webdriver.remote.webelement.WebElement (session="65c0086ed6faf3c3c2b63e349de342d0", element="c62310d9-a5aa-4b66-9ed0-fd9ea0a178c0")>
#方法二:
#<selenium.webdriver.remote.webelement.WebElement (session="65c0086ed6faf3c3c2b63e349de342d0", element="c62310d9-a5aa-4b66-9ed0-fd9ea0a178c0")>
#<selenium.webdriver.remote.webelement.WebElement (session="65c0086ed6faf3c3c2b63e349de342d0", element="c62310d9-a5aa-4b66-9ed0-fd9ea0a178c0")>
#<selenium.webdriver.remote.webelement.WebElement (session="65c0086ed6faf3c3c2b63e349de342d0", element="c62310d9-a5aa-4b66-9ed0-fd9ea0a178c0")>
5.2 查找多个节点
  • find_elements():返回的是列表类型,列表里面每一个都是WebElement类型。
    find_elements_by_XXX:这个方法不需要额外添加依赖包
方法1方法2
find_elements_by_idfind_elements(By.ID, “”)
find_elements_by_namefind_elements(By.NAME, “”)
find_elements_by_xpathfind_elements(By.XPATH, “”)
find_elements_by_link_textfind_elements(By.LINK_TEXT, “”)
find_elements_by_partial_link_textfind_elements(By.PARTIAL_LINK_TEXT, “”)
find_elements_by_tag_namefind_elements(By.TAG_NAME, “”)
find_elements_by_class_namefind_elements(By.CLASS_NAME, “”)
find_elements_by_css_selectorfind_elements(By.CSS_SELECTOR, “”)
'''
    功能如下:
        实现查找节点中id方法的案例
    案例网站:【豆瓣电影排行榜】https://movie.douban.com/chart

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

def fun_one():
    '''
    使用 find_elements_by_xxx类型
    :return:
    '''
    items1 = browser.find_elements_by_css_selector('div.indent .item')
    items2 = browser.find_elements_by_xpath('//div[@class="indent"]//tr[@class="item"]')
    print("方法一:")
    print(items1)
    print(items2)


def fun_two():
    '''
    使用 find_elements()类型
    :return:
    '''
    items1 = browser.find_elements(By.CSS_SELECTOR, 'div.indent .item')
    items2 = browser.find_elements(By.XPATH, '//div[@class="indent"]//tr[@class="item"]')
    print("方法二:")
    print(items1)
    print(items2)


if __name__ == '__main__':
    browser = webdriver.Chrome()
    browser.get('https://movie.douban.com/chart')
    wait = WebDriverWait(browser, 15)
    wait.until(EC.presence_of_element_located((By.ID, "content")))
    fun_one()  # 方法一:find_elements_by_xxx类型
    fun_two()  # 方法二:find_elements()类型
    browser.quit()
6、节点交互(操作节点事件)
  • Selenium驱动浏览器执行一些动作,比较常见的方法有:
  • send_keys():输入文字方法
  • clear():清空文字
  • click():点击按钮
  • submit():回车
  • 更多操作见:文档
'''
    功能如下:
        实现input框的输入
        实现input框的清空
        实现元素的点击操作
'''

import time

from selenium import webdriver
from selenium.webdriver.common.by import By  # 显示等待中使用By进行定位元素
from selenium.webdriver.common.keys import Keys  # 可以实现键盘回车的功能
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait


browser = webdriver.Chrome()  # 声明Chrome浏览器对象
try:
    browser.get('https://cn.bing.com/')  # get()方法请求网页
    input_item = browser.find_element(By.ID, 'sb_form_q')  # 定位到百度输入框,find_element()方法获取单个元素节点
    input_item.send_keys('Python')  # send_keys()方法:向input框中填入字符串
    input_item.submit()  # 模拟键盘回车
    # input_item.send_keys(Keys.ENTER)  # 模拟键盘回车
    wait = WebDriverWait(browser, 10)  # 显示等待,指定加载的最长时间
    wait.until(EC.presence_of_element_located((By.ID, "b_results")))  # 等待内容节点,直到出现进行下一步

    time.sleep(1)
    input_item2 = browser.find_element(By.ID, 'sb_form_q')
    input_item2.clear()  # clear()方法:清空input框内容
    time.sleep(0.2)
    input_item2.send_keys("阿尔法")  # send_keys()方法:输入字符串
    browser.find_element(By.ID, "sb_form_go").click()  # click()方法:进行点击操作
finally:
    time.sleep(3)  # 等待3s
    browser.quit()  # 退出浏览器
7、动作链
  • 用selenium做自动化,有时候会遇到需要模拟鼠标操作才能进行的情况,比如单击、双击、点击鼠标右键、拖拽等等。而selenium给我们提供了一个类来处理这类事件——ActionChains
  • 更多操作见:文档

使用动作链常用的几个场景,如下:

  • 鼠标点击(单击、双击、右键)
  • 鼠标移动(解决hover的某些问题)
  • 鼠标拖拽(实现节点拖拽操作,将某个节点从一处拖拽到另一处。)
  • 按键监听(监听按键的状态)

ActionChains方法列表

click(on_element=None) 										# 单击鼠标左键
click_and_hold(on_element=None)     						# 点击鼠标左键,不松开
context_click(on_element=None)      						# 单击鼠标右键
double_click(on_element=None)       						# 双击鼠标左键
drag_and_drop(source, target)       						# 按住鼠标左键拖拽到某个元素然后松开
drag_and_drop_by_offset(source, xoffset, yoffset)  			# 拖拽到某个坐标(偏移量)然后松开
key_down(value, element=None) 								# 按下某个键盘上的键,不释放
key_up(value, element=None) 								# 松开某个键
move_by_offset(xoffset, yoffset) 							# 鼠标从当前位置移动到某个坐标
move_to_element(to_element) 								# 鼠标移动到某个元素的中间
move_to_element_with_offset(to_element, xoffset, yoffset) 	# 移动到距某个元素(左上角坐标)多少距离的位置
perform() 													# 执行链中的所有动作
release(on_element=None) 									# 在某个元素位置松开鼠标左键
reset_actions()												# 清除链中的所有操作
send_keys(*keys_to_send) 									# 发送某个键到当前焦点的元素
send_keys_to_element(element, *keys_to_send) 				# 发送某个键到指定元素
7.1 鼠标点击

示例网址:https://sahitest.com/demo/clicks.htm

'''
    功能如下:
        1. 实现左键单击操作
        2. 实现左键双击操作
        3. 实现右键单击操作
'''

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
import time

browser = webdriver.Chrome()  # 初始化浏览器对象

try:
    browser.maximize_window()  # 窗口最大化
    browser.get('http://sahitest.com/demo/clicks.htm')
    time.sleep(0.5)
    click_btn = browser.find_element(By.XPATH, '//input[@value="click me"]')  # 单击按钮
    doubleclick_btn = browser.find_element(By.XPATH, '//input[@value="dbl click me"]')  # 双击按钮
    rightclick_btn = browser.find_element(By.XPATH, '//input[@value="right click me"]')  # 右键单击按钮
    ActionChains(browser).click(click_btn).double_click(doubleclick_btn).context_click(rightclick_btn).perform()  # 链式用法,执行动作链
    time.sleep(0.5)
    textarea = browser.find_element(By.XPATH, '//textarea[@name="t2"]').get_attribute('value')  # 获取textarea文本域中的值
    print(textarea)
finally:
    time.sleep(3)
    browser.quit()
7.2 鼠标移动

示例网址:https://sahitest.com/demo/mouseover.htm

'''
    功能如下:
        解决某些hover的问题
'''

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
import time

browser = webdriver.Chrome()  # 初始化浏览器对象

try:
    browser.maximize_window()  # 窗口最大化
    browser.get('https://sahitest.com/demo/mouseover.htm')
    time.sleep(0.5)
    write = browser.find_element(By.XPATH, '//input[@value="Write on hover"]')  # Writer on hover
    black = browser.find_element(By.XPATH, '//input[@value="Blank on hover"]')  # Blank on hover
    action = ActionChains(browser)
    action.move_to_element(write).perform()  # 将鼠标移动到Writer on hover
    time.sleep(2)
    action.move_to_element(black).perform()  # 将鼠标移动到Blank on hover
finally:
    time.sleep(3)
    browser.quit()
7.3 鼠标拖拽

示例网址:https://sahitest.com/demo/dragDropMooTools.htm

'''
    功能如下:
        实现鼠标将某一个元素拖拽到另一个元素中
'''

from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
import time

browser = webdriver.Chrome()  # 初始化浏览器对象

try:
    browser.maximize_window()  # 窗口最大化
    browser.get('https://sahitest.com/demo/dragDropMooTools.htm')
    time.sleep(0.5)
    dragger = browser.find_element(By.ID, 'dragger')  # dragger
    items = browser.find_elements(By.XPATH, '//div[@class="item"]')  # items

    action = ActionChains(browser)
    action.drag_and_drop(dragger, items[0]).perform()  # 将drop拖拽到第一个item中
    time.sleep(2)
    action.drag_and_drop(dragger, items[2]).perform()  # 将drop拖拽到第三个item中
    time.sleep(2)
    action.drag_and_drop(dragger, items[-1]).perform()  # 将drop拖拽到第四个item中
finally:
    time.sleep(3)
    browser.quit()
7.4 按键监听

示例网址:http://sahitest.com/demo/keypress.htm

'''
    功能如下:
        在selenium中实现键盘的简易操作
'''

import time

from selenium import webdriver
from selenium.webdriver import Keys
from selenium.webdriver.common.action_chains import ActionChains

from selenium.webdriver.common.by import By

browser = webdriver.Chrome()
browser.maximize_window()
browser.get('http://sahitest.com/demo/keypress.htm')

key_up_radio = browser.find_element(By.ID, 'r1')  # 监测按键升起
key_down_radio = browser.find_element(By.ID, 'r2')  # 监测按键按下
key_press_radio = browser.find_element(By.ID, 'r3')  # 监测按键按下升起

enter = browser.find_elements(By.XPATH, '//form[@name="f1"]/input')[1]  # 输入框
result = browser.find_elements(By.XPATH, '//form[@name="f1"]/input')[0]  # 监测结果

# 监测key_down
key_down_radio.click()
ActionChains(browser).key_down(Keys.CONTROL, enter).key_up(Keys.CONTROL).perform()  # 在输入框中按下ctrl建
print(result.get_attribute('value'))
time.sleep(5)

# 监测key_up
key_up_radio.click()
enter.click()
ActionChains(browser).key_down(Keys.SHIFT).key_up(Keys.SHIFT).perform()  # 在输入框中按下shift建,松开
print(result.get_attribute('value'))
time.sleep(5)

# 监测key_press
key_press_radio.click()
enter.click()
ActionChains(browser).send_keys('a').perform()
print(result.get_attribute('value'))
time.sleep(5)
browser.quit()
8、执行JavaScript脚本
  • execute_script():可以直接模拟运行JavaScript,常见的几种执行场景如下:
    • 将滚动条拉至顶部
    • 将滚动条拉至底部
    • 直接使用js操作页面,能解决很多click()不生效的问题
    • 处理富文本,时间控件的输入

代码如下:

'''
    功能如下:
        - 将滚动条拉至顶部
	    - 将滚动条拉至底部
	    - JS执行元素操作(点击、输入文本、等)
'''
from selenium import webdriver
import time

from selenium.webdriver.common.by import By

browser = webdriver.Chrome()
browser.maximize_window()
browser.get('https://movie.douban.com/chart')
time.sleep(2)

# driver.execute_script("arguments[0].click();", element),点击操作
# driver.execute_script("arguments[0].scrollIntoView();", element),移动到目标元素,类似于滑动查找


# 滚动条拉到底部
js = 'window.scrollTo(0, document.body.scrollHeight)'
browser.execute_script(js)
print(f'''滚动条滑动到底部''')
time.sleep(2)

# 滚动条拉到顶部
js = 'window.scrollTo(0, 0)'
browser.execute_script(js)
print(f'''滚动条滑动到顶部''')
time.sleep(2)

# 输入文本操作
msg = '悬疑'
send_js = f"text_input = document.getElementById('inp-query'); " \
          f"text_input.value = '{msg}'"
browser.execute_script(send_js)
print(f'''{msg}文本输入成功。。。''')
time.sleep(2)

# 点击操作
input_btn = browser.find_element(By.CSS_SELECTOR, ".inp-btn input")
click_js = 'arguments[0].click();'
browser.execute_script(click_js, input_btn)
print(f'''搜索按钮点击成功''')

# 创建一个新的选项卡
browser.execute_script('window.open()')
handles = browser.window_handles  # 获取当前浏览器对象中有多少选项卡
print(handles)
browser.switch_to.window(handles[-1])  # 跳转到最后一个选项卡中
browser.get('https://www.taobao.com')  # 跳转至淘宝中

time.sleep(3)
browser.quit()
9、获取节点信息
  • page_source属性可以获取网页的源代码,也可以使用解析库(如正则表达式、BeautifulSoup、pyquery、parsel等)来提取信息

  • Selenium已经提供了选择节点的方法,返回的是WebElement类型,那么它也有相关的方法和属性来直接提取节点信息,如属性、文本等。这样的话,我们就可以不用通过解析源代码来提取信息了,非常方便。

    get_attribute():获取节点的属性,但是其前提是先选中这个节点,示例如下:

    from selenium import webdriver
    import time
    
    from selenium.webdriver.common.by import By
    
    browser = webdriver.Chrome()
    browser.maximize_window()
    browser.get('https://movie.douban.com/chart')
    time.sleep(2)
    
    items = browser.find_elements(By.XPATH, '//div[@class="pl2"]/a[1]')
    for item in items:
        print(item.get_attribute('href'))  # 获取节点属性href
    
    time.sleep(2)
    browser.quit()
    
    # 运行效果
    # https://movie.douban.com/subject/30314848/
    # https://movie.douban.com/subject/27199850/
    # https://movie.douban.com/subject/35874097/
    # https://movie.douban.com/subject/35008440/
    # https://movie.douban.com/subject/34861178/
    # https://movie.douban.com/subject/30165311/
    # https://movie.douban.com/subject/35769174/
    # https://movie.douban.com/subject/35307624/
    # https://movie.douban.com/subject/35303842/
    # https://movie.douban.com/subject/35441573/
    

    text:获取文本值,每个WebElement节点都有text属性,直接调用这个属性就可以得到节点内部的信息,示例如下:

    from selenium import webdriver
    import time
    
    from selenium.webdriver.common.by import By
    
    browser = webdriver.Chrome()
    browser.maximize_window()
    browser.get('https://movie.douban.com/chart')
    time.sleep(2)
    
    items = browser.find_elements(By.XPATH, '//div[@class="pl2"]/a[1]')
    for item in items:
        print(item.text)  # 获取文本数据
    
    time.sleep(2)
    browser.quit()
    
    # 运行结果
    # 瞬息全宇宙 / 妈的多重宇宙(台) / 奇异女侠玩救宇宙(港)
    # 暗夜博士:莫比亚斯 / 莫比亚斯 / 魔比煞(港)
    # 网络炼狱:揭发N号房 / 网路炼狱:揭发N号房(台) / 网络地狱:N号房现形记
    # 唐顿庄园2 / 唐顿庄园电影版2 / 唐顿庄园:全新世代(港/台)
    # 北欧人 / 北方人(台)
    # 坏蛋联盟 / 大坏蛋 / 坏家伙
    # 万湖会议 / The Conference
    # 渔港的肉子酱 / 渔港的肉子 / Fortune Favors Lady Nikuko
    # 迷失之城 / 迷失D城 / Lost City of D
    # 首尔怪谈 / Urban Myths / Urban Myths: Tooth Worms
    

    id属性:selenium 使用的内部 ID。
    location属性:获取节点在页面中的相对位置
    tag_name属性:可以获取标签名称
    size属性:可以获取节点元素大小

    '''
        功能如下:
            id属性:selenium 使用的内部 ID。
            location属性:获取节点在页面中的相对位置
            tag_name属性:可以获取标签名称
            size属性:可以获取节点元素大小
    '''
    
    from selenium import webdriver
    import time
    
    from selenium.webdriver.common.by import By
    
    browser = webdriver.Chrome()
    browser.maximize_window()
    browser.get('https://movie.douban.com/chart')
    time.sleep(2)
    
    item = browser.find_elements(By.XPATH, '//div[@class="pl2"]/a[1]')[0]
    print(item.id)  # 获取节点在selenium中的id
    print(item.location)  # 获取节点在页面中的位置
    print(item.size)  # 获取节点的大小
    print(item.tag_name)  # 获取节点的标签名称
    
    time.sleep(2)
    browser.quit()
    
    # 执行效果
    # 8c32db1c-1321-4674-9aee-92abad562603
    # {'x': 534, 'y': 281}
    # {'height': 16, 'width': 318}
    # a
    
10、切换iFrame

示例网址:https://sahitest.com/demo/iframesTest.htm
selenium中处理iFrame有三种方式

  • 1、如果iframe有id或name,则可根据iframe的id或name切换。

    <iframe name="aa"id="x-URS-iframe1610006384373.8518"></iframe>
    browser.switch_to.frame('x-URS-iframe1610006384373.8518')  # id定位
    browser.switch_to.frame('aa')  # name定位
    
  • 2、把iframe当作页面元素,通过元素定位表达式进行切换。

    <iframe name="aa"id="x-URS-iframe1610006384373.8518"></iframe>
    frame = browser.find_element_by_xpath('//iframe[@id="x-URS-iframe"]')  # 先定位元素
    browser.switch_to.frame(frame)  # 在切换iframe
    
  • 3、将iframe存储到list中,然后根据ifrane的索引定位 (适合页面有多个iframe,且前两种方法无法使用)。

    browser.switch_to.frame(0)
    
  • 返回上一级

    browser.switch_to.parent_frame()  # 返回上一级
    
  • 跳出iframe窗口并返回到Top Window 上

    browser.switch_to_default_conten()  # 跳出iframe窗口并返回Window主窗体
    
  • 这里案例只用将元素作为参数传递,进入iframe中。

    from selenium import webdriver
    import time
    
    from selenium.webdriver.common.by import By
    
    browser = webdriver.Chrome()
    browser.maximize_window()
    browser.get('https://sahitest.com/demo/iframesTest.htm')
    time.sleep(2)
    
    item = browser.find_element(By.ID, 'checkRecord').get_attribute('value')
    h2_out = browser.find_element(By.TAG_NAME, 'h2').text
    print(f'''外层的主体输出:{item}, {h2_out}''')
    
    time.sleep(2)
    # 第一层iframe
    iframe = browser.find_element(By.TAG_NAME, 'iframe')
    browser.switch_to.frame(iframe)
    h2_in = browser.find_element(By.TAG_NAME, 'h2').text
    print(f'''内层iframe的输出:{h2_in}''')
    
    time.sleep(2)
    browser.quit()
    
11、延迟等待(显示等待和隐式等待)
  • 在selenium中,get()方法会在网页框架加载完之后结束,但是在这时候获取网页源代码page_source,可能并不是浏览器加载完之后的数据,如果某些页面有额外的Ajax请求,我们在网页源代码中也不一定能成功获取到。所以,这里需要延时等待一定时间,确保节点已经加载出来。

  • 等待的方式有两种:一种是显示等待,一种是隐式等待

  • 隐式等待implicily_wait():当使用隐式执行测试时,如果selenium没有在DOM中找到节点,将继续等待,超出设定时间后则抛出找不到节点的异常。【换句话说,当前查找节点的节点没有立即出现,则进行等待隐式等待设定的时候,再查找DOM节点,默认的隐式等待时间为0】

    from selenium import webdriver
    from selenium.webdriver.common.by import By
    
    browser = webdriver.Chrome()
    browser.implicitly_wait(10)  # 隐式等待10s
    browser.maximize_window()
    browser.get('https://movie.douban.com/chart')
    
    items = browser.find_elements(By.XPATH, '//div[@class="pl2"]/a[1]')
    for item in items:
        print(item.get_attribute('href'))  # 获取节点属性href
    browser.quit()
    
  • 显式等待wait = WebDriverWait(browser,10):隐式等待的效果其实没有这么好,隐式等待只是设置固定等待一段时间,而页面会收到网络的影响。有一中更适合的显示等待方法,去处理上述问题,【简单的说,显示等待就是在查找节点时,设置一个最长等待时间,在这个规定的时间内,不断的间隔查找节点是否加载出来,如果加载出来,则返回查找的节点;如果到了规定时间依然没有加载出该节点,则抛出找不到节点的异常】

    import time
    
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.wait import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
    browser = webdriver.Chrome()
    browser.implicitly_wait(10)  # 隐式等待10s
    browser.maximize_window()
    browser.get('https://movie.douban.com/chart')
    
    item = WebDriverWait(browser, 10).\
        until(EC.presence_of_element_located((By.XPATH, '//div[@class="pl2"]')))
    print(item)
    time.sleep(2)
    browser.quit()
    # 运行结果
    <selenium.webdriver.remote.webelement.\
    WebElement (session="21cb0b79ea3b60b9711ae9bb7aab33a5", element="0d6c5acb-9eba-40eb-8075-3655d02b336a")> 
    
  • 详细操作:文档

等待条件含义
title_is标题是某内容
title_contains标题包含某内容
presence_of_element_located节点加载出来,传入定位元组,如(By.ID,‘p’)
visibility_of_element_located节点可见,传入定位元组
visibility_of可见,传入节点对象
presence_of_all_elements_located所有节点加载出来
text_to_be_present_in_element某个节点文本包含某文字
text_to_be_present_in_element_value某个节点值包含某文字
frame_to_be_available_and_switch_to_it加载并切换
invisibility_of_element_located节点不可见
element_to_be_clickable节点可点击
staleness_of判断一个节点是否仍在DOM,可判断页面是否已经刷新
element_to_be_selected节点可选择,传节点对象
element_located_to_be_selected节点可选择,传入定位元组
element_selection_state_to_be传入节点对象以及状态,相等返回true,否则返回False
element_located_selection_state_to_be传入定位元组以及状态,相等返回True,否则返回False
alert_is_present是否出现警告
12、前进与后退
  • back():后退
  • forward():前进
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
browser.get('https://www.taobao.com/')
browser.get('https://www.zhihu.com/')
browser.back()
time.sleep(1)
browser.forward()
browser.close()
13、Cookies使用
  • get_cookies():获取cookies 【列表格式】
  • add_cookie(dict):添加cookie【字典格式】
  • delete_cookie(name=“”):删除某一个cookie
  • delete_all_cookies():删除所有的cookies
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.baidu.com/')
cookies = browser.get_cookies()  # 获取页面的cookie【列表格式】
print(cookies)
time.sleep(1)
browser.add_cookie({'name': 'name', 'domain': '.baidu.com', 'value': 'xuan'})  # 添加cookie
time.sleep(0.5)
print(browser.get_cookies())
time.sleep(0.5)
browser.delete_all_cookies()  # 删除所有的cookies
time.sleep(0.5)
print(browser.get_cookies())
browser.close()

# 运行结果
# [{'domain': '.baidu.com', 'expiry': 1685068239, 'httpOnly': False, 'name': 'ZFY', 'path': '/', 'sameSite': 'None', 'secure': True, 'value': '6L4XyME:AUQ:AgwiMtufstx4tSWgLYItHOAIkkYt6HSMo:C'}, {'domain': '.baidu.com', 'expiry': 1653618639, 'httpOnly': False, 'name': 'BA_HECTOR', 'path': '/', 'secure': False, 'value': '8cak8121ah252lela01h8tpif15'}, {'domain': '.baidu.com', 'httpOnly': False, 'name': 'H_PS_PSSID', 'path': '/', 'secure': False, 'value': '36454_31253_36452_36421_36165_36488_36055_26350_36301_36469_36311_36447'}, {'domain': '.baidu.com', 'expiry': 1685068238, 'httpOnly': False, 'name': 'BAIDUID', 'path': '/', 'secure': False, 'value': 'C0B5A9B5DBE343265E238C99CE101CAC:FG=1'}, {'domain': '.baidu.com', 'expiry': 3801015885, 'httpOnly': False, 'name': 'BIDUPSID', 'path': '/', 'secure': False, 'value': 'C0B5A9B5DBE3432620590E72CBC92B05'}, {'domain': '.baidu.com', 'expiry': 3801015885, 'httpOnly': False, 'name': 'PSTM', 'path': '/', 'secure': False, 'value': '1653532239'}, {'domain': 'www.baidu.com', 'expiry': 1654396239, 'httpOnly': False, 'name': 'BD_UPN', 'path': '/', 'secure': False, 'value': '12314753'}, {'domain': 'www.baidu.com', 'httpOnly': False, 'name': 'BD_HOME', 'path': '/', 'secure': False, 'value': '1'}]
# [{'domain': '.baidu.com', 'expiry': 1685068239, 'httpOnly': False, 'name': 'ZFY', 'path': '/', 'sameSite': 'None', 'secure': True, 'value': '6L4XyME:AUQ:AgwiMtufstx4tSWgLYItHOAIkkYt6HSMo:C'}, {'domain': '.baidu.com', 'expiry': 1653618639, 'httpOnly': False, 'name': 'BA_HECTOR', 'path': '/', 'secure': False, 'value': '8cak8121ah252lela01h8tpif15'}, {'domain': '.baidu.com', 'httpOnly': False, 'name': 'H_PS_PSSID', 'path': '/', 'secure': False, 'value': '36454_31253_36452_36421_36165_36488_36055_26350_36301_36469_36311_36447'}, {'domain': '.baidu.com', 'expiry': 1685068238, 'httpOnly': False, 'name': 'BAIDUID', 'path': '/', 'secure': False, 'value': 'C0B5A9B5DBE343265E238C99CE101CAC:FG=1'}, {'domain': '.baidu.com', 'httpOnly': False, 'name': 'name', 'path': '/', 'secure': True, 'value': 'xuan'}, {'domain': '.baidu.com', 'expiry': 3801015885, 'httpOnly': False, 'name': 'BIDUPSID', 'path': '/', 'secure': False, 'value': 'C0B5A9B5DBE3432620590E72CBC92B05'}, {'domain': '.baidu.com', 'expiry': 3801015885, 'httpOnly': False, 'name': 'PSTM', 'path': '/', 'secure': False, 'value': '1653532239'}, {'domain': 'www.baidu.com', 'expiry': 1654396239, 'httpOnly': False, 'name': 'BD_UPN', 'path': '/', 'secure': False, 'value': '12314753'}, {'domain': 'www.baidu.com', 'httpOnly': False, 'name': 'BD_HOME', 'path': '/', 'secure': False, 'value': '1'}]
# []
  • 这里增加一个扩展功能,比如selenium的Cookies转换成字符串Cookie可以给requests使用,又或者requests的Cookie字符串转换成selenium可使用的list格式Cookies。
# 网页中的cookie转换成selenium使用的cookie
def cookie_seleinium(cookieStr, domain):
    '''
    将requests拿到的cookie转换成selenium使用的cookie
    :param cookieStr: cookie
    :param domain: 填入统一的domin域名
    :return:
    '''
    cookie_list = cookieStr.split(';')
    selenium_cookie_list = []
    for cookie in cookie_list:
        # print(cookie)
        # print(cookie.split('=', 1))
        cookie = cookie.strip()
        name = cookie.split('=', 1)[0]
        value = cookie.split('=', 1)[-1]
        cookie_dict = {
            "domain": domain,
            "name": name,
            "value": value,
            "path": "/"
        }
        selenium_cookie_list.append(cookie_dict)
    return selenium_cookie_list


# selenium获取cookie可转成requests使用的cookie
def selenium_requests_cookie(selenium_list):
    #获取cookies
    cookie_list = [item["name"] + "=" + item["value"] for item in selenium_list]
    cookieStr = ';'.join(item for item in cookie_list)
    return cookieStr
14、选项卡管理(切换句柄)
  • 获取当前句柄:browser.current_window_handle
  • 获取所有句柄:hanles = browser.window_handles
  • 切换指定句柄:handle = handles[-1] # 取最新窗口的id browser.switch_to.window(handle) # 切换窗口
  • 访问网页的时候,很多时候我们点击一个链接时,会新建一个选项卡,那么如何跳转至新打开的选项卡呢?就需要用到switch_to.window(handle)方法去跳转,以下代码会做一个小案例。
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
# 调用execute_script()方法,传入window.open()这个javascript语句新开启一个选项卡
browser.execute_script('window.open()')
# 获取当前开启的所有选项卡,返回的是选项卡的代号列表
print(browser.window_handles)
# 调用switch_to.window()方法切换选项卡,参数是选项卡代号,跳转到最后一个,选项卡中序号默认从0开始
browser.switch_to.window(browser.window_handles[-1])
browser.get('https://www.taobao.com')#打开淘宝页面
time.sleep(1)
browser.switch_to.window(browser.window_handles[0])#跳转到第一个选项卡
browser.get('https://douban.com')

time.sleep(1)
browser.quit()
# 运行结果:
# ['CDwindow-AD42B99E578AAAFBD39CE0B27261CEFB', 'CDwindow-A06ACF8B3CABE2F92782552A95C36071']
15、异常处理
  • 在使用selenium时,会经常遇到一些报错哦异常。例如:超时异常、节点未找到等报错异常,一旦出现这种异常,程序就会停止执行,这时我们可以使用try···except语句来实现捕获异常进行处理。
  • 更多异常类:文档
from selenium import webdriver
from selenium.common.exceptions import TimeoutException,NoSuchElementException
browser = webdriver.Chrome()
try:
	browser.get('https://www.baidu.com')
except TimeoutException:
	print('Time Out')
try:
	browser.find_element_by_id('hello')
except NoSuchElementException:
	print('No Element')
finally:
	browser.close()
# 运行结果
# No Element
16、浏览器退出
  • browser.close():关闭浏览器的一个标签页
  • browser.quit():关闭浏览器
17、截图操作
  • 在linux中,使用selenium进行截图,需要安装中文库,否则中文会变成方框。

  • Selenium截图有大的两个方式,一个是针对于浏览器而言,另一种是针对与元素而言

  • 针对于浏览器对象browser而言,有四种截图方式

    • driver.get_screenshot_as_base64():以 base64 编码字符串形式获取当前窗口的屏幕截图,在HTML界面输出截图时使用。
    • driver.get_screenshot_as_png():以二进制数据形式获取当前窗口的屏幕截图。
    • driver.save_screenshot(filename/full_path):获取截屏png图片,参数是文件名称,截屏必须是.png图片, 如果只给文件名,截图会保存在项目的根目录下面。
    • driver.get_screenshot_as_file(filename/full_path):获取截屏png图片,参数是文件的绝对路径,截屏必须是.png图片。如果只给文件名,截屏会存在项目的根目录下。
    import time
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    
    def save_screenshot_demo():
        '''
        获取截屏png图片,参数是文件名称,截屏必须是.png图片, 如果只给文件名,截图会保存在项目的根目录下面。
        :return:
        '''
        try:
            browser.get('https://www.baidu.com')
            browser.find_element(By.LINK_TEXT, '新闻').click()
            time.sleep(3)
            browser.switch_to.window(browser.window_handles[-1])
            browser.save_screenshot('save_screenshot_demo.png')  # save_screenshot的图片数据必须以png结尾
        finally:
            time.sleep(3)
            browser.quit()
    
    def get_screenshot_as_file_demo():
        '''
        获取截屏png图片,参数是文件的绝对路径,截屏必须是.png图片。如果只给文件名,截屏会存在项目的根目录下。
        :return:
        '''
        try:
            browser.get('https://www.baidu.com')
            browser.find_element(By.LINK_TEXT, '新闻').click()
            time.sleep(3)
            browser.switch_to.window(browser.window_handles[-1])
            browser.get_screenshot_as_file('get_screenshot_as_file_demo.png')  # get_screenshot_as_file的图片数据必须以png结尾
        finally:
            time.sleep(3)
            browser.quit()
    
    def get_screenshot_as_base64_demo():
        '''
        以 base64 编码字符串形式获取当前窗口的屏幕截图,在HTML界面输出截图时使用。
        :return:
        '''
        try:
            browser.get('https://www.baidu.com')
            browser.find_element(By.LINK_TEXT, '新闻').click()
            time.sleep(3)
            browser.switch_to.window(browser.window_handles[-1])
            b64 = browser.get_screenshot_as_base64()
            print(b64)
        finally:
            time.sleep(3)
            browser.quit()
    
    def get_screenshot_as_png_demo():
        '''
        以二进制数据形式获取当前窗口的屏幕截图。
        :return:
        '''
        try:
            browser.get('https://www.baidu.com')
            browser.find_element(By.LINK_TEXT, '新闻').click()
            time.sleep(3)
            browser.switch_to.window(browser.window_handles[-1])
            b_data = browser.get_screenshot_as_png()
            print(b_data)
        finally:
            time.sleep(3)
            browser.quit()
    
  • 针对于元素而言

    • element.screenshot(save_file_path):针对某一个元素进行截图,并报错到相对的路径文件
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as ec
    from selenium.webdriver.support.wait import WebDriverWait
    import random
    
    
    def selenium_screenshot(url, css_element: str, width=None, height=None, file_name=None):
        """
        快照截图(截图某个元素)
        :param url: url
        :param width:  窗口宽度
        :param height:
        :param css_element: css定位
        :return:
        """
        ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36"
        driver = ""
        ip = ''
        # ip = "xxx.xxx.xxx.xxx"
        try:
            chrome_options = Options()
            chrome_options.add_argument('--headless')  # 无头模式
            chrome_options.add_argument('--disable-gpu')  # 禁用gpu
            chrome_options.add_argument('--no-sandbox')
            chrome_options.add_argument(f'user-agent={ua}')  # 添加UA
            if ip:
                chrome_options.add_argument(f'--proxy-server=http://{ip}:port"')
            driver = webdriver.Chrome(options=chrome_options)
            driver.maximize_window()
            if width:
                driver.set_window_size(width, height)
            driver.get(url)
            wait = WebDriverWait(driver, 10)
            wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, css_element)))
            ele = driver.find_element(By.CSS_SELECTOR, css_element)
        except Exception as err:
            print(f"{url} selenium_screenshot false: {err} ")
            return
        else:
            if not file_name:
                file_name = random.random()
            save_file_path = f"{file_name}.png"
            ele.screenshot(save_file_path)
            print(f"selenium_screenshot success {url}")
            return save_file_path
        finally:
            if driver:
                driver.quit()
    
18、Selenium项目模板

这里给大家分享一个我自己常用的Selenium脚本执行的模板。

import time

from selenium.webdriver import Chrome, ChromeOptions
from selenium.webdriver.support.wait import WebDriverWait
from tenacity import retry, stop_after_attempt

TIME_OUT = 15  # wait最长等待时间

class Selenium_Chrome(object):
    def __init__(self):
        # 参数初始化
        self.chrome_path = r''  # 指定chrome版本浏览器存放的路径
        self.user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36'

    @retry(
        stop=stop_after_attempt(3)  # 重启三次
    )
    def start_chrome(self):
        '''

        Chrome初始化配置对象
        :return:
        '''
        chrome_options = ChromeOptions()
        if self.chrome_path:  # 如果指定Chrome的版本,就设置这个
            chrome_options.binary_location = self.chrome_path
        # chrome_options.add_argument("--headless")  # 无界面运行
        chrome_options.add_argument('accept-language="zh-CN,en-US;q=0.8"')
        chrome_options.add_argument(f'''user-agent={self.user_agent}''')
        chrome_options.add_experimental_option('useAutomationExtension', False)
        chrome_options.add_experimental_option('excludeSwitches', ['enable-automation'])
        chrome_options.add_argument("--disable-blink-features=AutomationControlled")
        chrome_options.add_argument('--disable-gpu')  # 爬虫的时候,我们一般会选择禁用GPU,如果不禁用,访客GPU都相同,太容易判断了
        chrome_options.add_argument('--no-sandbox')
        chrome_options.add_argument("-incognito")  # 设置无痕模式

        # 创建Chrome对象
        self.browser = Chrome(options=chrome_options)

        # 进行简单的规避操作
        self.browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
            "source": """
            Object.defineProperty(navigator, 'webdriver', {
              get: () => undefined
            })
          """
        })
        self.browser.maximize_window()  # 将窗口最大化
        self.wait = WebDriverWait(self.browser, TIME_OUT)

    def end_chrome(self):
        """
        清除缓存并关闭chrome
        """
        time.sleep(3)
        self.browser.delete_all_cookies()
        self.browser.quit()

    def start(self):
        try:
            self.start_chrome()
            '''
                这里存放主程序的各种执行函数
            '''
            self.browser.get('https://www.baidu.com')
        finally:
            self.end_chrome()

if __name__ == '__main__':
    test = Selenium_Chrome()
    test.start()

总结

以上便是目前我在selenium中常用的方法以及知识汇总,其中可能还会有欠缺,如果实际操作中,有用到其他的案例,也会继续在这里进行添加。当然如果文章中有不对的地方,欢迎评论区留言进行指导,我会及时更改。在这里非常感谢开头的几篇优质文章作为参考。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值