【Python3 爬虫学习笔记】动态渲染页面爬取 3 —— Selenium的使用 3

切换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)
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)

控制台的输出如下:

No Logo
<selenium.webdriver.remote.webelement.WebElement (session="fa0f3dcd003ff492c67172682612cfb7", element="0.05007953924776598-2")>
RUNOOB.COM

这里还是以前面演示动作链操作的网页为实例,首先通过switch_to.frame()方法切换到Frame里面,然后尝试获取父级Frame里的logo节点,如果找不到的话,就会抛出NoSuchElementException异常,异常被捕捉之后,就会输出No Logo。接下来,重新切换回父级Frame,然后再次重新获取节点,发现此时可以成功获取了。
所以,当页面中包含子Frame时,如果想获取子Frame中的节点,需要先调用switch_to.frame()方法切换到对应的Frame,然后再进行操作。

延时等待

在Selenium中,get()方法会在网页框架加载结束后结束执行,此时如果获取page_source,可能并不是浏览器完全加载完成的页面,如果某些页面有额外的Ajax请求,我们在网页源代码中也不一定能成功获取到。所以,这里需要延时等待一定时间,确保节点已经加载出来。
这里等待的方式有两种:一种是隐式等待,一种是显式等待。

隐式等待

当使用隐式等待执行测试的时候,如果Selenium没有再DOM中找到节点,将继续等待,超出设定时间后,则抛出找不到节点的异常。换句话说,当查找节点而节点并没有立即出现的时候,隐式等待将等待一段时间再查找DOM,默认的时间是0。示例如下:

from selenium import webdriver

browser = webdriver.Chrome()
browser.implicitly_wait(10)
browser.get('https://www.zhihu.com/explore')
input = browser.find_element_by_class_name('zu-top-add-question')
print(input)

这里使用了implicitly_wait()方法实现了隐式等待。

显式等待

隐式等待的效果其实并没有那么好,因为我们只规定了一个固定时间,而页面的加载时间会受到网络条件的影响。
显式等待方法,指定要查找的节点,然后指定一个最长等待时间。如果在规定时间内加载出来了这个节点,就返回查找的节点;如果到了规定时间依然没有加载出该节点,则抛出超时异常。示例如下:

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)

这里首先引入WebDriverWait这个对象,指定最长等待时间,然后调用它的until()方法,传入要等待条件expected_conditions。比如,这里传入了presence_of_element_located这个条件,代表节点出现的意思,其参数是节点的定位元组,也就是ID为q的节点搜索框。
这样可以做到的效果就是,在10秒内如果ID为q的节点(即搜索框)成功加载出来,就返回该节点;如果超过10秒还没有加载出来,就抛出异常。
对于按钮,可以更改一下等待条件,比如改为element_to_be_clickable,也就是可点击,所以查找按钮时查找CSS选择器为.btn-search的按钮,如果10秒内它是可点击的,也就是成功加载出来了,就返回这个按钮节点;如果超过10秒还不可点击,也就是没有加载出来,就抛出异常。
关于更多等待条件的参数及用法,可以参考官方文档:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.support.expected_conditions。

前进和后退

平常使用浏览器时都有前进和后退功能,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()

这里我们连续访问3个页面,然后调用back()方法回到第二个页面,接下来再调用forward()方法又可以前进第三个页面。

Cookies

使用Selenium,还可以方便地对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())

首先,我们访问了知乎。加载完成后,浏览器实际上已经生成Cookies了。接着,调用get_cookies()方法获取所有的Cookies。然后,我们添加一个Cookies,这里传入一个字典,有name、domain和value等内容。接下来,再次获取所有的Cookies。可以发现,结果就多了这一项新加的Cookie。最后,调用delete_all_cookies()方法删除所有的Cookies。再重新获取,发现结果就为空了。

[{'domain': '.zhihu.com', 'httpOnly': False, 'name': 'l_n_c', 'path': '/', 'secure': False, 'value': '1'}, {'domain': 'www.zhihu.com', 'expiry': 1540049555.999395, 'httpOnly': False, 'name': 'tgw_l7_route', 'path': '/', 'secure': False, 'value': '9553ebf607071b8b9dd310a140c349c5'}, {'domain': '.zhihu.com', 'expiry': 1540050459, 'httpOnly': False, 'name': '__utmb', 'path': '/', 'secure': False, 'value': '51854390.0.10.1540048660'}, {'domain': '.zhihu.com', 'expiry': 1634656655.999624, 'httpOnly': False, 'name': 'q_c1', 'path': '/', 'secure': False, 'value': '4a2ecf5be7aa4570a924d2f3e2452338|1540048654000|1540048654000'}]
[]

选项卡管理

在访问网页的时候,会开启一个个选项卡。在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')

控制台的输出如下:

['CDwindow-F0E440AC76BF055E65B5D9B645DFBCE6', 'CDwindow-74443144C7DA82B70F4D5D3B1141AA8D']

首先访问了百度,然后调用了execute_script()方法,这里传入window.open()这个JavaScript语句新开启一个选项卡。接下来,我们想切换到该选项卡。这里调用window_handles属性获取当前开启的所有选项卡,返回的是选项卡的代号列表。想要切换选项卡,只需要调用switch_to_window()方法即可,其中参数是选项卡的代号。这里我们将第二个选项卡代号传入,即跳转到第二个选项卡,接下来再第二个选项卡下打开一个新页面,然后切换回第一个选项卡重新调用switch_to_window()方法,再执行其他操作即可。

异常处理

在使用Selenium的过程中,难免会遇到一些异常,例如超时、节点未找到等错误,一旦出现此类错误,程序便不会继续运行了。这里我们可以使用try except语句来捕获各种异常。
为了防止程序遇到异常而中断,我们需要捕获这些异常,示例如下:

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()

这里我们使用try except来捕获各种异常。比如,我们对find_element_by_id()查找节点方法捕获NoSuchElementException异常,这样一旦出现这样的错误,就进行异常处理,程序也不会中断了。
控制台的输出如下:

No Element

关于更多的异常类,可以参考官方文档:http://selenium-python.readthedocs.io/api.html#module-selenium.common.exceptions 。

你可能感兴趣的:(学习笔记)