【问题标题】:Mechanize: Match fields by label text机械化:按标签文本匹配字段
【发布时间】:2016-12-08 06:12:06
【问题描述】:

在抓取表单时,我更喜欢通过标签查找字段,因为我正在使用的页面的大多数 ID 和名称都是自动生成的,我不能相信它们不会更改,而且标签很多比名称更具描述性。

而不是一直在我的脚本中这样做:

Mechanize::Page.elements_with 'label'
#...
some_form.field_with(
  some_form.page.label_with(:text => "Address").node['for']
).value = "..."

some_form.field_with(
  some_form.page.label_with(:text => "Zipcode").node['for']
).value = "..."

我已经开始在我的脚本顶部放置一个猴子补丁:

class Mechanize::Form::Field
  def label_text
    # hack to get the document root
    root = node.ancestors.last
    # look up the label for this field
    label = root.at("label[for=#{dom_id.inspect}]") if dom_id
    label && label.text
  end
 end

所以我可以这样做:

some_form.field_with( :label_text => "Address" ).value = "..."
some_form.field_with( :label_text => "Zipcode" ).value = "..."

这是一个 hack,但它现在可以工作。我可以使用更优雅的解决方案吗?

【问题讨论】:

  • 所以您相信标签不会更改但不会更改字段名称?在我看来,您应该重新检查一下。
  • 我相信标签不会频繁更换。
  • 更改标签文本可能有充分的理由并且不会破坏任何内容。你认为这比没有理由的事情更不可能而且会破坏事情吗?
  • 我想我宁愿不要像ctl00_m_g_8cecb01f_9b31_4ee6_952c_eeea26359d2d_ctl00_ctl02_ctl00_ctl02_ctl00_ctl00_ctl00_ctl04_ctl00_ctl00_ctl04_ctl00_ctl0_TextField 那样依赖ids(不夸张)。我猜如果他们改变任何两个字段的呈现顺序,那将会改变。而且我知道我宁愿通过“描述”的标签文本来查找它,而不是为我正在使用的每个字段复制/粘贴它。当然,如果标签发生变化,脚本会中断,但出于代码维护的目的,标签的描述性要强得多。
  • 您应该发布表单的 html。也许有人能想出一个更好的主意。

标签: ruby label mechanize


【解决方案1】:

我找到了一个不涉及猴子修补的更好解决方案。由于{element}_with 条件是使用=== 匹配的,我可以将它传递给lambda

# convenince methods to define matcher lambdas

def has_title expected
  lambda { |node| expected === node['title']
end

def has_label expected
  lambda do |node|
    # hack to get the document root
    root = node.ancestors.last
    dom_id = node['id']
    # look up the label for this field
    label = root.at("label[for=#{dom_id.inspect}]") if dom_id
    # check if it matches
    expected === (label && label.text)
  end
end

some_form.field_with( :node => has_label("Address") ).value = "..."
some_form.field_with( :node => has_label("Zipcode") ).value = "..."
some_form.field_with( :node => has_title("Description") ).value = "..."
...

【讨论】:

  • 这个sn-p中dom_id的局部变量如何定义?
  • jonkratz:好电话。当它提到Mechanize::Form::Field#dom_id 时,看起来这是我的monkeypatch 的保留。立即修复。
【解决方案2】:

你可以这样做:

def get_key page, str
  id = page.at("label[text()*='#{str}']")[:for]
  key = page.at("##{id}")[:name]
end

然后

form[get_key(page, 'Address')] = value

这有点干净,但仍然是一团糟。我这样做需要一个真正的充分理由,而且如果在我继承的代码中找到它,我会很恼火。

【讨论】:

    猜你喜欢
    • 2013-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多