我试图使用Capybara和PhantomJS进行刮刀时,我必须查找一些项目,当您与3个下拉菜单进行交互时,第一个下拉列表为您提供第二个下拉菜单的选项,第二个下拉列表为您提供第三个选项,所以,这是我的问题,我已经在第一个下拉列表中列出了选项,但是当我点击第一个元素时,循环停止,并且没有执行其他选项下拉菜单。
这是我的代码。
find(:xpath, "//a[contains(@id, 'filterBrand-button')]").click
all(:xpath , "//*[contains(@id, 'filterBrand')]")[1].all('*').each do|option|
if option.text != '-- Select --'
puts option.text
option.click
sleep(2)
find(:xpath, "//a[contains(@id, 'filterModel-button')]").trigger('click')
sleep(2)
all(:xpath , "//*[contains(@id, 'filterModel')]")[0].all('*').each do|option2|
if option2.text != '-- Select --'
puts option2.text
option2.click
find(:xpath, "//a[contains(@id, 'filterVersion-button')]").trigger('click')
sleep(4)
all(:xpath , "//*[contains(@id, 'filterVersion')]")[0].all('*').each do|option3|
if option3.text != '-- Select --'
option3.click
puts option3.text
end
end
end
end
end
我使用sleep命令等到下拉列表加载选项,但在option.click
之后代码在输出中没有显示任何内容
HTML代码就是这样。
<form name="searchForm" id="searchForm" action="http://search_action" method="POST" name="searchform">
<p>
<label class="left" for="filterBrand"> Marca </label>
<select style="font-size:73%;" name="filterBrand" id="filterBrand" class="combo">
</select>
</p>
<p>
<label class="left" for="filterModel"> Modello</label>
<select style="font-size:73%;" onchange="searchProduct();" name="filterModel" id="filterModel" class="combo">
</select>
</p>
<p>
<label class="left" for="filterVersion">Versione</label>
<select style="font-size:73%;" onchange="searchProduct();" name="filterVersion" id="filterVersion" class="combo">
</select>
</p>
如您所见,下拉列表中没有选项,单击此选项后会加载此选项。正如我在第一个问题中所写的那样,问题是,除了第一个下拉选择中的第一个选项之外,capybara在任何选项中都不执行click方法;但如果您对点击方法发表评论,则可以看到打印完整的选项列表。
所以,我能说的是,在调用click方法之后,循环被中断,或者是我在几次执行中可以观察到的。
答案 0 :(得分:0)
你在这里遇到的问题是你正在使用all
但没有传递任何关于你希望它返回多少元素的指示。这意味着0个元素是可接受的数字,因为在第一次选择之后没有选项(直到AJAX请求返回,所以整个页面没有被完全替换,或者你将拥有过时的元素,我假设?){{ 1}}只会返回一个空数组。最简单的解决方案是告诉all
您希望返回最少数量的元素
all
注意:由于https://github.com/teamcapybara/capybara#beware-the-xpath--trap而使用find(:xpath, ".//a[contains(@id, 'filterBrand-button')]").click
all(:xpath , ".//*[contains(@id, 'filterBrand')]")[1].all('*', minimum: 2).each do |option| # Assuming you'll see `-- Select --` and at least one other
if option.text != '-- Select --'
puts option.text
option.click
find(:xpath, ".//a[contains(@id, 'filterModel-button')]").trigger('click')
all(:xpath , ".//*[contains(@id, 'filterModel')]", minimum: 1)[0].all('*', minimum: 2).each do|option2|
if option2.text != '-- Select --'
puts option2.text
option2.click
find(:xpath, ".//a[contains(@id, 'filterVersion-button')]").trigger('click') # Needing to use trigger here is a red flag
all(:xpath , ".//*[contains(@id, 'filterVersion')]", minimum: 1)[0].all('*', minimum: 2).each do|option3|
if option3.text != '-- Select --'
option3.click
puts option3.text
end
end
end
end
end
启动每个XPath选择器。此外,我确信你可以使用的选择器可以使这个读取更好并清理它,但是如果没有实际HTML的例子,就不可能为此提出建议。可以在没有HTML的情况下进行的一个清理建议是将“ - 选择 - ”检查移动到Capybara查询中
.//
更新:既然你已经添加了HTML(假设按钮ID是准确的,并且真的不需要find(:xpath, "//a[contains(@id, 'filterBrand-button')]").click
all(:xpath , "//*[contains(@id, 'filterBrand')]")[1].all('*', minimum: 1, text: /^((?!-- Select --).)*$/).each do |option|# Element with `-- Select --` won't be matched so now minimum: 1
puts option.text
option.click
find(:xpath, "//a[contains(@id, 'filterModel-button')]").trigger('click')
all(:xpath , "//*[contains(@id, 'filterModel')]", minimum: 1)[0].all('*', minimum: 1, text: /^((?!-- Select --).)*$/).each do|option2|
puts option2.text
option2.click
find(:xpath, "//a[contains(@id, 'filterVersion-button')]").trigger('click') # Needing to use trigger here is a red flag
all(:xpath , "//*[contains(@id, 'filterVersion')]", minimum: 1)[0].all('*', minimum: 2, text: /^((?!-- Select --).)*$/).each do|option3|
option3.click
puts option3.text
end
end
end
,这将更清晰地写为
contains