学完元素通用性之后,大家应该已经知道了,在使用影刀 RPA 捕获去哪儿网某个酒店(例如:北京三里屯CHAO酒店)点评问答模块中的点评数元素时,因为点评数这个元素是动态元素,所以我们需要考虑其通用性。
影刀官方课程针对此类问题给了一个通用的解决方案:
先通过元素编辑将其目前所勾选的属性给去掉或者换成其他属性,再进行校验。
如果校验到多个元素,此时可以结合源码,分析网页结构。
根据网页源码找出能区分出不同元素的关键属性。
在元素编辑中勾选这个这个关键属性即可。
但是昨天遇到这个问题的时候,在使用元素编辑来解决这个问题之前,我看到元素编辑器提示:未找到元素,请确认窗口已激活,或者点此修复,于是我就尝试修复了一下,修复完之后,我发现:
此时,innerText 属性还是勾选状态,再仔细看,原来属性的值改为通过正则表达式来匹配了。
嗯,不错,很多时候用正则表达式或者通配符的方式也可以很快的解决这类问题,这是一种更小范围的抽象。
不过,这时我突然意识到一个问题:
如果去掉 innerText 属性,就会同时匹配到点评数元素和问答数元素,如果不去掉 innerText 属性,改为正则表达式之后,虽然点评数元素能够正确匹配到,但理论上问答数元素应该也能匹配到,因为问答数元素的内容结构是跟点评数元素一样的,都是数字啊,可是为什么没有匹配到它而是只匹配到了点评数元素呢?
想到正则表达式既然可以匹配所有数字,那我就索性把元素编辑中问答数的数字改成跟评论数数字一样,然后把匹配方式还改成相等,这样理论上应该就可以同时匹配到点评数和问答数这两个元素,于是尝试了一下,然后再次校验,神奇的事情发生了:
居然校验不到?
这时候,我就有点不明白了,因为目前限制条件只有 innerText 这一个属性,其他条件都没有勾选啊,难道影刀 RPA 在定位元素的时候,还有一些隐藏的限制条件?但感觉这样做不太合理的样子。
那难道是使用路径定位的?但是如果是使用了路径或者其的话,应该在 index 或者 index-of-type 上有体现才对,但现在来看,其它层级并没有任何路径的定位啊,除非是用了类似的定位方式,但又不是通过 index 或者 index-of-type 来表达的,但感觉这样也不是很合理。
于是,我就又仔细观察源代码和元素编辑器中的内容的区别,此时,我注意到了一个细节:

原来这个点评数和问答数后面使用的不是同一种括号,前者是中文括号(),后者则是英文括号(),而我在尝试更换数字的时候,只是更改了数字,并没有意识到这两个括号是不一样的,所以更换完之后才匹配不到。
心中的困惑解决了,答案跟我想象的不一样,并没有什么黑魔法,只是一个很小的细节导致的,虽然不知道为什么去哪儿网的开发者为什么在这个地方要用两种不同类型的括号,难道是为了一些设计效果之类的吗?不过,这个也不重要了。
只是很多时候当结果跟自己的猜想不一致的时候,不用着急下结论,可以再认真分析一下问题的表现,答案往往可能隐藏在细节中。
经过上面的一个小插曲之后,我开始了进一步的思考。
官方课程中在讲到影刀RPA 如何定位一个元素时提到:
影刀 RPA 是通过路径和限制条件来唯一定位一个元素的。
但我个人觉得这里叫做路径可能并不是很恰当,因为元素编辑中列出来的这些节点,仅仅体现了元素之间的层级关系,实际上每一个层级中可能都存在很多相似的节点,也就是说仅仅通过节点的层级来看的话,是会存在多条路径的。
我理解的严格意义上的路径,应该是像 XPath 那样直接通过元素的层级和每一级元素在该层级中指定的位置来最终定位唯一一个元素的。又或者像 CSS Selector 那样通过id、class 及位置关系(对应影刀 RPA 元素编辑中的 index 和 index-of-type)等条件来唯一定位元素的。
实际上,影刀 RPA 本身也是支持通过 CSS Selector 以及 XPath 的方式来捕获元素的,但这两种方式对于新手来件都还是存在一定的学习门槛的,另外,通过这两种方式来定位的话,我们虽然可以通过一个专门的文件来保存这些路径,并给这些路径加上注释,但是其可读性及可维护性还是要相对差一些。
而影刀 RPA 的做法是,在捕获一个元素的时候,会默认加上一些限制条件,也就是启用一些属性,最终根据限制条件从多条路径中筛选出一条符合条件的路径。同时,它会将这些节点和节点所包含的属性通过元素编辑器暴露给我们,我们可以进行对它们进行编辑,其可读性和可维护性会比 CSS Selector 和 XPath 这两种方式好很多,而且影刀还专门额外添加了 index 和 index-of-type 这两个属性,更便于我们更好的定位元素。
我们通过元素编辑器可以看到,影刀 RPA 在默认情况下其实是通过尽量少的限制条件来定位一个元素的,比如如果最后一级的某些属性启用之后就能够定位元素的话,它就不会再进行多余的勾选,但问题在于一旦元素的通用性不够,那么去掉一些限制条件之后,我们就需要结合源码去进行分析,虽然熟练了之后也会很快,但是这样的设计还是让我心中产生了一些疑问:
既然每一级中的元素属性它都已经列出来了,那么,理论上它完全可以像 CSS Selector 那样通过id、class 及位置关系(对应影刀 RPA 元素编辑中的 index 和 index-of-type)等条件来唯一定位元素的,也就是说,它可以把每一级节点中相关的属性都勾选上,这样就变成了一条严格的路径。
我觉得这样设计的好处在于:如果最后一级的限制条件过于严格导致元素不具备通用性的话,我们可以直接把这个限制条件给去掉,但此时由于上层节点仍然包含一些限制条件,那么,我们并不需要再进行额外的改动就能把定位的规则变得更通用了,这样对于新手来讲学习成本会降低很多,毕竟影刀官方的初衷也是开发一款人人会用的 RPA。
可是,官方为什么没有按照这种方式来设计呢?目前我还没有得出结论。此处也想 @影刀官方技术同学,想认真请教下,影刀刀官方技术同学在设计元素编辑器的时候是怎么从哪些方面来考虑的呢?期待回复~
当然,以上这些只是我个人的一些不成熟的想法,可能会有考虑的不够全面甚至是错误的地方,也许影刀现在这样的设计也是综合方面因素权衡之后的一个结果。
关于这一点,大家是如何思考的呢?欢迎一起来讨论~
------------------------------------------------------------------
更新1:
看到了下面远方同学的回复,非常有启发性,为了方便大家阅读,特意帮大家提取出来了:
"它可以把每一级节点中相关的属性都勾选上,这样就变成了一条严格的路径"
以我的愚见,勾选的属性越多,属性发生变化的概率越大,任何一个被勾选的属性发生变化,都会影响元素的通用性。
越简单,越强大,还是让我们拥抱简单的快乐吧:)
PS:中英文括号,就是去哪儿的程序员手动打错了,不用怀疑
------------------------------------------------------------------
更新2:
针对远方同学的回复,我对于软件设计时的易用性和稳定性有了新的思考,也分享给大家,大家有什么新的想法也可以一起讨论哈~
从通用性这个角度来考虑的话,远方同学的观点确实是很有道理的。
因为同时满足的限制条件越多,容错率就越低,也就意味着稳定性越差。因为如果某一级元素节点的属性发生了变化(比如:class 属性变了),而这个属性又被勾选了,那么 RPA 在运行过程中就捕获不到这个元素了,而如果只用最少的属性来限制的话,上层某些节点属性发生变化时,可能并不会影响到整个元素的定位,从而保证了元素的通用性。
看来这样设计是基于稳定性和易用性的一种权衡。我提出的这个方案,虽然看起来易用性比较好,因为前期开发应用的时候,遇到动态元素的情况,不用调整太多的属性,就可以快速实现元素的通用性,这样做看似对新手比较友好,但是在实际的业务场景中,稳定性相对来说更重要,毕竟能持续稳定的正常工作才是首要目标,一旦应用稳定性出现问题,那么开发者还是要花时间来分析问题,并作出调整,这样整体算下来,效率未必高。因此,从整体来看,牺牲一点前期的易用性,来保证后期整体应用的稳定性,我觉得这个牺牲是非常值得的。其实也还好,前期把整个原理理解透了,后面在实际开发的过程中配合上网页源码,效率也挺高的。
------------------------------------------------------------------
更新3:
大家在学习的过程中想要一起交流,共同学习的话,可以加我微信哈:17600125520。