我正在使用capybara / dsl,selienium webdriver和电子表格gem开发支持javascript的屏幕抓取工具。非常接近所需的输出,但是出现了两个主要问题:
我无法找出确切的xpath选择器来过滤掉我正在寻找的元素;为了确保没有丢失,我使用的是一个广泛的选择器,我知道它会产生重复的元素。我打算只在那个选择器上调用.uniq,但这会引发错误。执行此操作的正确方法是什么导致所需的过滤。错误是'uniq'的未定义的无法。也许我没有正确使用它:results = all("//a[contains(@onclick, 'analyticsLog')]").uniq
。我知道我选择提取hrefs://a[contains(@onclick, 'analyticsLog')]
的xpath将定义比我预期更多的节点,因为使用find来检查页面元素显示144而不是72构成页面结果。我找了一个更具体的选择器,但是由于网站上使用的业务逻辑,我没有找到一个没有过滤掉一些所需链接的选择器。
我的save_item方法有两个选择器,它们并不总是在信息结果中找到,我希望脚本只是跳过那些找不到的那些,只保存那些但是我当前的迭代会抛出一个Capybara :: ElementNotFound并退出。我怎样才能将其配置为以预期的方式工作。
下面的代码
require "capybara/dsl"
require "spreadsheet"
Capybara.run_server = false
Capybara.default_driver = :selenium
Capybara.default_selector = :xpath
Spreadsheet.client_encoding = 'UTF-8'
class Tomtop
include Capybara::DSL
def initialize
@excel = Spreadsheet::Workbook.new
@work_list = @excel.create_worksheet
@row = 0
end
def go
visit_main_link
end
def visit_main_link
visit "http://www.some.com/clothing-accessories?dir=asc&limit=72&order=position"
results = all("//a[contains(@onclick, 'analyticsLog')]")# I would like to use .uniq here to filter out the duplicates that I know will be delivered by this selector
item = []
results.each do |a|
item << a[:href]
end
item.each do |link|
visit link
save_item
end
@excel.write "inventory.csv"
end
def save_item
data = all("//*[@id='content-wrapper']/div[2]/div/div")
data.each do |info|
@work_list[@row, 0] = info.find("//*[@id='productright']/div/div[1]/h1").text
@work_list[@row, 1] = info.find("//div[contains(@class, 'price font left')]").text
@work_list[@row, 2] = info.find("//*[@id='productright']/div/div[11]").text
@work_list[@row, 3] = info.find("//*[@id='tabcontent1']/div/div").text.strip
@work_list[@row, 4] = info.find("//select[contains(@name, 'options[747]')]//*[@price='0']").text #I'm aware that this will not always be found depending on the item in question but how do I ensure that it doesn't crash the program
@work_list[@row, 5] = info.find("//select[contains(@name, 'options[748]')]//*[@price='0']").text #I'm aware that this will not always be found depending on the item in question but how do I ensure that it doesn't crash the program
@row = @row + 1
end
end
end
tomtop = Tomtop.new
tomtop.go
答案 0 :(得分:1)
问题1:获取独特元素
all
返回的所有元素都是唯一的。因此,我假设“唯一”元素,你的意思是“onclick”属性是唯一的。
Capybara返回的元素集合是可枚举的。因此,您可以将其转换为数组,然后根据其onclick属性获取唯一元素:
results = all("//a[contains(@onclick, 'analyticsLog')]")
.to_a.uniq{ |e| e[:onclick] }
请注意,重复链接看起来像是图像的一个,而图像下面的文本是一个。您可以将搜索范围限定为一个或另一个,然后您不需要执行uniq检查。要仅限于文本链接,请使用链接是h5的子项的事实:
results = all("//h5/a[contains(@onclick, 'analyticsLog')]")
问题2:如果元素存在则捕获文本
要解决第二个问题,可以使用first
找到元素。如果存在匹配元素,则返回匹配元素,如果不存在,则返回nil。然后,如果找到该元素,则可以保存文本。
例如:
el = info.first("//select[contains(@name, 'options[747]')]//*[@price='0']")
@work_list[@row, 4] = el.text if el
如果您需要所有匹配元素的文本,请使用all
:
options = info.all(".//select[contains(@name, 'options[747]')]//*[@price='0']")
@work_list[@row, 4] = options.collect(&:text).join(', ')
当有多个匹配选项时,您将获得类似“绿色,粉红色”的内容。如果没有匹配选项,您将获得“”。