动机
我一直在考虑静态检测CSS选择器的复杂性。
我正在研究的范围是测试自动化和网络抓取,其中选择可靠的CSS选择器很重要,以尽可能减少对UI /标记/布局更改的依赖。
目前,我可以通过
css-selector-parser
解析CSS选择器并简单地计算节点数来检查CSS选择器的“深度”。如果节点数超过5,我认为这是一个潜在的复杂CSS选择器。这背后的原因是,选择器在路径中拥有的节点越多,页面对HTML结构的依赖性就越大-它就越脆弱。例如,此CSS选择器将被认为是“易碎的”(6个节点):特殊的“得分”值,可以使选择器的测量结果更坚固/更耐用。受著名的代码复杂性度量标准(例如,循环复杂性或可维护性指数)的启发。您会考虑使用哪些参数来确定CSS选择器是否可以抵抗更改?什么才是可靠的CSS定位器呢?特定于实现的类和属性会使选择器的可靠性降低。 (例如,在AngularJS-bootstrap
或ng-scope
类的情况下)使用
ng-binding
或id
属性可能是理想的#1 楼
您会考虑使用哪些参数来确定CSS选择器是否可以抵抗更改?是什么构成可靠的CSS定位器?我会考虑的一些因素:首先,基础知识是:
定位器不应包含页面布局结构
不要基本选择在实际页面上的文字
在现有框架中工作...
是否使用嵌套表
是否使用
data-
属性标识符给定的CSS ID是否实际上是唯一的
选择器中是否使用文字内容文本
重复元素的使用,例如
div div div
第一个选择器元素的DOM嵌套深度
选择器中单独html元素的数量
历史上更改任何现有选择器的频率
选择器字符串(不同元素的数量)
选择器字符串的长度(不同字符的数量)
它与DOM中的嵌套嵌套级别有关
是否部分和通配符内容文本在定位器中使用
是否使用表,如果使用了表,如何对行进行排序/重新排序
例如通过使用索引标识符css
:nth-child(number)
或xpath []
使用带有限定标识符的
id
或name
等独特属性将css id用于选择器中元素的次数
存在多少个实例选择器中的诸如css类之类的标识符
某些ID是否全部都是数字且唯一的,这表明数据库支持
某些css元素ID是否动态,例如唯一资源记录ID的
选择器的每个单独元素出现在DOM中的次数
选择器元素是直接嵌套还是仅在其他元素“内部”
与其他选择器比较时是否可以看到一致的方法
如果在选择器中使用多个
table
,td
或tr
,则是否在一张表中使用使用通用属性(例如
span
和div
),但不限定标识符它们DOM元素是直接相邻还是嵌套在其他元素中
使用像Ruby on Rails这样的框架为框架提供与数据库相关的元素的唯一标识符一部分是要知道要赋予这些权重什么。有些将受到开发和ux框架的使用的严重影响,并且在某些情况下与其他情况或多或少相关。
表示元素的权重和可预测性的一种方法是对工程进行反向工程并检查由于DOM更改而导致的过去测试中断,以查看关系。在实践中,我发现很难做到这一点,因为开发人员在提交代码之前先修复测试。
像这样的大型公司也许可以更好地进行研究。
区分这种变化的应用程序代码和自动化选择器也很重要。给定选择器的等级或等级可能会为自动化器提供很好的反馈,以供自动化器开发用于自动测试的选择字符串,但不适合ux组开发的页面内容本身。
#2 楼
我已经能够减少您描述的复杂性,如下所示:将代码视为数据,将数据视为代码;使用集合。这避免了使用定义进入网页的复杂路径的方法。使用集合和适当的过滤技术,我们只能依靠在页面上看到的文本。
示例
var day = 12;
var calendar = calenderElement.Click(); //opens the calendar
//finds the link with the number 12 (in the text) for each link.
var ele= calendar.FindElements.By.TagName("a").Select(i=>i.Text == day).First();
ele.Click() //sets the date in the calendar
此代码样式对于C#,Java和Javascript解决方案,应该是开箱即用的。这三种语言都支持集合查询,并且FindEements将从当前的IWebElement(如果选择器不是全局的)开始工作。使用当前元素中的FindElement可以对所需的内容进行细调。 >
这使我们可以以不同的方式来思考网页。我们真正需要的只是ID,链接或CSS作为我们的主要检索点。从那里开始,我们使用集合过滤和/或从这些点开始的FindEement(s)来过滤我们想要的内容。最好的部分是它只能基于我们看到的文本,而不能基于隐藏的属性等。但是,如果我们需要更细粒度的搜索,则所有属性也可以用相同的方式进行过滤。
示例2
我们知道类选择器将返回(通常是太多元素),因此让我们基于仅使用classNames看到的文本拨入过滤器。
var specificTextWanted = "Something we see";
//too many elements here //filtered here
var theSingleElement = wd.FindElements(By.ClassName("alpha").Where(i=>i.text == specificTextWanted).First();
我们现在可以基于返回的集合使用基于文本的过滤来绕过复杂的选择器。即使对于动态内容,此方法也能很好地工作,但是有时可以在上面的Where子句中引发陈旧的元素引用,它很容易修复(Try,Catch),而忽略该元素,毕竟,它不再存在了!
评论
非常好的总结,谢谢!是的,重量会很有挑战性。我想,如果除了CSS选择器之外,还有给定页面的HTML,则可以做出更有意义的决定。这会使分析复杂化,但可能会得出更现实的结果。
– alecxe♦
17-6-26 at 21:36
是的,您要使用的实际DOM页面是图片的一部分,并且是上述某些分析所需要的
–迈克尔·杜兰特(Michael Durrant)
17-6-26 at 21:40
我也在考虑将一些代码复杂性思想应用于理解CSS选择器的复杂性-例如,更多的运算符(选择器,例如:not,:first-child等),更多的[]条件-选择器越复杂。但是,这不一定意味着选择器不够好。我想,由于没有硬性规定,我们将不得不越过一条线,避免误报是不可能的。
– alecxe♦
17-6-26 at 21:45