Selenium(from selenium import webdriver)
1、安装
2、基本使用
- Selenium是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作,同时还可以获取浏览器当前呈现的页面的源代码,做到可见即可爬。
- 以下代码运行:会自动弹出一个Chrome浏览器。浏览器首先会跳转到百度,然后在搜索框中输入Python,接着就会跳转到搜索结果页。
from selenium import webdriver
from selenium.webdriver.common.by import 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()
try:
browser.get("https://www.baidu.com")
input_item = browser.find_element_by_id('kw')
input_item.send_keys('Python')
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)
print(browser.get_cookies)
print(browser.page_source)
finally:
browser.quit()
3、声明浏览器对象
- 以下代码完成了浏览器对象的初始化并将其赋值为browser对象,接下来就是调用browser对象,让其执行各个动作以模拟浏览器操作
from selenium import webdriver
browser = webdriver.Chrome()
browser = webdriver.Firefox()
browser = webdriver.Edge()
browser = webdriver.PhantomJS()
browser = webdriver.Safari()
4、访问页面
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
print(browser.page_source)
browser.quit()
5、查找节点
- (1)find_element():查找单个节点,返回的是WebElement类型;所有方法如下表,其中方法1和方法2是等价的,但方法2需要导库方可使用:from selenium.webdriver.common.by import By:
方法1 | 方法2 |
---|
find_element_by_id() | find_element(By.ID,) |
find_element_by_name() | find_element(By.NAME,) |
find_element_by_xpath() | find_element(By.XPATH,) |
find_element_by_link_text() | find_element(By.LINK_TEXT,) |
find_element_by_partial_link_text() | find_element(By.PARTIAL_LINK_TEXT,) |
find_element_by_tag_name() | find_element(By.TAG_NAME,) |
find_element_by_class_name() | find_element(By.CLASS_NAME,) |
find_element_by_css_selector() | find_element(By.CSS_SELECTOR,) |
- (1) 查找单个节点例子:如下代码使用3种方式获取输入框,分别是ID/CSS选择器/XPath,它们返回的结果一致。
browser.find_element(By.ID,‘q’)等价于
input_first = browser.find_element_by_id(‘q’)
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
input_first = browser.find_element_by_id('q')
input_second = browser.find_element_by_css_selector(' # q')
input_third = browser.find_element_by_xpath('//*[@id="q"]')
print(input_first)
print(input_second)
print(input_third)
browser.close()
- (2)find_elements():查找多个节点方法如下:
方法1 | 方法2 |
---|
find_elements_by_id() | find_elements(By.ID,) |
find_elements_by_name() | find_elements(By.NAME,) |
find_elements_by_xpath() | find_elements(By.XPATH,) |
find_elements_by_link_text() | find_elements(By.LINK_TEXT,) |
find_elements_by_partial_link_text() | find_elements(By.PARTIAL_LINK_TEXT,) |
find_elements_by_tag_name() | find_elements(By.TAG_NAME,) |
find_elements_by_class_name() | find_elements(By.CLASS_NAME,) |
find_elements_by_css_selector() | find_elements(By.CSS_SELECTOR,) |
- (2)查找多个节点例子,返回的是列表类型,列表中的每个节点都是WebElement类型:
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
lis = browser.find_elements_by_css_selector('.service-bd li')
print(lis)
browser.close()
6、节点交互
- Selenium驱动浏览器执行一些动作,比较常见的方法有:
- send_keys():输入文字方法
- clear():清空文字
- click():点击按钮
- 更多操作见:文档
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
browser = webdriver.Chrome()
browser.get("https://www.taobao.com")
input_item = browser.find_element(By.ID, 'q')
input_item.send_keys('iPhone')
time.sleep(1)
input_item.clear()
input_item.send_keys('iPad')
button = browser.find_element(By.CLASS_NAME, 'btn-search')
button.click()
browser.close()
7、动作链
- 上面实例中,一些交互动作都是针对某个节点执行的。比如:对于输入框,我们就调用它的输入文字和清空文字方法;对于按钮,就调用它的点击方法。其实,还有另外一些操作,它们没有特定的执行对象,比如鼠标拖拽、键盘按键灯,这些动作用另一种方式来执行,那就是动作链。
- 实现节点拖拽操作,将某个节点从一处拖拽到另外一处,
- -更多操作见:文档
from selenium import webdriver
from selenium.webdriver import ActionChains
browser = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
browser.switch_to.frame('iframeResult')
source = browser.find_element_by_css_selector('#draggable')
target = browser.find_element_by_css_selector('#droppable')
actions = ActionChains(browser)
actions.drag_and_drop(source, target)
actions.perform()
8、执行JavaScript
- execute_script():可以直接模拟运行JavaScript,比如下拉进度条;基本上API没有提供的所有功能都可以用执行JavaScript的方式来实现;
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
browser.execute_script('alert("To Bottom")')
9、获取节点信息
- (1)page_source属性可以获取网页的源代码,也可以使用解析库(如正则表达式、BeautifulSoup、pyquery等)来提取信息
- (2)Selenium已经提供了选择节点的方法,返回的是WebElement类型,那么它也有相关的方法和属性来直接提取节点信息,如属性、文本等。这样的话,我们就可以不用通过解析源代码来提取信息了,非常方便。
- (2)get_attribute():获取节点的属性,但是其前提是先选中这个节点,示例如下:
from selenium import webdriver
browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
browser.get(url)
logo = browser.find_element_by_id('zh-top-link-logo')
print(logo)
print(logo.get_attribute('class'))
- (2).text:获取文本值,每个WebElement节点都有text属性,直接调用这个属性就可以得到节点内部的文本信息,示例如下:
from selenium import webdriver
browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
browser.get(url)
input = browser.find_element_by_class_name('zu-top-add-question')
print(input.text)
- (2).id .location .tag_name .size;id属性可以获取节点id,location属性获取节点在页面中的相对位置,tag_name属性可以获取标签名称,size属性可以获取节点大小,也就是宽高,示例如下:
from selenium import webdriver
browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
browser.get(url)
input = browser.find_element_by_class_name('zu-top-add-question')
print(input.id)
print(input.location)
print(input.tag_name)
print(input.size)
10、切换Frame
- switch_to.frame():获取子Frame里面的节点,子Frame相当于页面的子页面
import time
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
browser = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
browser.get(url)
browser.switch_to.frame('iframeResult')
try:
logo = browser.find_element_by_class_name('logo')
except NoSuchElementException:
print('NO LOGO')
browser.switch_to.parent_frame()
logo = browser.find_element_by_class_name('logo')
print(logo)
print(logo.text)
11、延时等待
- 在selenium中,get()方法会在网页框架加载结束后结束执行,此时如果获取page_source,可能并不是浏览器完全加载完成的页面,如果某些页面有额外的Ajax请求,我们在网页源代码中也不一定能成功获取到。所以,这里需要延时等待一定时间,确保节点已经加载出来。
- 等待的方式有两种:一种是隐式等待,一种是显式等待。
- 隐式等待implicily_wait():当使用隐式等待执行测试的时候,如果selenium没有在DOM中找到节点,将继续等待,超出设定时间后,则抛出找不到节点的异常。换句话说,当查找节点而节点并没有立即出现的时候。隐式等待将等待一段时间再查找DOM,默认的时间是0。示例如下:
from selenium import webdriver
browser = webdriver.Chrome()
browser.implicitly_wait(10)
browser.get('http://www.zhihu.com/explore')
input = browser.find_element_by_class_name('zu-top-add-question')
print(input)
- 显式等待wait = WebDriverWait(browser,10),隐式等待的效果其实并没有那么好,因为我们只规定了一个固定的时间,而页面加载时间会受到网络条件的影响。这里还有一种更合适的显式等待方法,它指定要查找的节点,然后指定一个最长等待时间。如果在规定时间内加载出来了这个节点,就返回查找的节点;如果到了规定时间依然没有加载出该节点,则抛出超市异常。示例如下:
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.get('https://www.taobao.com')
wait = WebDriverWait(browser,10)
input = wait.until(EC.presence_of_element_located((By.ID,'q')))
button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'.btn-search')))
print(input)
print(button)
等待条件 | 含义 |
---|
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、前进与后退
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():添加cookie
- delete_all_cookies():删除cookies
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
print(browser.get_cookies())
browser.add_cookie({'name':'name','domain':'www.zhihu.com','value':'germey'})
print(browser.get_cookies())
browser.delete_all_cookies()
print(browser.get_cookies())
14、选项卡管理
- 在访问网页的时候,会开启一个选项卡。在Selenium中,我们可以对选项卡进行操作,实例如下:
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.baidu.com')
browser.execute_script('window.open()')
print(browser.window_handles)
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://python.org')
15、异常处理
- 在使用Selenium的过程中,难免会遇到一些异常,例如超时、节点未找到等错误,一旦出现此类错误,程序便不会继续运行了。用try except语句来捕获各种异常。
- 更多异常类参考:https://selenium-python.readthedocs.io/api.html#module-selenium.common.exceptions
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()
16、其他浏览器退出
- browser.close():关闭浏览器的一个标签页
- browser.quit():关闭浏览器
- linux环境下截屏需要安装中文库,否则中文字会全部显示方框
17、截图
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
import logging
def selenium_screenshot(url, css_element: str, width, height):
"""
快照截图
:param url: url
:param width: 窗口宽度
:param height:
:param css_element: css定位
:return:
"""
ua = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:50.0) Gecko/20100101Firefox/50.0"
driver = ""
ip = "xxx.xxx.xxx.xxx"
try:
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument(f'user-agent={ua}')
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:
logging.warning(f"{url} selenium_screenshot false: {err} ")
return
else:
save_file_path = f"{random.random()}.png"
ele.screenshot(save_file_path)
logging.info(f"selenium_screenshot success {url}")
return save_file_path
finally:
if driver:
driver.quit()