当前位置: 首页 > 工具软件 > Time-Elements > 使用案例 >

selenium 元素定位 增加超时timeout设置

白宏义
2023-12-01

我就奇怪怎么分割线以下那段代码时灵时不灵,原来是我自己修改的时候,思路弄错了。
涉及到try-return-except结构中的一些功能效果。
废话不多说,先上修改后的代码:

def safe_get_element(driver,by,element_num,timeout=2):
	"""
	传参时:
	1,driver参数为浏览器驱动所在变量名,下方return部份不需要修改。
	
	2,by参数和element_num参数参照driver.find_element("","")的写法,简略版如下,详细版请参照https://blog.csdn.net/qq_32897143/article/details/80383502
	2.1,by_id                -> find_element("id","")
	2.2,by_xpath          -> find_element("xpath","")
	2.3,by_link_text      -> find_element("link text","")
	2.4,by_partial_text  -> find_element("partial link text","")
	2.5,by_name          -> find_element("name","")
	2.6,by_tag_name    -> find_element("tag name","")
	2.7,by_class_name  -> find_element("class name","")
	2.8,by_css_selector -> find_element("css selector","")
	感谢CSDN博客ID为“我的猪很厉害的”的相关分享。
	
	3,timeout参数默认为5,以秒为单位
	
	4,将会返回一个元素,
	4.1,后续操作与driver.find_element("id","kw").send_keys('python')等一样,
	4.2,参考:safe_get_element(driver=amzjp,by='id',element_num='drrGenerateReportButton').click()
	"""
	import time
	start_time = time.time()
	print('开始时间为:{0:F}'.format(start_time))
	while True:
		try:
			print('开始定位元素,当前时间为:{0:F}'.format(time.time()))
			element_result=driver.find_element(by,element_num)
			return element_result
		except:
			if time.time() - start_time >= timeout:
				print('定位元素超时,当前时间为:{0:F}'.format(time.time()))
				return False
			else:
				time.sleep(0.2)
				print('正在定位元素,当前时间为:{0:F}'.format(time.time()))



def safe_get_elements(driver,by,element_num,timeout=2):
	"""
	该自定义函数会返回一个由元素组成的列表,寻找所需要的元素时,请参照列表的方式取出元素。
	传参时:
	1,driver参数为浏览器驱动所在变量名,下方return部份不需要修改。
	
	2,by参数和element_num参数参照driver.find_element("","")的写法,简略版如下,详细版请参照https://blog.csdn.net/qq_32897143/article/details/80383502
	2.1,by_id                -> find_elements("id","")
	2.2,by_xpath          -> find_elements("xpath","")
	2.3,by_link_text      -> find_elements("link text","")
	2.4,by_partial_text  -> find_elements("partial link text","")
	2.5,by_name          -> find_elements("name","")
	2.6,by_tag_name    -> find_elements("tag name","")
	2.7,by_class_name  -> find_elements("class name","")
	2.8,by_css_selector -> find_elements("css selector","")
	感谢CSDN博客ID为“我的猪很厉害的”的相关分享。
	
	3,timeout参数默认为5,以秒为单位
	
	4,将会返回一个元素,
	4.1,后续操作与driver.find_elements("id","kw")等一样,例:driver.find_elements("css selector",".mnav")[6].click()
	4.1.1,class一般是用.标记
	4.1.2,id一般是用#标记
	4.2,参考:safe_get_elements(driver=amzjp,by='id',element_num='drrGenerateReportButton')
	"""
	import time
	start_time = time.time()
	print('开始时间为:{0:F}'.format(start_time))
	while True:
		try:
			print('开始定位元素,当前时间为:{0:F}'.format(time.time()))
			element_result_list=driver.find_elements(by,element_num)
			return element_result_list
		except:
			if time.time() - start_time >= timeout:
				print('定位元素超时,当前时间为:{0:F}'.format(time.time()))
				return False
			else:
				time.sleep(0.2)
				print('正在定位元素,当前时间为:{0:F}'.format(time.time()))

以上为修改后的代码,目前timeout功能可以正常运作了。

区别在于:
原版代码中我图省事,直接把find_element放在了return后面,这相当于return了一个“任务”,而不是return一个“结果”。
新版代码中,我把find_element放在了try的后面,而放在return的前面,并且使用了一个变量,对find_element的结果进行接收,而return则只返回已经被变量接收的元素这一“结果”,而不再是find_element这个“过程”。
所以就能运作成功了。

如果感兴趣原版本(错误版本)的话,可以继续往下看。
如果只是找个方法解决一下元素定位时间过久,或者在定位不到元素的时候也不想让程序报错退出,看到这里就可以了。

PS:再提醒一句,修正后的代码,如果找不到元素,会返回False哦~
如果希望继续报错的话,把函数中的“return False”改成“raise Exception(‘没有找到元素’)”就好~
以上~
感谢观看~
m(_ _)m

~~~~~~~以上为2020-09-07新增内容,以下为原来的文章~~~~~~~~

这其实算是我上课之后的收获吧,听了康神的爬虫课,get了这么个技能。
这里厚颜无耻地链上康神的博客哈~康神的CSDN博客地址

实际上我在使用链式编程解决“将日常工作自动化”的需求时发现,selenium包里面的元素定位(selenium原装的元素定位方法,参照博文《史上最全!Selenium元素定位的30种方式》),偶尔会出现卡在那里不动的情况,而且如果页面不存在需要定位的元素时,卡顿往往会超过1分钟,这就很难熬了。

结合康神上课时给出的代码,稍加改良,就得出来下面这两个safe_get元素的自定义函数了。
其实不难看出,这两个自定义函数,对应的分别是find_element_by和find_elements_by,获得的也是一个是元素,一个是由元素组成的列表。
效果差不多,但加上了timeout(默认为2秒)。

8种对应写法,来源也在函数说明里写上了。

上代码:

def safe_get_element(driver,by,element_num,timeout=2):
	"""
	传参时:
	1,driver参数为浏览器驱动所在变量名,下方return部份不需要修改。
	
	2,by参数和element_num参数参照driver.find_element("","")的写法,简略版如下,详细版请参照https://blog.csdn.net/qq_32897143/article/details/80383502
	2.1,by_id                -> find_element("id","")
	2.2,by_xpath          -> find_element("xpath","")
	2.3,by_link_text      -> find_element("link text","")
	2.4,by_partial_text  -> find_element("partial link text","")
	2.5,by_name          -> find_element("name","")
	2.6,by_tag_name    -> find_element("tag name","")
	2.7,by_class_name  -> find_element("class name","")
	2.8,by_css_selector -> find_element("css selector","")
	感谢CSDN博客ID为“我的猪很厉害的”的相关分享。
	
	3,timeout参数默认为5,以秒为单位
	
	4,将会返回一个元素,
	4.1,后续操作与driver.find_element("id","kw").send_keys('python')等一样,
	4.2,参考:safe_get_element(driver=amzjp,by='id',element_num='drrGenerateReportButton').click()
	"""
	import time
	start_time = time.time()
	print('开始时间为:{0:F}'.format(start_time))
	while True:
		try:
			print('开始定位元素,当前时间为:{0:F}'.format(time.time()))
			return driver.find_element(by,element_num)
		except:
			if time.time() - start_time >= timeout:
				raise Exception('没有找到元素')
				print('定位元素超时,当前时间为:{0:F}'.format(time.time()))
			else:
				time.sleep(0.2)
				print('正在定位元素,当前时间为:{0:F}'.format(time.time()))



def safe_get_elements(driver,by,element_num,timeout=2):
	"""
	该自定义函数会返回一个由元素组成的列表,寻找所需要的元素时,请参照列表的方式取出元素。
	传参时:
	1,driver参数为浏览器驱动所在变量名,下方return部份不需要修改。
	
	2,by参数和element_num参数参照driver.find_element("","")的写法,简略版如下,详细版请参照https://blog.csdn.net/qq_32897143/article/details/80383502
	2.1,by_id                -> find_elements("id","")
	2.2,by_xpath          -> find_elements("xpath","")
	2.3,by_link_text      -> find_elements("link text","")
	2.4,by_partial_text  -> find_elements("partial link text","")
	2.5,by_name          -> find_elements("name","")
	2.6,by_tag_name    -> find_elements("tag name","")
	2.7,by_class_name  -> find_elements("class name","")
	2.8,by_css_selector -> find_elements("css selector","")
	感谢CSDN博客ID为“我的猪很厉害的”的相关分享。
	
	3,timeout参数默认为5,以秒为单位
	
	4,将会返回一个元素,
	4.1,后续操作与driver.find_elements("id","kw")等一样,例:driver.find_elements("css selector",".mnav")[6].click()
	4.1.1,class一般是用.标记
	4.1.2,id一般是用#标记
	4.2,参考:safe_get_elements(driver=amzjp,by='id',element_num='drrGenerateReportButton')
	"""
	import time
	start_time = time.time()
	print('开始时间为:{0:F}'.format(start_time))
	while True:
		try:
			print('开始定位元素,当前时间为:{0:F}'.format(time.time()))
			return driver.find_elements(by,element_num)
		except:
			if time.time() - start_time >= timeout:
				raise Exception('没有找到元素')
				print('定位元素超时,当前时间为:{0:F}'.format(time.time()))
			else:
				time.sleep(0.2)
				print('正在定位元素,当前时间为:{0:F}'.format(time.time()))

后续其实也碰上了一点问题,就是没办法写成像find_element那样的链式定位:driver.find_element_by_id(‘123’).find_element_by_id(‘456’).click()
但可以这样使用:
driver=webdriver(r’我是浏览器驱动绝对路径’)
driver.get(‘我是一个网址’)
element_big=safe_get_element(driver=driver , 别的参数)
element_in_big=safe_get_element(driver=element_big , 别的参数).click()

当然,如果excel嵌套用得6,也可以尝试直接把element_big那一段写入到element_in_big的driver参数里。。
只不过这样的话你这一行代码会很长就是了。。

在此再次感谢康神提供思路~
康神的CSDN博客地址

#~~~~~~~我是分割线,以下为200828更新内容~~~~~~~~

更新一个版本,引入了selenium的NoSuchElementException块。
修改了except部份,使得程序即便无法定位到元素,也不会因为报错导致整个程序中止运行,而是返回了一个False。

def safe_get_element(driver,by,element_num,timeout=2):
	"""
	传参时:
	1,driver参数为浏览器驱动所在变量名,下方return部份不需要修改。
	
	2,by参数和element_num参数参照driver.find_element("","")的写法,简略版如下,详细版请参照https://blog.csdn.net/qq_32897143/article/details/80383502
	2.1,by_id                -> find_element("id","")
	2.2,by_xpath          -> find_element("xpath","")
	2.3,by_link_text      -> find_element("link text","")
	2.4,by_partial_text  -> find_element("partial link text","")
	2.5,by_name          -> find_element("name","")
	2.6,by_tag_name    -> find_element("tag name","")
	2.7,by_class_name  -> find_element("class name","")
	2.8,by_css_selector -> find_element("css selector","")
	感谢CSDN博客ID为“我的猪很厉害的”的相关分享。
	
	3,timeout参数默认为5,以秒为单位
	
	4,将会返回一个元素,
	4.1,后续操作与driver.find_element("id","kw").send_keys('python')等一样,
	4.2,参考:safe_get_element(driver=amzjp,by='id',element_num='drrGenerateReportButton').click()
	"""
	from selenium.common.exceptions import NoSuchElementException;import time;
	start_time = time.time()
	print('开始时间为:{0:F}'.format(start_time))
	while True:
		try:
			print('开始定位元素,当前时间为:{0:F}'.format(time.time()))
			return driver.find_element(by,element_num)
		except NoSuchElementException as e:
			if time.time() - start_time >= timeout:
				#打印异常信息
				print(e,'判断结束,没有找到该元素,判断耗时:{}'.format(time.time()-start_time))
				#发生了NoSuchElementException异常,说明页面中未找到该元素,返回False
				return False
			else:
				time.sleep(0.2)
				print('正在定位元素,当前时间为:{0:F}'.format(time.time()))

各位看官请按照实际需要选择使用哈~

 类似资料: