百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Python的selenium实现等待某个元素加载完成后返回结果

bigegpt 2025-03-18 19:58 8 浏览

1. 介绍

1.1 介绍

福哥在使用selenium的时候遇到了一个问题,就是页面有些元素和数据是通过AJAX渲染的,而且采用的是异步加载的方式实现的AJAX功能,这样在selenium认为页面已经加载完成了的时候其实数据还没有渲染上,这个可愁坏福哥了!

经过研究发现selenium有两个功能就是可以实现福哥想要的效果,一个是WebDriverWait对象,另一个是implicitly_wait方法,它们都可以达到建立一个监视器,等待元素加载到页面上之后立即捕获并返回的目的。

另外福哥还发现使用time对象的sleep方法也可以实现这个效果,而且自由度非常高,特别适合处理复杂的情况。

这些技巧大家跟着福哥来一起学习一下吧~~

2. AJAX页面

福哥弄了一个AJAX异步延迟渲染的页面,保证正常情况下selenium绝对无法获得渲染后的内容,拿这个来做实验!

2.1 直接爬取

使用下面的代码直接爬取页面,很显然异步延迟的AJAX渲染的数据是拿不到的。

chrome.get("http://192.168.2.168/tfams/test.html")
print(chrome.find_element_by_css_selector("p#content-in-ajax").text)

3. WebDriverWait

使用WebDriverWait对象来实现等待元素加载完毕的监视是一个比较理想的方法,我们可以设置一个最长等待时间,然后通过EC对象的presence_of_element_located方法进行预期元素的查找尝试,如果查找成功那么WebDriverWait的until方法就会立即返回,否则的话WebDriverWait的until方法会在达到最长等待时间之前一直等待着,超过最长等待时间的时候就会抛出异常错误。

看完WebDriverWait的工作原理之后,福哥惊呼这不就是我们想要的东西吗?

3.1 安装

需要引入三个库,都是selenium.webdriver下面的库。

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

3.2 示例

这是一个使用WebDriverWait实现等待AJAX加载完毕的示例。

chrome.get("http://192.168.2.168/tfams/test.html")
try:
    WebDriverWait(chrome, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, "p#content-in-ajax h3")))
except Exception as e:
    doNothing = e
print(chrome.find_element_by_css_selector("p#content-in-ajax").text)

看!这下内容爬取到了哦~~

因为示例当中的p标签的内容来自AJAX,而内容是复合型的HTML结构,我们无法判断p标签是否为空,只能抓p标签下面的一个子元素h3作为加载完毕的标志,再去取整个p标签了!

4. implicitly_wait

使用implicitly_wait方法来实现等待元素加载完毕也还可以,在通过implicitly_wait设置了等待时间之后,每一次通过find_xxx方法查找元素的时候都会进行查找尝试,并且在最长等待时间之前查找成功就可以。

也就是说,我们在设置了implicitly_wait之后再去调用find_xxx方法去查找元素的时候,如果元素没有找到find_xxx并不会返回None而是反复进行查找尝试,在通过implicitly_wait设置的最长等待时间到达之前查找成功就会立即返回,超过了通过implicitly_wait设置的最长等待时间的时候就会抛出异常错误。

4.1 示例

这是一个使用implicitly_wait实现等待AJAX加载完毕的示例。

chrome.implicitly_wait(10)
chrome.get("http://192.168.2.168/tfams/test.html")
try:
    chrome.find_element_by_css_selector("p#content-in-ajax h3")
except Exception as e:
    doNothing = e
print(chrome.find_element_by_css_selector("p#content-in-ajax").text)

看!这样也可以爬取到哦~~

因为示例当中的p标签的内容来自AJAX,而内容是复合型的HTML结构,我们无法判断p标签是否为空,只能抓p标签下面的一个子元素h3作为加载完毕的标志,再去取整个p标签了!

5. time.sleep

最后一个是使用time对象的sleep方法进行人工延迟,具体实现方法是通过循环语句进行计时,并且在每次循环里手动检查结果是否完成,如果结果完成了就跳出。

网上说这是最蠢的方案,福哥并不认同这个观点。

在实际的项目当中,如果场景是AJAX程序处理完毕后会动态渲染出一个元素出来,这种情况当然可以使用WebDriverWait对象或者implicitly_wait方法进行查找。但是,假如场景是AJAX程序处理完毕后会动态删除一个元素,又或是改变一个元素的属性、样式,那么通过WebDriverWait对象或者implicitly_wait方法就不灵了。

不过,这种情况下使用time.sleep却可以解决,因为我们可以用最原始的方式,每次计时循环通过execute_script方法去检查元素是不是被删除了,又或是通过execute_script方法去检查元素的属性、样式是不是改变了,这样就可以解决问题了!

5.1 安装

使用time.sleep需要导入time库,这个是系统自带的库,不需要单独安装。

import time

5.2 示例1

这是一个使用time.sleep实现等待AJAX加载完毕的示例。

chrome.get("http://192.168.2.168/tfams/test.html")
waitSecs = 10
while waitSecs > 0:
    try:
        chrome.find_element_by_css_selector("p#content-in-ajax h3")
        break
    except Exception as e:
        doNothing = e
    waitSecs = waitSecs-1
    time.sleep(1)
print(chrome.find_element_by_css_selector("p#content-in-ajax").text)

代码有点复杂是不是?没有关系,下面福哥再来一个只有time.sleep可以干的事情的例子。

5.3 示例2

这是一个使用time.sleep实现等待AJAX加载完毕的示例,条件是不能预判AJAX加载的内容包含什么元素,也就是说我们不能再去判断p标签下面有没有h3标签了。

这下可怎么办呢?

chrome.get("http://192.168.2.168/tfams/test.html")
waitSecs = 10
while waitSecs > 0:
    isEmptyTagP = chrome.execute_script("return $.trim($('p#content-in-ajax').text()) == '' ? true : false;")
    if isEmptyTagP == False:
        break
    waitSecs = waitSecs-1
    time.sleep(1)
print(chrome.find_element_by_css_selector("p#content-in-ajax").text)

看到了吗?福哥自定义了一个逻辑,在当前页面执行JS脚本判断p标签下面是不是空的,如果不是空的就证明AJAX渲染完成了,这个过程完全不需要知道AJAX会加载什么内容出来都可以实现。

6. 总结

今天大家跟着福哥学会了在使用selenium抓取网页的时候,可以根据自己的情况在AJAX异步渲染的某个元素加载完成之后再返回结果,这样可以实现准确地判断那些异步加载数据的页面的加载完成时间,获得我们预期的结果。


https://m.tongfu.net/home/35/blog/513255.html

相关推荐

最全的MySQL总结,助你向阿里“开炮”(面试题+笔记+思维图)

前言作为一名编程人员,对MySQL一定不会陌生,尤其是互联网行业,对MySQL的使用是比较多的。对于求职者来说,MySQL又是面试中一定会问到的重点,很多人拥有大厂梦,却因为MySQL败下阵来。实际上...

Redis数据库从入门到精通(redis数据库设计)

目录一、常见的非关系型数据库NOSQL分类二、了解Redis三、Redis的单节点安装教程四、Redis的常用命令1、Help帮助命令2、SET命令3、过期命令4、查找键命令5、操作键命令6、GET命...

netcore 急速接入第三方登录,不看后悔

新年新气象,趁着新年的喜庆,肝了十来天,终于发了第一版,希望大家喜欢。如果有不喜欢看文字的童鞋,可以直接看下面的地址体验一下:https://oauthlogin.net/前言此次带来得这个小项目是...

精选 30 个 C++ 面试题(含解析)(c++面试题和答案汇总)

大家好,我是柠檬哥,专注编程知识分享。欢迎关注@程序员柠檬橙,编程路上不迷路,私信发送以下关键字获取编程资源:发送1024打包下载10个G编程资源学习资料发送001获取阿里大神LeetCode...

Oracle 12c系列(一)|多租户容器数据库

作者杨禹航出品沃趣技术Oracle12.1发布至今已有多年,但国内Oracle12C的用户并不多,随着12.2在去年的发布,选择安装Oracle12c的客户量明显增加,在接下来的几年中,Or...

flutter系列之:UI layout简介(flutter-ui-nice)

简介对于一个前端框架来说,除了各个组件之外,最重要的就是将这些组件进行连接的布局了。布局的英文名叫做layout,就是用来描述如何将组件进行摆放的一个约束。在flutter中,基本上所有的对象都是wi...

Flutter 分页功能表格控件(flutter 列表)

老孟导读:前2天有读者问到是否有带分页功能的表格控件,今天分页功能的表格控件详细解析来来。PaginatedDataTablePaginatedDataTable是一个带分页功能的DataTable,...

Flutter | 使用BottomNavigationBar快速构建底部导航

平时我们在使用app时经常会看到底部导航栏,而在flutter中它的实现也较为简单.需要用到的组件:BottomNavigationBar导航栏的主体BottomNavigationBarI...

Android中的数据库和本地存储在Flutter中是怎样实现的

如何使用SharedPreferences?在Android中,你可以使用SharedPreferencesAPI来存储少量的键值对。在Flutter中,使用Shared_Pref...

Flet,一个Flutter应用的实用Python库!

▼Flet:用Python轻松构建跨平台应用!在纷繁复杂的Python框架中,Flet宛如一缕清风,为开发者带来极致的跨平台应用开发体验。它用最简单的Python代码,帮你实现移动端、桌面端...

flutter系列之:做一个图像滤镜(flutter photo)

简介很多时候,我们需要一些特效功能,比如给图片做个滤镜什么的,如果是h5页面,那么我们可以很容易的通过css滤镜来实现这个功能。那么如果在flutter中,如果要实现这样的滤镜功能应该怎么处理呢?一起...

flutter软件开发笔记20-flutter web开发

flutterweb开发优势比较多,采用统一的语言,就能开发不同类型的软件,在web开发中,特别是后台式软件中,相比传统的html5开发,更高效,有点像c++编程的方式,把web设计出来了。一...

Flutter实战-请求封装(五)之设置抓包Proxy

用了两年的flutter,有了一些心得,不虚头巴脑,只求实战有用,以供学习或使用flutter的小伙伴参考,学习尚浅,如有不正确的地方还望各路大神指正,以免误人子弟,在此拜谢~(原创不易,转发请标注来...

为什么不在 Flutter 中使用全局变量来管理状态

我相信没有人用全局变量来管理Flutter应用程序的状态。毫无疑问,我们的Flutter应用程序需要状态管理包或Flutter的基本小部件(例如InheritedWidget或St...

Flutter 攻略(Dart基本数据类型,变量 整理 2)

代码运行从main方法开始voidmain(){print("hellodart");}变量与常量var声明变量未初始化变量为nullvarc;//未初始化print(c)...