什么是Selenium
主要用于自动化测试工具,支持多浏览器:chrome,Firefox,Android浏览器等,主要用于驱动浏览器,给浏览器发一些指令,让浏览器执行各种动作:输入、跳转、点击、下拉等操作。它在爬虫中主要解决javaScript渲染问题,完全模拟网页的加载。
在做爬虫的时候如果遇到Request、urllib无法正常获取网页内容,那么这可能是JavaScript渲染致使的问题,这时使用Selenium可以完成渲染,即模拟浏览器完整的操作,之后获取到的源代码就是网页渲染后的源代码,可以完全解决javaScript渲染问题。
安装
- pip install selenium
- 点击我,下载chromedriver:这里使用的是chrome 版本是68所以下载的是2.42版本的驱动,下载解压后,解压后的文件所在的路径必须配置在环境变量path中。不同版本的下载只需要把url中的2.42更改为对应的版本号就行驱动的版本和浏览器版本兼容说明
基本使用
下面是一个简单实例代码:
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()#chrom浏览器驱动对象
try:
browser.get('https://www.baidu.com')#传入url,此时会跳出浏览器,访问百度网址
input = browser.find_element_by_id('kw') #找出id为kw元素
input.send_keys('Python')#kw中发送python
input.send_keys(Keys.ENTER)#回车
wait = WebDriverWait(browser, 10)#等待加载完成
wait.until(EC.presence_of_element_located((By.ID, 'content_left')))#等待content_left加载完成
print(browser.current_url)
#print(browser.get_cookies())
#print(browser.page_source)
finally:
browser.close()
输出的当前网页url其实就是我们搜索关键词时浏览器地址栏的地址:
https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=Python&rsv_pq=e7742729000658f1&rsv_t=cc28oZ5U7GMkpj%2FJdBtJXIrYy8IMIXVo35002Hb4hIvJpqwhNFLtlB9KzUw&rqlang=cn&rsv_enter=1&rsv_sug3=6&rsv_sug2=0&inputT=75&rsv_sug4=76
pageSource太长了就没打印
(1)声明浏览器对象
from selenium import webdriver
browser = webdriver.Chrome()
browser = webdriver.Firefox()
browser = webdriver.Edge()
browser = webdriver.PhantomJS()
browser = webdriver.Safari()
(2) 访问页面
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
print(browser.page_source)
browser.close()
(3)查找单个元素
获取到网页源码后,可能需要进行一些交互的操作:输入框、按钮点击之类的。
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, input_second, input_third)#三个结果一样
browser.close()
输出的三个结果其实是一样的,也就是可以使用不同的方法找元素
<selenium.webdriver.remote.webelement.WebElement (session="5e53d9e1c8646e44c14c1c2880d424af", element="0.5649563096161541-1")>
<selenium.webdriver.remote.webelement.WebElement (session="5e53d9e1c8646e44c14c1c2880d424af", element="0.5649563096161541-1")>
<selenium.webdriver.remote.webelement.WebElement (session="5e53d9e1c8646e44c14c1c2880d424af", element="0.5649563096161541-1")>
常用的查找单个元素方法:
- find_element_by_name
- find_element_by_xpath
- find_element_by_link_text
- find_element_by_partial_link_text
- find_element_by_tag_name
- find_element_by_class_name
- find_element_by_css_selector
上面这些方法可以通过一个统一的方式使用:
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
input_first = browser.find_element(By.ID, 'q')
print(input_first)
browser.close()
(4)查找多个元素
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()
下面与上面方式一样:
from selenium import webdriver
from selenium.webdriver.common.by import By
browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
lis = browser.find_elements(By.CSS_SELECTOR, '.service-bd li')#列表
print(lis)
browser.close()
常用的查找多个元素方法:
- find_elements_by_name
- find_elements_by_xpath
- find_elements_by_link_text
- find_elements_by_partial_link_text
- find_elements_by_tag_name
- find_elements_by_class_name
- find_elements_by_css_selector
(5)元素的交互操作
from selenium import webdriver
import time
browser = webdriver.Chrome()
browser.get('https://www.taobao.com')
input = browser.find_element_by_id('q')
input.send_keys('iPhone')
time.sleep(1)#等待1秒
input.clear()
input.send_keys('iPad')搜索IPad
button = browser.find_element_by_class_name('btn-search')
button.click()
上面程序含义是:在淘宝中搜索“iPad”,那么为什么是find_element_by_id('q')呢?q又是从何而来的呢?我们打开淘宝首页,邮件,审查元素,鼠标点击淘宝的搜索框,如下图所示:
这就是id为‘q’的由来。当我们在淘宝搜索iPhone时,再次点击邮件->检查,结果如下图所示:
这就是‘q’的由来。
另外,btn-search是怎么来的呢?
另外,实际测试中发现填写:tb-bg也是可以的
更多操作: http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.remote.webelement
(6)交互动作
和上面的元素交互动作是不同的:
- 元素交互动作需要先获取一个特定的元素,调用相应的方法完成响应动作
- 这里是将动作附加到动作链中串行执行
比如人机验证时的拖拽:
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()
上面的draggable和droppable都来自上图,执行后就将小方框拖动到大方框中了
更多操作: http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.common.action_chains
执行JavaScript
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
browser.execute_script('alert("To Bottom")')
(7)获取元素属性、文本值
from selenium import webdriver
from selenium.webdriver import ActionChains
browser = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
browser.get(url)
logo = browser.find_element_by_id('zh-top-link-logo')
print(logo.text)#文本值
print(logo.get_attribute('class'))
输出:
知乎
zu-top-link-logo
获取ID、位置、标签名、大小
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)
输出:
0.6822924344980397-1
{'y': 7, 'x': 774}
button
{'height': 32, 'width': 66}
Frame
Frame在网页中可能出现比较频繁,但是如果出现了Frame,在做元素筛选的时候会导致一些不太方便的问题:有些Frame相对于一个独立的网页,在父级的Frame中,想查找子元素的Frame,实际上必须切换到Frame中才能进行查找,否则是不能完成元素的查找。
比如之前拖拽案例中的源代码:
整个拖拽是在一个iframe中,但是如果我们在这个iframe中想要获取外面的那些元素,获取时可能汇报错误,比如在拖拽那个iframe中尝试获取logo class,此时汇报找不到该元素的错误:
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')#切换到拖拽那个iframe中
source = browser.find_element_by_css_selector('#draggable')
print(source.text)#
try:
logo = browser.find_element_by_class_name('logo')#尝试找外面的元素
except NoSuchElementException:
print('NO LOGO')#没找到
browser.switch_to.parent_frame()#切换到父iframe查找
logo = browser.find_element_by_class_name('logo')
print(type(logo))
print(logo.text)
输出:
请拖拽我!
NO LOGO
<class 'selenium.webdriver.remote.webelement.WebElement'>
RUNOOB.COM
不能在子frame查找父frame中的元素
等待
我们在爬取数据的时候可能会有一些Ajax请求,这些Ajax请求不会管Selenium是否完成了网页的加载,也就是说:Selenium只是把基本的框架给加载出来了,如果有一些后续的Ajax请求等其他的操作,可能会出现有部分元素没有加载完全,在没加载完时进行操作会导致一些问题的出现。所以,我们需要加一些等待,确保元素都完成加载后在进行一些操作,这样可以减少异常。
等待分为两种:显式等待和隐式等待。
(1)隐式等待
当使用了隐式等待执行测试的时候,如果 WebDriver没有在 DOM中找到元素,将继续等待,超出设定时间后则抛出找不到元素的异常, 换句话说:当查找元素或元素并没有立即出现的时候,隐式等待将等待一段时间再查找 DOM,默认的时间是0
from selenium import webdriver
browser = webdriver.Chrome()
browser.implicitly_wait(10)#隐式等待时间10秒
browser.get('https://www.zhihu.com/explore')
#当网速比较慢时会出现下面的元素没加载出来
input = browser.find_element_by_class_name('zu-top-add-question')
print(input)
(2)显示等待
- 指定一个等待条件
- 指定一个最长等待时间
在最长等待时间内判断条件是否成立,如果成立则立即返回;否则一直等待到最长等待时间,超时会抛出异常。
常用的等待条件:
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 frame加载并切换
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 是否出现Alert
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
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, button)
详细等待条件介绍:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions
浏览器的前进和后退
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.python.org/')
browser.back()
browser.back()
time.sleep(1)
browser.forward()
browser.close()
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())
浏览器选项卡的操作
新增浏览器选项卡:最简单的就是通过js打开新的选项卡;另外就是通过模拟键盘按键(浏览器可以通过快捷键打开选项卡),不太通用,不同浏览器快捷方式不一样:
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')#第一个选项卡切换到python
异常处理
例如:某个元素无法点击异常、加载超时异常、没有找到元素的异常,各类异常最好查看官方文档:
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()
exception的详细介绍文档:
http://selenium-python.readthedocs.io/api.html#module-selenium.common.exceptions
扫描下方二维码,及时获取更多互联网求职面经、java、python、爬虫、大数据等技术,和海量资料分享:
公众号菜鸟名企梦
后台发送“csdn”即可免费领取【csdn】和【百度文库】下载服务;
公众号菜鸟名企梦
后台发送“资料”:即可领取5T精品学习资料、java面试考点和java面经总结,以及几十个java、大数据项目,资料很全,你想找的几乎都有
网友评论