在日常的网站里,前端开发人员会把一些选项封装成一个列表,设置为隐藏属性,这就是隐藏式列表菜单。
以著名的日本船公司ONE为例,当打开官网后,在 “Origin” 输入SHEKOU后,会自动弹出相对应的详细名,在 “Network" 中,可以看到相关的 Port Code 以及名字,这就是列表的隐藏菜单,通过API 动态生成的。因此这个隐藏菜单是封装在后台服务器的, 如下图1。 但其相对应的功能以及应用范围,例如sls_ofc 等, 都可以通过Json() 的方法用Spider 去提取,这里就不详细讲解怎样去通过Spider爬取, 如下图2 。
下面将会详细讲解 隐藏式列表菜单的处理,当弹出警告提示框时怎样处理,以及如何实现不同窗口的数据转换。
相关的测试视频 请看 https://weibo.com/2203755810, 为了演示每一步的过程、变化,把sleep() 调慢了。
当登陆官网后,如果首先执行对 " Origin" & " Destination" 填充,会收到元素不存在的报错信息。通过再三较对元素定位,确定没有错,但为什么会出现报错呢? 再次观察该元素的HTML结构,才发现,这 " SCHEDULE" 板块是嵌套在 frame 主结构下的 iframe, 如下图3
frame 是整个页面的框架,iframe 是内嵌的网页元素,也可以说是内嵌的框架。iframe 和 frame 标记的最大区别是在网页中嵌入 的所包含的内容与整个页面是一个整体,而< /frame>所包含的内容是一个独立的个体,是可以独立显示的。
因此要实现对 " Origin" & " Destination" 填充成功,首先要先转换到 iframe框架,通过 switch_to_frame() 方法转换。 在图3可见,iframe label 没有 " Name" 或者 " ID" 属性名,所以只能直接对这 ifrme 定位,例如通过 css 或者 xpath等方法。
在填充完成后,由于登陆主页后,在某个设定的时间段内,会弹出 如下图4 的 Live-Chat帮助活动框架,该框架是在frame里的。当运行 Selenium 后,可见该帮助活动框架是把 " Destination" 和 “ Veiw" 遮挡的, 如下图5, 所以有以下两种情况出现。
1. 如果不把这个帮助框移开,当要自动对"Destionation" 填充时,会遇到元素不可见的报错信息。
2. 如果把这个帮助框随便移到坐标,例如(0,100), 就可以成功对"Destionation" 填充,但是如果以这个坐标位置,也是会遮挡 ” View", 当要执行 " Veiw" 时,也会收到类似的元素不存在的报错信息, 如下图6
因此,解决方法也有以下的方法。
1. 把帮助框向下移动坐标改为 (0,130),经过测试,可以解决 “ View" 的遮挡问题。
2. 保持移动(0,100), 当成功对"Destionation" 填充后,虽然 ” View" 被遮挡了,但可以先从“ SCHEDULE" 这个 ifrme 框架,通过 switch_to_default_content() 方法跳转回 frame里,目的是要把这个帮助框关闭,定位这个框的 ” X“ (关闭) 如下图4 关闭后,就可以解决帮助框遮挡问题。
注: 以上提及的坐标移动,可以通过 执行Java Script ,详细请看在之前发布的鼠标滚动方法的文章里已经有提过。
微博视频以移动(0,100) 为例,移动-跳转去frame进行填充-跳回frame关闭帮助框-跳回iframe执行View的顺序,目的是演示怎样关闭那个帮助框。其实正常逻辑可以在登陆主页时,先直接关闭帮助框,就可以省去 frame 和 iframe 直接的不断跳转。但为说明它们之间的跳转逻辑,就用了这迂回的过程。
在解决了帮助框遮挡问题后,完成对 “Origin" " Destination" 填充,还有日期选择,执行” View" 后,主页会弹出了一个警告 (Alert) 框, 如下图7, 经过多次较对, “Origin" 和 " Destionation" 的名和这网页自动带出来的名也是100%匹对的。于是尝试把这警告框关闭,再重新运行,结果也是一样,不可以自动跳转到一个新窗口。
注:可以通过 switch_to_alert().accept() 方法去关闭这个警告框。作用就相当于执行 ”确定“。
再重新观察 ” Origin" 和 “ Destination" 这两个 input 框结构,都是有 autocomplete=“list” 这样的自动列表设置,而且还嵌套了一个 带有 type=“hidden” 这样的属性的 input label, 但是没有 value 属性名的, 如下图 8, 9
尝试在 " Origin" 和 ” Destination " 手动选择相对应的名后,再观察那个嵌套的 input label 自动多了个 value属性值(也就是船公司系统常用的 Port Code) , 如下图 10,11
由于这隐藏式的菜单,如果只对 " Origin" 和 ” Destination " 填充,还不够的,以上已经提到会遇到警告框弹出。所以解决的方法,要对这两个嵌套的 Port Code 框先移除它的隐藏属性,主要方法有以下两种,通过执行 Java Script。( 以下对 “ Origin " 对应的 Port Code 为例,Destination 就不再重复了,也是一样的思路。)
1.
pol_code = browser.find_element_by_id(‘oriLocCd’)
execute_script(“arguments[0].removeAttribute(‘type’)”,pol_code)
这个方法就是直接移除 type = 'hidden" 这个属性
2.
pol_code = browser.find_element_by_id(‘oriLocCd’)
execute_script(“arguments[0].type=‘inline’”,pol_code)
这个方法就是把 type = ‘hidden’ 属性 改为 可视状态。
无轮用哪个方法,在测试过程可见这两个隐藏框最终都会显示出来,并可以实现通过 send_keys 直接完成填充。 如下图 12
接着对 ” Period" 起始日期选择后 (可以通过填充方法,也可以用默认自带的),执行 “ View " 后,会 自动打开一个新的搜索结果窗口, 如下图 13
此时如果想要对第2个窗口操作,必须通过句柄(handles) 转换,方法如下,其中 【1】表示索引1,第2个窗。同理,当有多个分窗时,如果要跳转去第5个窗,就为 handles[4] 。
handles=browser.window_handles
switch_to.window(handles[1])
最后,可以对 ” Priority" 进行 选择,然后执行 “ Search " 。
在 “Priority” 中,可见是一个 Select label, 如下图 14, 例如要选择” Direct", 有以下两种方法:
1. 可以通过 Select 库 去选择,具体可以参考之前发布的 Select 库的应用文章。
priority = browser.find_element_by_id(‘tsInd’)
Select(priority).select_by_value(‘D’)
2. 由于这个 Select label 没有设置不可视,所以如果不用 Select 库,也可以直接对 " Direct" 定位。
图1
图2
图3
图4
图5
图6
图7
图8
图9
图10
图11
图12
图13
图14