1、Selenium
Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,可以按指定的命令自动操作,不同是Selenium 可以直接运行在浏览器上,它支持所有主流的浏览器(包括PhantomJS这些无界面的浏览器)。
Selenium 可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生。
Selenium 自己不带浏览器,不支持浏览器的功能,它需要与第三方浏览器结合在一起才能使用。但是有时候需要让它内嵌在代码中运行,可以用一个叫 PhantomJS 的工具代替真实的浏览器。
安装:`pip install selenium`
selenium官方文档:https://selenium-python.readthedocs.io/index.html
2、PhantomJS
PhantomJs是一个基于webkit的"无界面"(headless)浏览器,它会把网站加载到内存并执行页面上的javascript,因为不会展示图形界面,所以运行起来比完整的浏览器要高效。
把Selenium和PhantomJS结合在一起,就可以运行一个非常强大的网络爬虫了,这个爬虫可以处理JavaScrip、Cookie、headers,以及任何我们真实用户需要做的事情。
安装:`sudo apt-get install phantomjs`
PhantomJS官方文档:https://phantomjs.org/documentation/
不过现在最新版的selenium不再支持了,可以选择Chrome。
3、快速入门
selenium库里有个叫webdriver的API,webdriver类似于可以加载网站的浏览器,它类似BeautifulSoup或其他Selector对象,用来查找页面元素,与页面上的元素进行交互(发送文本,点击等),以及执行其他动作来运运行网络爬虫。
(1)获取id标签的文本内容:driver.find_element_by_id("id_name").text
(2)获取标题:driver.title
(3)生成当前页面快照并保存:driver.save_screenshot("filename.png")
(4)id="kw"用来定位输入框,输入字符串:driver.find_element_by_id("kw").send_keys("爬虫")
(5)id="su"用来定位搜索按钮,click()是模拟点击:driver.find_element_by_id("su").click()
(6)获取网页渲染后的源代码:driver.page_source
(7)获取当前页面Cookie:driver.get_cookies()
(8)ctrl+a全选定位部分内容:driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'a')
(9)ctrl+x剪切定位部分内容:driver.find_element_by_id("kw").send_keys(Keys.CONTROL,'x')
(10)模拟enter回车键:driver.find_element_by_id("su").send_keys(Keys.RETURN)
(11)清楚选定部分的内容:driver.find_element_by_id("kw").clear()
(12)获取当前url:driver.current_url
(13)关闭当前页面,如果只有一个页面,会关闭浏览器:driver.close()
(14)关闭浏览器:driver.quit()
# 导入webdriver from selenium import webdriver # 调用键盘按钮操作时需要引入的keys包 from selenium.webdriver.common.keys import Keys import time # 调用环境变量指定的PhantomJS浏览器创建浏览器对象 driver = webdriver.Chrome() # 如果没有在环境变量指定chromedriver位置,则需要引用可执行文件 #driver = webdriver.Chrome(executable_path="/usr/bin/chromedriver") # get方法会一直等到页面被完全加载,然后才会继续程序,通常测试会选择time.sleep(2) driver.get("https://www.baidu.com") # 获取页面中 为head_wrapper的id标签的文本内容 # data = driver.find_element_by_id("head_wrapper").text # 打印获取到的数据 # print(data) """ 百度热榜 �换一换 1同一个世界同一个妈 4直播:相信未来义演再开唱 2奥巴马批评特朗普疫情应对 5强基计划直播 3吉林一女洗衣工确诊后再传11人 6今天,最想对妈妈说的话 """ # 打印页面标题 # print(driver.title) # 百度一下,你就知道 # 生成当前页面快照并保存 #driver.save_screenshot('baidu.png') # # id="kw"是百度搜索输入框,输入字符串“爬虫” # driver.find_element_by_id("kw").send_keys("爬虫") # # id="su"是百度搜索按钮,click是模拟点击 # driver.find_element_by_id("su").click() # # 延时2s,保证获取到实际的内容 # time.sleep(2) # # 获取新页面的快照 # driver.save_screenshot("爬虫.png") # 打印网页渲染后的源代码 # print(driver.page_source) # 获取当前页面cookie # print(driver.get_cookies()) # # 输入框重新输入内容 driver.find_element_by_id("kw").send_keys("python") # driver.find_element_by_id("su").click() # ctrl+a全选输入框内容 # driver.find_element_by_id('kw').send_keys(Keys.CONTROL, "a") # ctrl+x剪切输入框内容 # driver.find_element_by_id("kw").send_keys(Keys.CONTROL, "x") # 模拟enter回车键 driver.find_element_by_id("su").send_keys(Keys.RETURN) # 清空输入款内容 # driver.find_element_by_id('kw').clear() # 获取当前url print(driver.current_url) """ https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=python&fenlei=256&rsv_pq=f56af1be000010cf&rsv_t=682eH4uSAFnDdURF0mggnYJfY6t28dxq2Irnjwx%2F4vQhRZrNLQQ1UnwAVVo&rqlang=cn&rsv_enter=1&rsv_dl=tb&rsv_sug3=6&rsv_btype=i&inputT=132&rsv_sug4=132 """ # 关闭当前页面,如果只有一个页面,会关闭浏览器 time.sleep(3) driver.close() # 关闭浏览器 # driver.quit()
4、页面操作
selenium的webdriver提供了各种方法来寻找元素
假设有一个表单输入框:
<input type="text" name="user-name" id="passwd-id" />
那么通过find_element_by_*等方法可以找到元素:
# 获取id标签值 element = driver.find_element_by_id("passwd-id") # 获取name标签值 element = driver.find_element_by_name("user-name") # 获取标签名值 element = driver.find_element_by_tag_name("input") # 通过XPath来匹配 element = driver.find_element_by_xpath("//input[@id='passwd-id']")
5、定位UI元素(WebElements)
5.1 关于元素的选取,有如下的API单个元素选取:
`find_elements_by_id`
`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.2 selenium.webdriver.common.by下有一个By,可以结合find_element()一起使用
导入By`from selenium.webdriver.common.by import By`
(1)By ID
<div id = "cool" > ... < /div > element = driver.find_element_by_id("cool") ------------------------ or ------------------------- element = driver.find_element(by=By.ID,value="cool")
(2)By Class Name
<div class = "cheese" > <span > Cheddar < /span > </div > <div class = "cheese" > <span > Gouda < /span > </div > element = driver.find_elements_by_class_name("cool") ------------------------ or ------------------------- element = driver.find_elements(by=By.CLASS_NAME,value="cheese")
(3)By Link Text
<a href = "http://www.google.com/search?q=cheese" > cheese < /a > element = driver.find_elements_by_link_text("cool") ------------------------ or ------------------------- element = driver.find_elements(by=By.LINK_TEXT,value="cheese")
(4)By Partial Link Text
<a href = "http://www.google.com/search?q=cheese" >search for cheese < /a > element = driver.find_elements_by_partial_link_text("cool") ------------------------ or ------------------------- element = driver.find_elements(by=By.PARTIAL_LINK_TEXT,value="cheese")
(5)By CSS
<div id = "food" > <span class = "dairy" > milk < /span > <span class = "dairy aged" > cheese < /span > </div > element = driver.find_elements_by_css_selector("#food span.dairy.aged") ------------------------ or ------------------------- element = driver.find_elements(by=By.CSS_SELECTOR, "#food span.dairy.aged")
(6)By XPath
<input type = "text" name = "example" / > <INPUT type = "text" name = "other" / > element = driver.find_elements_by_xpath("//input") ------------------------ or ------------------------- element = driver.find_elements(by=By.XPATH, "//input")
(7)By Tag Name
<iframe src = "..." > </iframe > element = driver.find_elements_by_tag_name("iframe") ------------------------ or ------------------------- element = driver.find_elements(by=By.TAG_NAME, "iframe")
(8)By Name
<input name = "cheese" type = "text"/> element = driver.find_elements_by_name("cheese") ------------------------ or ------------------------- element = driver.find_elements(by=By.NAME, "cheese")
6、鼠标动作链
通过导入ActionChains类,来实现在页面上模拟一些鼠标操作,比如双击、右击、拖拽或者按住不动等。
# 导入webdriver from selenium import webdriver # 调用键盘按钮操作时需要引入的keys包 from selenium.webdriver.common.keys import Keys # 导入ActionChains类 from selenium.webdriver import ActionChains import time driver = webdriver.Chrome() driver.get("https://www.baidu.com") # 鼠标移动到"新闻",`ac`定义了元素的位置 ac = driver.find_element_by_xpath("//div[@id='s-top-left']/a[1]") ActionChains(driver).move_to_element(ac).perform() time.sleep(2) # 鼠标移动到”hao123“ ac = driver.find_element_by_xpath("//div[@id='s-top-left']/a[2]") ActionChains(driver).move_to_element(ac).perform() # 在ac位置单击 # ac = driver.find_element_by_xpath("//div[@id='s-top-left']/a[1]") # ActionChains(driver).move_to_element(ac).click(ac).perform() # 在ac位置双击 # ac = driver.find_element_by_xpath("//div[@id='s-top-left']/a[1]") # ActionChains(driver).move_to_element(ac).double_click(ac).perform() # 因为同时在这个地方双击,所以会弹出两个相同的窗口 # 在ac位置右击 # ac = driver.find_element_by_xpath("//div[@id='s-top-left']/a[1]") # ActionChains(driver).move_to_element(ac).context_click(ac).perform() # 在ac位置左键单击hold住 # ac = driver.find_element_by_xpath("//div[@id='s-top-left']/a[1]") # ActionChains(driver).move_to_element(ac).click_and_hold(ac).perform() # 将ac1拖拽到ac2位置 ac1 = driver.find_element_by_xpath("//div[@id='s-top-left']/a[1]") ac2 = driver.find_element_by_xpath("//div[@id='s-top-left']/a[2]") ActionChains(driver).drag_and_drop(ac1,ac2).perform()
7、SELECT表单
碰到<select></select>标签的下拉框,直接点击下拉框中的选项不一定可行。
Selenium专门提供了Select类来处理下拉框,
# 导入webdriver from selenium import webdriver from selenium.webdriver.support.ui import Select import time driver = webdriver.Chrome() driver.get("http://course.hbpu.edu.cn/G2S/ShowSystem/Index.aspx") # 找到class的选项卡 """ <select class="left search" onchange="searchChange(this)" style="margin-top:2px;"> <option value="OrganiseSearch.aspx">组织结构</option> <option value="SpecialtySearch.aspx">专业</option> <option value="TeacherSearch.aspx">教师</option> <option value="CourseSearch.aspx">课程</option> <option value="WebsiteSearch.aspx">课程网站</option> </select> """ # 定位后构造选择器 select_ = Select(driver.find_element_by_xpath("//select")) # 操作select_来选择,可以通过index,value,visible_text select_.select_by_index(2) time.sleep(2) select_.select_by_value("SpecialtySearch.aspx") time.sleep(2) select_.select_by_visible_text("课程") # 状态是”教师“>>>"专业>>>”课程“
以上是三种选择下拉框的方式,它可以根据索引来选择,可以根据值来选择,可以根据文字来选择。
说明:(1)index索引从0开始
(2)value是option标签的一个属性值,并不是显示在下拉框中的值
(3)visible_text是在option标签文本中的值,是显示在下拉框的值
如果全部取消选择:`select.deselect_all()`
8、弹窗处理
当触发了某个事件之后,页面出现了弹窗提示,处理这个提示或者获取提示信息的方法:
`alert = driver.switch_to_alert()`
9、页面切换
切换浏览器个页面窗口的方法:`driver.switch_to.window("this is window name")`
使用window_handles方法来获取每个窗口的操作对象:
```
for handle in driver.window_handles:
driver.switch_to_window(handle)
```
10、页面前进或后退
操作页面的前进和后退功能:
```
driver.forward() #前进
driver.back() #后退
```
11、Cookies
获取页面每个Cookies值,用法如下:
```
for cookie in driver.get_cookies():
print("{} -> {}".format(cookie['name'],cookie['value']))
```
删除Cookies,用法如下:
```
# 通过name
driver.delete_cookie("CookieName")
# 删除所有
driver.delete_all_cookies()
```
12、页面等待
现在的网页越来越多采用了 Ajax 技术,这样程序便不能确定何时某个元素完全加载出来了。如果实际页面等待时间过长导致某个dom元素还没出来,但是你的代码直接使用了这个WebElement,那么就会抛出NullPointer的异常。
为了避免这种元素定位困难而且会提高产生 ElementNotVisibleException 的概率。所以 Selenium 提供了两种等待方式,一种是隐式等待,一种是显式等待。
隐式等待是等待特定的时间,显式等待是指定某一条件直到这个条件成立时继续执行
12.1 显式等待
显式等待指定某个条件,然后设置最长等待时间,如果在这个时间还没有找到元素,那么便会抛出异常。
from selenium import webdriver from selenium.webdriver.common.by import By # 导入WebDriverWait库,负责循环等待 from selenium.webdriver.support.ui import WebDriverWait # 导入expected_conditions类,负责条件触发 from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() driver.get("http://www.baidu.com") try: # 页面一致循环,直到id="myDynamicElement"出现 element=WebDriverWait(driver,10).until( EC.presence_of_element_located((By.ID,"myDynamicElement")) ) finally: driver.quit()
如果不写参数,程序默认会0.5s调用一次来查看元素是否已经生成,如果本来元素就是存在,那么会立即返回。
expected_conditions中内置的等待条件,可以直接调用这些条件,而不用自己写某些等待条件:
`title_is`
`title_contains`
`persence_of_element_located`
`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-it is Displayed and Enabled`
`staleness_of`
`element_to_be_selected`
`element_located_to_be_selected`
`element_selection_state_to_be`
`element_location_selection_state_to_be`
`alert_is_present`
12.2 隐式等待
隐式等待比较简单,就是简单地设置一个等待时间,单位为秒。
from selenium import webdriver driver = webdriver.Chrome() driver.implicitly_wait(10) #等待10s driver.get('http://www.baidu.com') myDynamicElement = driver.find_element_by_id("myDynamicElement")
如果不设置,则默认等待时间为0。