selenium——自动化测试工具,专门为Web应用程序编写的一个验收测试工具,测试其兼容性,功能什么的。然而让虫师们垂涎的并非以上的种种,而是其经过驱动浏览器得到的解析JavaScript的能力。因此说这货在动态爬取方面简直是挂逼级别的存在,相较于手动分析更简单易用,节省分析打码时间。css
虽然selenium因其“超能力”被很多人吹上天了,可是认清利弊,根据需求来选择爬虫工具,仍是挺重要的,因此这里简单说下以供参考:python
理由:打开一个/多个浏览器,浏览器里还有n个窗口.....
下面很少说,进入正题git
本体直接pip安装pip install selenium
github
驱动按需选择:web
下载好后把解压获得的驱动放到设置了环境变量的路径下就好了,若是你的python设置了环境变量,应该丢到python目录下就好了。ajax
照例贴上文档,2.53旧版中文,想学更多就给我啃
选好浏览器就建立实例,以后的操做都在这个实例之上,并介绍一些有用的option,本文以Chrome为例。算法
from selenium import webdriver #其余浏览器把Chrome换名就行 #option = webdriver.ChromeOptions() #option.set_headless() 设置无头浏览器,就是隐藏界面后台运行 driver = webdriver.Chrome() #建立driver实例 #driver = webdriver.Chrome(chrome_options=option) 建立实例并载入option url = '**********' driver.get(url) #driver.maximize_window() 最大化窗口 #driver.set_window_size(width,height) 设置窗口大小 print(driver.page_source) #打印网页源码 driver.quit() # 关闭浏览器
对付低级的动态网页(ajax较少)就是这么简单,基本不用考虑动态问题,徒手撸动态的人表示羡慕。然而更多时候并不像这样简单,直接套用的话很容易致使源码所见非所得,并且不少爬虫并无简单到拿个源码就走的程度,它还要交互,模拟点击滚动等等。因此还请往下看,不要看到这就投入实战啦chrome
selenium提供多种方法对元素进行定位,返回WebElement对象,而上面提到的driver就至关于最大的WebElement对象npm
#如下都是单次定位,返回第一个定位到的。若是想屡次定位,给element加个s就行,返回的是符合元素的列表 element = driver.find_element_by_id() # 经过标签的id定位,接收id属性值 driver.find_element_by_name() # 经过标签的name定位,接收name属性值 driver.find_element_by_xpath() # 经过xpath定位,接收xpath表达式 driver.find_element_by_link_text() # 经过标签的彻底文本定位,接收完整的文本 driver.find_element_by_partial_link_text() # 经过标签的部分文本定位,接收部分文本 driver.find_element_by_tag_name() # 经过标签名定位,接收标签名 driver.find_element_by_class_name() # 经过标签的class定位,接收class属性值 driver.find_element_by_css_selector() # 经过css选择器定位,接收其语法 #返回的WebElement对象能够继续往下定位
xpath和css就不展开讲了,能实现精肯定位,必定要学其中一个,不知道的小伙伴们上网自学吧,不难windows
除了上面这些公有的方法,还有2个私有的方法来帮助页面对象的定位。 这两个方法就是 find_element 和 find_elements,须要导入By类辅助,接收一个By类属性及其对应语法/值
from selenium.webdriver.common.by import By driver.find_element(By.XPATH,'//a[text()="dark"]') driver.find_elements(By.XPATH,'//a[text()="dark"]') '''By类有如下属性 ID = "id" XPATH = "xpath" LINK_TEXT = "link text" PARTIAL_LINK_TEXT = "partial link text" NAME = "name" TAG_NAME = "tag_name" CLASS_NAME = "class name" CSS_SELECTOR = "css selector" '''
不少人在用selenium会遇到所见非所得,或者定位页面元素的时候会定位不到的问题,这种状况颇有多是frame在搞鬼,必须切换到相应frame中再进行定位。若是遇到以上问题,第一时间F12看下你所要的信息是否在frame标签里面。
frame标签有frameset、frame、iframe三种,frameset跟其余普通标签没有区别,不会影响到正常的定位,而frame与iframe对selenium定位而言是同样的。
selenium提供了4种方法定位iframe并切换进去:
#对于<iframe name="frame1" id="dark">.....</iframe> driver.switch_to_frame(0) # 用frame的index来定位,第一个是0,以此类推 driver.switch_to_frame("frame1") # 用id来定位 driver.switch_to_frame("dark") # 用name来定位 driver.switch_to_frame(driver.find_element_by_tag_name("iframe")) # 用WebElement对象来定位
一般经过id和name就能实现,无此属性时能够经过WebElement对象,即用find_element系列方法所取得的对象来定位。若是你肯定每一个目标frame都是固定第几个,那也能够用index定位
切到frame中以后,就不能继续操做主文档的元素了,这时若是想操做主文档内容,则需切回主文档。
driver.switch_to_default_content()
嵌套frame的切换
若是frame里包着frame而你要的frame是后者,那么须要一层一层切换进去,切换方法四选一
driver.switch_to_frame("frame1") driver.switch_to_frame("frame2")
若是想回去上一个父frame,用driver.switch_to.parent_frame()
有时候点开一个连接就会弹出一个新窗口,若是要对其操做就要切换过去,方法和frame的切换差很少,但只接收window_handle(至关于窗口的名字)来进行切换。driver.switch_to_window("windowName")
切换前最好保存以前的handle和全部的handles以便于来回切换。
current_window = driver.current_window_handle # 获取当前窗口handle name all_windows = driver.window_handles # 获取全部窗口handle name # 若是window不是当前window,则切换到该window,即切换到新窗口 for window in all_windows: if window != current_window: driver.switch_to_window(window) #.... driver.switch_to_window(current_window) # 返回以前的窗口 driver.close() # 窗口的关闭用close()
经常使用的页面交互有点击,输入文本等。交互的原则是先定位,后交互,好比你F12找到了某个文本框或某个可点击项的标签,那就先定位到那,再用如下的交互方法
from selenium.webdriver.common.keys import Keys # 首先定位到某个文本框或某个可点击项(如超连接,按钮), element = driver.find_element_by_xpath('//a[text()="dark"]') element.send_keys("some text") # 往文本框输入文本 #element.send_keys("some text", Keys.ARROW_DOWN) 可使用 Keys 类来模拟输入方向键 element.clear() # 清空文本框 #element.click() 若是此元素可点击,可用click()方法
要注意的一点是,不是定位到就一定能交互,有时候目标会被网页弹出来的东西覆盖,致使没法交互,因此要确保页面干净无覆盖
selenium能够执行js,下拉滚动能够经过此实现,所以就算不懂js也能够记一些有用的js代码
#driver.execute_script('js_str') driver.execute_script('window.scrollTo(0,10000)') # 移动到指定坐标 driver.execute_script('window.scrollBy(0,10000)') # 相对当前坐标移动 driver.execute_script('window.scrollTo(0, document.body.scrollHeight)') # 相对当前坐标移动
如今很多web都都有使用ajax技术,即异步加载,有时候你要的东西都还没加载到你就去定位了,就会抛出异常。为了不此等血淋淋的惨状,必需要待其加载一段时间后再进行后面的操做。这里付一张不等待就获取page_source的后果
最粗暴的方法就是使用time.sleep(),这很笨,由于你还要设置合适的时间,而不一样网站加载的速度有异,容易形成时间的浪费。因此最好仍是使用selenium提供的两种等待方法
显式Wiats容许你设置一个加载时间的上限和一个条件,每隔0.5s就判断一下所设条件,条件成立就继续执行下面的代码,若是过了时间上限仍是没有成立,默认抛出NoSuchElementException 异常。这种相对智能的等待方法能最大化地节省时间,应该优先选择使用
selenium提供了多种expected_conditions(EC)来设置条件,可是要注意有定位时EC的方法接收的是定位信息的元组(locator_tuple)而不是两个参数,正确用法如 EC.presence_of_element_located((By.ID,"dark"))
这个条件检测是否有id='dark'的元素
selenium提供的EC有如下方法,意思如其名,这里注释一些易搞错的,选择使用
title_is(str)
title_contains(str)
presence_of_element_located(locator_tuple)
visibility_of_element_located(locator_tuple) # 判断某个元素是否可见
visibility_of(WebElement) # 同上,传参不一样
presence_of_all_elements_located(locator_tuple)
text_to_be_present_in_element(str) # 判断某个元素中的text是否包含了指定字符串
text_to_be_present_in_element_value(str) # 判断某个元素中的value属性是否包含了预期的字符串
frame_to_be_available_and_switch_to_it
invisibility_of_element_located(locator_tuple)
element_to_be_clickable(locator_tuple)
staleness_of(WebElement) # 等待某个元素从的移除
element_to_be_selected(WebElement)
element_located_to_be_selected(locator_tuple)
element_selection_state_to_be(WebElement)
element_located_selection_state_to_be(locator_tuple)
alert_is_present() # 判断页面上是否存在alert
使用上一般搭配try语句
from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait # 导入显式等待 from selenium.webdriver.support import expected_conditions as EC # 导入EC from selenium.common.exceptions import NoSuchElementException # WebDriverWait(driver,time).until(EC) 显式waits try: element = WebDriverWait(driver,10).until(EC.presence_of_element_located((By.ID,"myDynamicElement"))) except NoSuchElementException: #..... finally: driver.quit()
隐式等待是在尝试定位某个元素的时候,若是没能成功,就等待固定长度的时间,默认0秒。一旦设置了隐式等待时间,它的做用范围就是Webdriver对象实例的整个生命周期。driver.implicitly_wait(10)
这是用selenium几分钟弄出来的网易云音乐单曲评论爬虫,并且还模拟了评论翻页,还截了图。没提取信息,提取的时候能够用BeautifulSoup或正则提取,
from selenium import webdriver import time from selenium.common.exceptions import NoSuchElementException, TimeoutException from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait driver = webdriver.Chrome() driver.maximize_window() driver.get("http://music.163.com/#/song?id=31877470") driver.switch_to_frame("contentFrame") time.sleep(5) driver.execute_script('window.scrollTo(0, document.body.scrollHeight)') driver.save_screenshot('E:/python3/gg.png') # 截图 b = driver.find_element_by_xpath("//a[starts-with(@class,'zbtn znxt')]") b.click() try: WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH,"//a[@data-type='reply']"))) print(driver.page_source) except NoSuchElementException: print('OMG') finally: driver.quit()
短短二十行就能作到这种程度(并且很多仍是import的),足以见得selenium强大。若是要手动分析,你还要分析js加密算法,写上n倍的代码。二者相比起来selenium真的很吸引人,简直是懒人救星。你们权衡利弊按需选择吧