动态渲染网页爬取-selenium
Selenium 简介
Selenium是一个自动化测试工具,利用它可以驱动浏览器执行特定的操作例如点击、下拉等操作。同事它还能够获取浏览器当前呈现的页面的源代码,即可以做到可见可爬。这对于一些JavaScript渲染的页面我就就可以使用它进行爬取,而不用去分析后台接口参数。#应用:(以google浏览器为例))安装selenium并且将google驱动chromedirver.exe程序与python代码文件的放置在同一个目录中,即可使用selenium驱动google浏览器.以下为一个简单示例:
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 #声明浏览器对象(也可以是其他浏览器:火狐、IE等) browser = webdriver.Chrome() try: #访问页面 browser.get('https://www.baidu.com') input = browser.find_element_by_id('kw') input.send_keys('python') input.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.close() 结果(输出当前url,源代码,cookies) .............................................................................................省略 <script> if(bds.comm.supportis){ window.__restart_confirm_timeout=true; window.__confirm_timeout=8000; window.__disable_is_guide=true; window.__disable_swap_to_empty=true; } initPreload({ 'isui':true, 'index_form':"#form", 'index_kw':"#kw", 'result_form':"#form", 'result_kw':"#kw" }); </script> <script> if(navigator.cookieEnabled){ document.cookie="NOJS=;expires=Sat, 01 Jan 2000 00:00:00 GMT"; } </script> </body></html>
Selenium声明浏览器对象
from selenium import webdriver #声明谷歌浏览器对象 browser = webdriver.Chrome() #声明火狐浏览器对象 browser = webdriver.Firefox() browser = webdriver.Edge() browser = webdriver.PhantomJS() browser =webdriver.Safari()
Selenium访问页面
from selenium import webdriver browser = webdriver.Chrome() #访问淘宝网页面获取网页原代码 browser.get('https://www.taobao.com') #获取网页原代码 print(browser.page_source) #关闭浏览器 browser.close()
Selenium查找节点
1.单节点查找
单个节点查找find_element()方法
常见方法有:
- find_element_by_id()
- 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_css_selector()
或
find_element()传入两个参数查找方式By和值,例如:
find_element(By.ID,id)
*取以淘宝搜索框网页为例 <input id="q" name="q" aria-label="请输入搜索文字" accesskey="s" autofocus="autofocus" autocomplete="off" class="search-combobox-input" aria-haspopup="true" aria-combobox="list" role="combobox" x-webkit-grammar="builtin:translate" tabindex="0"> from selenium import webdriver browser = webdriver.Chrome() browser.get('https://www.taobao.com') #根据id获取淘宝搜索框 input_first = browser.find_element_by_id('q') #根据css选择器获取 input_second = browser.find_element_by_css_selector('#q') #根据xpath获取 input_third = browser.find_element_by_xpath('//*[@id="q"]') print(input_first,input_second,input_third) browser.close() 结果(三个结果一致) <selenium.webdriver.remote.webelement.WebElement (session="2c84a22fc9d5113f9b53256945f72454", element="0.9638255071470887-1")> <selenium.webdriver.remote.webelement.WebElement (session="2c84a22fc9d5113f9b53256945f72454", element="0.9638255071470887-1")> <selenium.webdriver.remote.webelement.WebElement (session="2c84a22fc9d5113f9b53256945f72454", element="0.9638255071470887-1")>
2.多节点查找
多个节点查找find_elements()方法
- 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_css_selector()
或
find_elements()传入两个参数查找方式By和值,例如:
find_element(By.ID,id)
*以淘宝导航栏为例 from selenium import webdriver browser = webdriver.Chrome() browser.get('https://www.taobao.com') lis = browser.find_elements_by_css_selector('.service-bd li') 或者以下方法 Liss = browser.find_elements(By.CSS_SELECTOR,’.server-bd li’)#结果一致 print(lis) browser.close() 结果 [<selenium.webdriver.remote.webelement.WebElement (session="89a7ea4bb337fc1f8976d6593615d13d", element="0.7879413394489616-1")>...<selenium.webdriver.remote.webelement.WebElement (session="89a7ea4bb337fc1f8976d6593615d13d", element="0.7879413394489616-16")>]
节点交互,常用的有以下几个:
- 输入文字用send_keys()方法
- 清空文字用clear()方法
- 点击按钮用click()方法
from selenium import webdriver import time browser = webdriver.Chrome() browser.get('https://www.taobao.com') #获取输入框 input = browser.find_element_by_id('q') #搜索框输入iphone,但是未点击搜索按钮所以不进行搜索 input.send_keys('iphone') time.sleep(1) #清空输入框 input.clear() input.send_keys('ipad') #获取搜索按钮 button = browser.find_element_by_class_name('btn-search') #点击按钮完成搜索任务 button.click() #关闭浏览器 browser.close()
动作链:例如鼠拖曳和键盘按键等操作就称之为动作链,它们没有特定的执行对象
*举例:实现一个节点的拖曳操作 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') #声明ActionChains对象 actions = ActionChains(browser) #action调用以下两个方法完成拖曳操作 actions.drag_and_drop(source,target) actions.perform() browser.close()
执行JavaScript:例如下拉进度条可以直接模拟运行JavaScript,执行execute_script()方法即可实现
from selenium import webdriver browser = webdriver.Chrome() browser.get('https://www.zhihu.com/explore') #将下拉条拉倒最底部 browser.execute_script('window.scrollTo(0,document.body.scrollHeight)') #弹出alert提示框 browser.execute_script('alert("To Bottom")') browser.close()
获取节点信息(包括属性,文本以及id位置标签名和大小)
*获取属性 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')) browser.close() 结果 <selenium.webdriver.remote.webelement.WebElement (session="52975bfa983727a2a7f26b9972c414a2", element="0.9714708708818114-1")> zu-top-link-logo *获取文本值 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) browser.close() 结果 提问
获取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') #获取id值 print(input.id) #获取位置 print(input.location) #获取标签名 print(input.tag_name) #获取大小 print(input.size) browser.close() 结果 0.8772617338808859-1 {'x': 760, 'y': 7} button {'height': 32, 'width': 66}
切换Frame:网页中有一种节点叫做iframe,也就是子Frame,相当于页面的子页面,结构和外部网页完全一致。Selenium默认打开后是在父级Frame里面操作,而此时如果页面中还有子Frame,则是不能够获取子Frame里面的节点的。则需要使用switch_to_.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) #通过switch_to.frame()切换到子页面Frame里面 browser.switch_to.frame('iframeResult') try: #获取子Frame里面的logo节点 logo = browser.find_element_by_class_name('logo') #若不存在打印No Logo except NoSuchElementException: print('No Logo') #通过switch_to_.parent_frame切回父级Frame browser.switch_to.parent_frame() #重新获取logo节点 logo = browser.find_element_by_class_name('logo') print(logo) print(logo.text) 结果 No Logo <selenium.webdriver.remote.webelement.WebElement (session="342ed5d025ac85c06d872fdf337edc82", element="0.12105089091907728-2")> RUNOOB.COM
延时等待:
selenium中get()方法会在网页加载结束后结束执行,此时如果要获取page_source,可能并不是浏览器完全加载完成的页面,如果某些页面有额外的Ajax请求,我们在网页源代码中不一定能成功获取,所以需要等待一定的时间从而确保页面加载出来,而等待又分为隐式等待和和显式等待。
- 隐式等待::当时用隐式等待执行测试的时候,若Selenium没有在DOM中找到节点,将继续等待,超出设定时间后,则会抛出找不到的节点的异常,即当查找节点而节点并没有立即出现的时候,隐式等待将等待一段时间在查找DOM,默认时间为0
- 显式等待:指定要查找的节点,然后指定一个最长的等待时间。若在规定的时间内加载出来这个节点,就返回查找的节点,若到了规定时间没有加载出来这个节点则会抛出超时异常。
隐式等待
from selenium import webdriver browser = webdriver.Chrome() #调用implicitly_wait()方法实现隐式等待 browser.implicitly_wait(10) browser.get('https://www.zhihu.com/explore') input = browser.find_element_by_class_name('zu-top-add-question') print(input) 结果 <selenium.webdriver.remote.webelement.WebElement (session="9bc5b8f1ae5203fd98654d854b8b70e6", element="0.6674161481100129-1")>
显式等待条件
等待条件 含义
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,可判断页面是否已经刷新
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') #创建WebDriverWait对象,指定最长等待时间 10秒 wait = WebDriverWait(browser,10) #调用until()方法传入等待条件(条件为id为q的节点出现10秒内是否出现) input = wait.until(EC.presence_of_element_located((By.ID, 'q'))) #查找CSS选择器为.btn-serch的按钮,若在10秒内是可点击的,则成功加载出来 button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,'.btn-search'))) print(input,button) browser.close() 结果 <selenium.webdriver.remote.webelement.WebElement (session="c8d488bc04ef5ad442cab51e8547dc34", element="0.8244517500943758-1")> <selenium.webdriver.remote.webelement.WebElement (session="c8d488bc04ef5ad442cab51e8547dc34", element="0.8244517500943758-2")>
前进和后退selenium
*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.python.org/')
browser.back()
time.sleep(1)
browser.forward()
browser.close()
Cookies
*使用selenium可以方便的对cookies进行获取、添加、删除等操作
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.zhihu.com/explore')
#获取所有cookies
print(browser.get_cookies())
#添加cookies
browser.add_cookie({'name':'name','domain':'www.zhihu.com','value':'germey'})
print(browser.get_cookies())
#删除所有cookies
browser.delete_all_cookies()
#重新获取结果为空
print(browser.get_cookies())
browser.close()
选项卡管理
*当我们在访问网页的时候会开启一个选项卡,可以使用selenuim对选项卡进行操作
import time
from selenium import webdriver
browser = webdriver.Chrome()
#访问百度网页
browser.get('https://www.baidu.com')
#开启一个新的选项卡
browser.execute_script('window.open()')
#调用window_handles属性获取当前开启的所有选项卡
print(browser.window_handles)
#调用switch_to_window()方法切换到第二个选项卡
browser.switch_to_window(browser.window_handles[1])
browser.get('https://www.taobao.com')
time.sleep(1)
#调用switch_to_window()方法切换到第一个选项卡
browser.switch_to_window(browser.window_handles[0])
browser.get('https://python.org')
结果
['CDwindow-E4ECA535D3501ED974B9B9E0AD36995B', 'CDwindow-C362F44E7078475E2676DD6C5DF455DF']
异常处理
*在使用selenium的过程中难免会遇到一些错误,一旦出现错误程序便不会在运行了,而我们可以使用try excep语句来捕获各种异常
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