动态渲染页面爬取

18 篇文章 0 订阅
11 篇文章 0 订阅

在之前,我们了解了 Ajax 的分析和抓取方式,这其实也是 JavaScript 动态渲染的页面的一种情形,通过直接分析 Ajax ,我们仍然可以借助 requests 或 urllib 来实现数据爬取。

不过,JavaScript 渲染的页面不止 Ajax 一种,为了解决这些问题,我们可以直接使用模拟浏览器运行的方式来实现。这样就可以做到在浏览器中看到是什么样,抓取到的源码就是什么样,也就是可见即可爬。这样我们就不用再去管网页内部的 JavaScript 用了什么算法渲染页面,不用管网页后台的 Ajax 接口到底有哪些参数。

Selenium 的使用

Selenium 是一个自动化测试工具,利用它可以驱动浏览器执行特定的动作,如点击、下拉等操作,同时还可以获取浏览器当前呈现的页面的源代码 ,做到可见即可爬。对于一些 JavaScript 动态渲染的页面来说,此种抓取方式非常有效。

准备工作

此处以 Chrome 为例来讲解 Selenium 的用法。在开始之前,请确保已经正确安装好了 Chrome 览器并配置好了 ChromeDriver(要和浏览器版本相匹配)。 另外,还需要正确安装好 Python 的 Selenium 库。

基本使用

首先来大体看一下 Selenium 有一些怎么样的功能。示例如下:

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

driver = webdriver.Chrome()

try:
    driver.get('https://www.baidu.com')
    driver.find_element_by_id('kw').send_keys('python')
    driver.find_element_by_id('kw').send_keys(Keys.ENTER)
    driver.implicitly_wait(10)
    driver.find_element_by_id('content_left')
    print(driver.current_url)
finally:
    print('运行结束')

运行代码后发现,会自动弹出一个 Chrome 浏览器。浏览器首先会跳转到百度,然后在搜索框中输入 python ,接着跳转到搜索结果页面,如下图:
在这里插入图片描述
而且,在搜索结果加载出来之后,控制台会输入当前的 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=cd74056900082e02&rsv_t=8733EHnEPYv6rv1oFX3M4Q4VzZGOIlqMYfTas7e4CerS4RszUwAbnKPK8F8&rqlang=cn&rsv_enter=1&rsv_dl=tb&rsv_sug3=6&rsv_sug2=0&rsv_btype=i&inputT=92&rsv_sug4=92

可以看到,我们得到的当前 URL 是浏览器中的真实内容。

所以说,如果用 Selenium 来驱动浏览器加载网页的话 就可以直接拿到 JavaScript 渲染的结果了。

下面来详细了解一下 Selenium 的用法。

声明浏览器对象

Selenium 支持非常多的浏览器,如Chrome、firefox、Edge等,还有 Android 等手机端的浏览器。此外,也支持无界面的浏览器 PhantomJS。

我们可以使用如下方式初始化:

from selenium import webdriver

driver = webdriver.Chrome()
driver = webdriver.Firefox()
driver = webdriver.Edge()
driver = webdriver.PhantomJS()
driver = webdriver.Safari()

这样就完成了浏览器对象的初始化并将其赋值为 driver 对象。接下来,我们就可以调用 driver 对象,让其执行各种动作以模拟浏览器操作。

访问页面

我们在这里使用 get() 方法来请求网页,参数传入链接 URL 即可。比如,这里用 get() 方法访问淘宝,然后打印出其源代码,代码如下:

from selenium import webdriver

driver = webdriver.Chrome()
driver.get('https://ww.taobao.com')
print(driver.page_source)

# 关闭页面
driver.close()

运行后发现,弹出了 Chrome 浏览器并且自动访问了淘宝,然后在控制台输出了淘宝页面的源代码。

通过这几行简单的代码,我们可以实现浏览器的驱动并 取网页源码,非常便捷。

查找节点

Selenium 可以驱动浏览器完成各种操作,比如填充表单、模拟点击等。如果我们想要完成向某个输入框输入文字的操作,我们首先要知道这个输入框在什么位置。Selenium 提供了一系列查找节点的方法,我们可以用这些方法来获取想要的节点,以便下一步执行一些动作或者提取信息。

单个节点

比如,想要从淘宝页面中提取搜索框这个节点,首先要观察它的源代码。
在这里插入图片描述
可以发现,搜索框的id是q,name也是q。此外,还有其他的一些属性,此时,我们就可以利用多种方式去获取到搜索框的位置。下面用代码实现一下:

from selenium import webdriver

driver = webdriver.Chrome()
driver.get('https://www.taobao.com')
driver.implicitly_wait(10)
input_first = driver.find_element_by_id('q')
input_second = driver.find_element_by_css_selector('#q')
input_third = driver.find_element_by_xpath('//*[@id="q"]')
print(input_first,input_second,input_third)
driver.close()

这里我们使用3种方式获取输入框,分别是根据id、css选择器和xpath获取,它们返回的结果完全一致。运行结果如下:

<selenium.webdriver.remote.webelement.WebElement (session="81e937bd833f62ed0bd8cce8893fa76b", element="466d3924-2778-4df9-a40f-e93ca3de7e47")> 
<selenium.webdriver.remote.webelement.WebElement (session="81e937bd833f62ed0bd8cce8893fa76b", element="466d3924-2778-4df9-a40f-e93ca3de7e47")> 
<selenium.webdriver.remote.webelement.WebElement (session="81e937bd833f62ed0bd8cce8893fa76b", element="466d3924-2778-4df9-a40f-e93ca3de7e47")>

可以看到,这三个节点都是WebElement 类型,是完全一致的。

此外,还有以下获取单个节点的方法:

find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector

另外,Selenium 还提供了通用方法 find_element() ,它需要传入两个参数:查找方式 By 和值。实际上,它就是 find_element_by_id() 这种方法的通用函数版本,比如 find_element_by_id(id) 就等价于 find_element(By.ID, id),二者得到的结果完全一致。代码示例如下:

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get('https://www.taobao.com')
driver.implicitly_wait(10)
input_first = driver.find_element(By.ID,'q')
print(input_first)
driver.close()

实际上,这种查找方式的功能和上面的查找函数完全一致,不过参数更加灵活。

多个节点

如果查找的目标在网页中只有一个,那么完全可以用 find_element() 方法。但如果有多个节点,再用 find_e lement() 方法查找,就只能得到第一个节点了。如果要查找所有满足条件的节点, 需要用 find_elements() 这样的方法。注意,在这个方法的名称中, element 多了一个 s,注意区分。

比如,要查找淘宝左侧导航条的所有条目。
在这里插入图片描述
代码如下:

from selenium import webdriver

driver = webdriver.Chrome()
driver.get('https://ww.taobao.com')
lis = driver.get_elements_by_class_name('J_Cat')
print(lis)

运行结果如下:

[<selenium.webdriver.remote.webelement.WebElement (session="4162f334ab2d3978937e91dbae4ac7e7", element="c919812b-92ee-436c-a801-cc1ba47e4380")>, <selenium.webdriver.remote.webelement.WebElement (session="4162f334ab2d3978937e91dbae4ac7e7", element="f9de96f1-c684-4843-91ff-f6bbbb826147")>, <selenium.webdriver.remote.webelement.WebElement (session="4162f334ab2d3978937e91dbae4ac7e7", element="be8b8d40-1108-45be-a894-246bc0690e65")>, <selenium.webdriver.remote.webelement.WebElement (session="4162f334ab2d3978937e91dbae4ac7e7", element="40c06367-2b66-40ab-873e-5b60fd512f14")>, <selenium.webdriver.remote.webelement.WebElement (session="4162f334ab2d3978937e91dbae4ac7e7", element="45c51c9d-e299-4d15-acf5-1483a4d11136")>, <selenium.webdriver.remote.webelement.WebElement (session="4162f334ab2d3978937e91dbae4ac7e7", element="b2f24cf5-4280-48b1-ab6b-853bdef6dd14")>, <selenium.webdriver.remote.webelement.WebElement (session="4162f334ab2d3978937e91dbae4ac7e7", element="7bd6be3f-30a0-4420-885d-0e70fd9bcbef")>]

这里简化了输出结果,中间部分省略。

可以看到,得到的结果变成了列表类型,列表中的每一个元素都是 WebElement 类型。

当然,我们也可以直接用 find_elements() 方法来选择,这时可以这样写:

lis = driver.find_elements(By.CLASS_NAME,'J_Cat')

结果是完全一致的。

节点交互

Selenium 可以驱动浏览器来执行一些操作,也就是说可以让浏览器模拟执行一些动作。比较常见的用法有:输入文字时用 send_keys() 方法,清空文字时用 clear() 方法,点击按钮时用 click() 方法。示例如下:

from selenium import webdriver
import time

driver = webdriver.Chrome()
driver.get('https://www.taobao.com')
input = driver.find_element_by_id('q')
input.send_keys('iphone')
time.sleep(2)
input.clear()
input.send_keys('ipad')
button = driver.find_element_by_class_name('btn-search')
button.click()

这里首先驱动浏览器打开淘宝,然后用 find_element_by_id() 方法获取输入框,然后用 send_keys() 方法输入 iphone 文字,等待两秒后用 clear() 方法获取搜索按钮,最后调用 click() 方法完成搜索动作。

通过上面的方法,我们就完成了一些常见节点的动作操作,更多的操作可以参见官方文档的交互动作介绍:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.remote.webelement。

动作链

在上面的实例中,一些交互动作都是针对某个节点执行的。比如,对于输入框,我们就调用它的输入文字和清空文字的方法;对于按钮,我们就调用它的点击方法。其实还有一些操作,它们没有特定的执行对象,比如鼠标拖拽、键盘按键等,这些动作用另一种方式执行,那就是行为链。

比如,现在实现一个节点的拖拽操作,将某个节点从一处拖拽到另外一处,可以这样实现:

from selenium import webdriver
from selenium.webdriver import ActionChains

driver = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
driver.get(url)
driver.switch_to.frame('iframeResult')
source = driver.find_element_by_css_selector('#draggable')
target = driver.find_element_by_css_selector('#droppable')
actions = ActionChains(driver)
actions.drag_and_drop(source,target)
actions.perform()

首先,打开网页中的一个拖拽实例,然后依次选中要拖拽的节点和目标节点,接着声明行为链对象并将其赋值为 actions ,然后通过调用 actions 变量的 drag_and_drop() 方法,最后调用 perform() 方法执行动作,此时就完成了拖拽操作。如下图:
在这里插入图片描述

在这里插入图片描述

执行 JavaScript

对于某些操作,Selenium API 并没有提供。比如,下拉进度条,它可以直接模拟运行 JavaScript,此时使用 execute_script() 方法即可实现,代码如下:

from selenium import webdriver

driver = webdriver.Chrome()
driver.get('https://www.zhihu.com/explore')
driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
driver.execute_script('alert("To Buttom")')

这里就利用 execute_script() 方法将进度条下拉到最底部,然后弹出 alert 提示框。

有了这个方法,基本上 API 没有提供的所有功能都可以用执行 JavaScript 的方式来实现了。

获取节点信息

前面说过,通过 page_source 属性可以获取页面的源代码,接着就可以使用解析库(如正则表达式,Beautiful Soup、Xpath等)来提取信息了。

不过既然 selenium 已经提供了选择节点的方法,返回的是 WebElement 类型,那么它也有相关的方法和属性来直接提取节点信息,如属性、文本等。这样的话我们就不用通过解析源代码来提取信息了,非常方便。

获取属性

我们可以使用 get_attribute() 方法来获取节点的属性,但是前提是先选中这个节点,示例如下:

from selenium import webdrive
from selenium.webdriver import ActionChains

driver = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
driver.get(url)
logo = driver.find_element_by_id('special')
print(logo)
print(logo.get_attribute('class'))

运行之后,程序便会驱动浏览器打开知乎页面,然后获取id值为special的节点,最后打印出它的class。

控制台的输出结果为:

<selenium.webdriver.remote.webelement.WebElement (session="5852f7289eb2c920a8b2404bd5b61260", element="ed8b4406-35ff-45eb-85bf-761606dca5a4")>
ExploreHomePage-ContentSection ExploreHomePage-section

通过 get_attribute() 方法,然后传入想要获取的属性名,就可以得到它的值了。

获取文本值

每一个 WebElement 节点都有 text 属性,直接调用这个属性就可以获取到节点内部的文本信息了,这相当于 Beautiful Soup 的 get_text() 方法,示例如下:

from selenium import webdriver

driver = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
driver.get(url)
input = driver.find_element_by_class_name('ExploreHomePage-ContentSection-header')
print(input.text)

在这里,我们获取“最新专题”这个节点,然后将其文本值打印出来。

输出结果为:

最新专题
获取id、位置、标签名和大小

另外, WebElement 节点还有一些其他属性,比如 id 属性可以获取节点 id(没有id会自动生成),location 属性可以获取该节点在页面中的相对位置, tag_name 属性可以获取标签名称, size 属性可以获取节点的大小,也就是宽高,这些属性有时候还是很有用的。示例如下:

from selenium import webdriver

driver = webdriver.Chrome()
url = 'https://www.zhihu.com/explore'
driver.get(url)
input = driver.find_element_by_class_name('ExploreHomePage-ContentSection-header')
print(input.id)
print(input.loaction)
print(input.tag_name)
print(input.size)

运行结果如下:

b3b2996c-005e-4eef-8f0b-aa3cb8537529
{'x': 16, 'y': 84}
div
{'height': 36, 'width': 1000}
切换 Frame

我们知道网页中有一种节点叫作 iframe ,也就是子 Frame ,相当于页面的子页面,它的结构和外部网页的结构完全一致。Selenium 打开页面后,它默认是在父级 Frame 里面操作,而此时如果页面中还有子 Frame ,它是不能获取到子 Frame 里面的节点的。这时就需要使用 switch_to.frame() 方法来切换 Frame。示例如下:

import time
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

driver = webdriver.Chrome()
url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
driver.get(url)
driver.switch_to.frame('iframeResult')
try:
    logo = driver.find_element_by_class_name('logo')
except NoSuchElementException:
    print('NO LOGO')
driver.switch_to.parent_frame()
logo = driver.find_element_by_class_name('logo')
print(logo)
print(logo.text)

运行结果如下:

NO LOGO
<selenium.webdriver.remote.webelement.WebElement (session="d5473ca19a98e182b55101d1c4725a2b", element="89420a7a-c3b9-4cbe-b7d8-5036fd6e04ee")>
RUNOOB.COM

这里还是以前面演示行为链操作的网页为例,首先通过 switch_to.frame() 方法切换到子 Frame 里面,然后尝试获取父级 Frame 里的 logo 节点(这是不能找到的),找不到就会抛出 NoSuchElementException 异常,捕获异常后就会输出 NO LOGO。接下来,通过 switch_to.parent_frame() 切换回父级 Frame,然后再次获取节点,此时,可以成功获取。

所以,当页面中包含子 Frame 时,如果想获取子 Frame 中的节点,需要先调用 switch_to.frame() 方法进行相应的切换,然后再进行操作。

延时等待

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

这里等待的方式有三种,第一种是强制等待,第二种是隐式等待,第三种是显示等待。

强制等待

利用 Python 自带的 time 模块进行强制时间等待,不管什么情况都会进行等待。示例如下:

import time
from selenium import webdriver

driver = webdriver.Chrome()
time.sleep(5)
driver.get('https://www.taobao.com')
隐式等待

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

from selenium import webdriver

driver = webdriver.Chrome()
driver.get('https://www.zhihu.com/explore')
driver.implicitly_wait(10)
input = driver.find_element_by_class_name('input')
print(input.get_attribute('placeholder'))

这里我们用 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

driver = webdriver.Chrome()
driver.get('https://www.taobao.com')
wait = WebDriverWait(driver, 10)
input = wait.until(EC.presence_of_element_located((By.ID,'q')))
button = WebDriverWait(driver, 10).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 秒还不可点击,也就是没有加载出来,就抛出异常。

运行代码,在网速较佳的情况下是可以成功加载出来的。输出如下:

<selenium.webdriver.remote.webelement.WebElement (session="eb19f3f58aad1c6b50366e3135e0165c", element="f52b4bd2-57d5-4323-a282-2654a2c73dc3")> <selenium.webdriver.remote.webelement.WebElement (session="eb19f3f58aad1c6b50366e3135e0165c", element="394f1c5b-96b2-4ebc-a56c-11fdcfa4d97c")>

关于等待条件,其实还有很多,这里列出几个常用的条件:

presence_of_element_located         #节点加载出来,传入定位元组,如(By.ID, 'p')
visibility_of_element_located       #节点可见,传入定位元组
presence_of_all_element_located     #所有节点加载出来
element_to_be_clickable             #节点可点击
前进和后退

平常使用浏览器时都会有前进和后退功能,Selenium 也可以完成这个操作,使用 back() 方法后退,使用 forward() 方法前进。示例如下:

import time
from selenium import webdriver

driver = webdriver.Chrome()
driver.get('https://www.taobao.com')
driver.get('https://www.baidu.com')
driver.get('https://www.python.org')
driver.back()
time.sleep(3)
driver.forward()
driver.close()

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

Cookies

我们也可以通过 Selenium 对 Cookies 进行操作,例如获取、添加、删除 Cookies 等。示例如下:

from selenium import webdriver

driver = webdriver.Chrome()
driver = webdriver.get('https://www.zhihu.com/explore')
print(driver.get_cookies())
driver.add_cookie({'name':'name','domain':'www.zhihu.com','value':'germey'})
print(driver.get_cookies())
driver.delete_all_cookies()
print(driver.get_cookies())

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

[{'domain': 'www.zhihu.com', 'httpOnly': False, 'name': 'KLBRSID', 'path': '/', 'secure': False, 'value': 'cdfcc1d45d024a211bb7144f66bda2cf|1619697020|1619697019'}, {'domain': '.zhihu.com', 'expiry': 1651233021, 'httpOnly': 
False, 'name': 'Hm_lvt_98beee57fd2ef70ccdd5ca52b9740c49', 'path': '/', 'secure': False, 'value': '1619697021'}, 
{'domain': '.zhihu.com', 'httpOnly': False, 'name': 'Hm_lpvt_98beee57fd2ef70ccdd5ca52b9740c49', 'path': '/', 'secure': False, 'value': '1619697021'}, {'domain': '.zhihu.com', 'expiry': 1714305019, 'httpOnly': False, 'name': 
'd_c0', 'path': '/', 'secure': False, 'value': '"AJBdSHZxBxOPTk1PCJg-4ZU2sMgEyeWygio=|1619697019"'}, {'domain': 
'.zhihu.com', 'httpOnly': False, 'name': '_xsrf', 'path': '/', 'secure': False, 'value': '8f73e20b-9163-4405-b542-44fa03cc732a'}, {'domain': '.zhihu.com', 'expiry': 1682769019, 'httpOnly': False, 'name': '_zap', 'path': '/', 'secure': False, 'value': '828388a0-6430-4501-90b7-71811f11deba'}]
[{'domain': '.www.zhihu.com', 'httpOnly': False, 'name': 'name', 'path': '/', 'secure': True, 'value': 'germey'}, {'domain': 'www.zhihu.com', 'httpOnly': False, 'name': 'KLBRSID', 'path': '/', 'secure': False, 'value': 'cdfcc1d45d024a211bb7144f66bda2cf|1619697020|1619697019'}, {'domain': '.zhihu.com', 'expiry': 1651233021, 'httpOnly': False, 'name': 'Hm_lvt_98beee57fd2ef70ccdd5ca52b9740c49', 'path': '/', 'secure': False, 'value': '1619697021'}, {'domain': '.zhihu.com', 'httpOnly': False, 'name': 'Hm_lpvt_98beee57fd2ef70ccdd5ca52b9740c49', 'path': '/', 'secure': False, 'value': '1619697021'}, {'domain': '.zhihu.com', 'expiry': 1714305019, 'httpOnly': False, 'name': 'd_c0', 'path': '/', 'secure': False, 'value': '"AJBdSHZxBxOPTk1PCJg-4ZU2sMgEyeWygio=|1619697019"'}, {'domain': 'www.zhihu.com', 'httpOnly': False, 'name': 'SESSIONID', 'path': '/', 'secure': False, 'value': '4VAxkSEep88bTts7VTjg14CFrClAsxBlH1sveC5cJLw'}, {'domain': '.zhihu.com', 'httpOnly': False, 'name': '_xsrf', 'path': '/', 'secure': False, 'value': '8f73e20b-9163-4405-b542-44fa03cc732a'}, {'domain': '.zhihu.com', 'expiry': 1682769019, 'httpOnly': False, 'name': '_zap', 'path': '/', 'secure': False, 'value': '828388a0-6430-4501-90b7-71811f11deba'}] 
[]

其中,get_cookies() 方法是获取所有的cookie,get_cookie(name) 是根据 cookie 的name 获取 cookie 。delete_cookie(‘key’) 删除某个cookie, delete_all_cookies() 删除所有 cookies。

选项卡管理(多页面)

在访问网页的时候,会开启一个个选项卡。在 Selenium 中,我们也可以对选项卡进行操作。示例如下:

import time
from selenium import webdriver

driver = webdriver.get('https://www.baidu.com')
driver.execute_script('window.open('https://www.taobao.com')')
print(driver.window_handles)
driver.switch_to_window('driver.window_handles[1]')
time.sleep(2)
driver.switch_to_window('driver.window_handles[0]')

控制台的输出为:

['CDwindow-D67781D6F0868F0DC81C44B7CD4EB67B', 'CDwindow-58DD3C38736C2028D2ABC8C347370703']

在这里,我们使用 execute_script() 方法,这里传入 window.open() 这个 JavaScript 语句打开一个新窗口。然后调用 window_handles 属性获取当前开启的所有的选项卡,返回的是选项卡的代号列表。如果想切换选项卡,只需要调用 switch_to_window() 方法即可,其参数为选项卡的代号。

异常处理

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

首先,演示一下节点未找到的异常,示例如下:

from selenium import webdriver

driver = webdriver.Chrome()
driver.get('https://www.baidu.com')
driver.find_element_by_id('hello')

这里首先打开百度页面,然后尝试选择一个不存在的节点,此时就会遇到异常。运行后输出如下:

selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element:

可以看到,这里抛出了 NoSuchElementException 异常,这通常是节点找不到的异常。为了防止程序遇到异常而中断,我们需要捕获这些异常,示例如下:

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException

driver = webdriver.Chrome()
driver.get('https://www.baidu.com')
try:
    driver.find_element_by_id('hello')
except NoSuchElementException as e:
    print('No Element')
    print(e)
finally:
    driver.close()

这里我们使用 try except 来捕获异常。这样一旦出现错误,就进行异常处理,程序也不会中断了。

使用 Selenium 爬取淘宝商品

该案例写在另一篇博客当中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值