为什么我的代码中会"undefined local variable or method"?



我想从Google搜索查询中删除链接。

我不能在TAB (links)中保存结果:

error : test.rb:17:in `parse_result': undefined local variable or
method `links' for main:Object (NameError)

这是我的代码:

require 'open-uri'
require 'nokogiri'
doc = Nokogiri::HTML(open('https://www.google.fr/search?q=estimation+immobilier'))
links = []
def parse_results(doc)
    doc.search('.g').map do |element|
      parse_block(element)
    end
end

def parse_block(element)
    tempo = element.search('.r').to_s
    links << tempo.scan(/<a href="/url?q=(.*)&amp;sa=U/)[0][0]
end
parse_results(doc)
puts links

这个问题是可变范围的,而且很常见。

我会这样重写代码:

require 'open-uri'
require 'nokogiri'
doc = Nokogiri::HTML(open('https://www.google.fr/search?q=estimation+immobilier'))
def parse_results(doc)
  _links = []
  doc.search('.g').each do |element|
    _links << parse_block(element)
  end
  _links
end
def parse_block(element)
  tempo = element.search('.r').to_s
  tempo.scan(/<a href="/url?q=(.*)&amp;sa=U/)[0][0]
end
links = parse_results(doc)
puts links

links可以定义为实例、类或全局变量,但所有这些都有代码气味。你会试图规避作用域,当你谈到避免在变量堆栈上浪费空间时,这是你真正的朋友。

scan将返回一个结果数组,因此将其结果压入_links

map不是你正在做的正确方法;each更合适,因为要在HTML中循环搜索class="g"的结果。使用map,您可以像这样编写parse_results():

def parse_results(doc)
  doc.search('.g').map { |element| parse_block(element) }
end

parse_block()写得不正确,或者至少它可以写得更符合Nokogiri的习惯用法。如果您在使用XML或HTML解析器时不得不使用正则表达式,那么您就知道有些事情需要重新考虑。看看发生了什么,下面是代码在parse_results()parse_block()中看到的:

doc.search('.g').first.search('.r').to_s
# => "<h3 class="r"><a href="/url?q=http://www.meilleursagents.com/estimation-immobiliere/&amp;sa=U&amp;ei=z33SU5a-LMPaoASe94GYBw&amp;ved=0CBQQFjAA&amp;usg=AFQjCNH_Nfe9VGSqO8AU_mc3TL_ZsyNRFw"><b>Estimation immobiliere</b> gratuite - MeilleursAgents.com</a></h3>n"

您正在尝试从链接中抓取参数,因此使用Nokogiri干净地完成该操作,而不是尝试使用模式和scan。我打开页面并像您一样解析它,然后尝试如下:

doc.search('.g h3.r a').map(&:to_html)
# => ["<a href="/url?q=http://www.meilleursagents.com/estimation-immobiliere/&amp;sa=U&amp;ei=gYDSU-D3AsHXiwLj1oGwBg&amp;ved=0CBQQFjAA&amp;usg=AFQjCNG59EuN3nByaD1NEg7t3garmotJTg"><b>Estimation immobiliere</b> gratuite - MeilleursAgents.com</a>",
#     "<a href="/url?q=http://www.drimki.fr/estimation-immobiliere-gratuite&amp;sa=U&amp;ei=gYDSU-D3AsHXiwLj1oGwBg&amp;ved=0CBoQFjAB&amp;usg=AFQjCNH4HpJ9WRzLhpSGVfRwcogxuJPZDA"><b>Estimation immobiliu00E8re</b> gratuite (maison, appartement <b>...</b> - Drimki</a>",
#     "<a href="/url?q=http://www.pap.fr/evaluation/estimation-immobiliere&amp;sa=U&amp;ei=gYDSU-D3AsHXiwLj1oGwBg&amp;ved=0CCAQFjAC&amp;usg=AFQjCNGcAeTDeib6hBVcD931CGyDRoPx6A"><b>Estimation immobiliu00E8re</b> avec Particulier u00E0 Particulier | De <b>...</b> - P.a.p</a>",
#     "<a href="/url?q=http://www.lacoteimmo.com/&amp;sa=U&amp;ei=gYDSU-D3AsHXiwLj1oGwBg&amp;ved=0CCYQFjAD&amp;usg=AFQjCNEjsDh8wYnj9XQBuuotGWOtJKrBYQ">LaCoteImmo - <b>Estimation immobiliu00E8re</b> et Prix immobilier</a>",
#     "<a href="/url?q=http://www.efficity.com/estimation-immobiliere/&amp;sa=U&amp;ei=gYDSU-D3AsHXiwLj1oGwBg&amp;ved=0CCwQFjAE&amp;usg=AFQjCNH_2RgWZ4VMeP29eKt1MAZTySOSZA"><b>Estimation immobiliu00E8re</b> - Efficity</a>",
#     "<a href="/url?q=http://www.paruvendu.fr/pa/prix-immobilier-prix-m2-estimation-gratuite-bien-immobilier/&amp;sa=U&amp;ei=gYDSU-D3AsHXiwLj1oGwBg&amp;ved=0CDIQFjAF&amp;usg=AFQjCNFz0VTEKcTJrzIgT4nwOMnm85vX5g"><b>Estimation</b> gratuite d'un bien <b>immobilier</b> - ParuVendu</a>",
#     "<a href="/url?q=http://www.meilleurtaux.com/services-immo/vendre-un-bien-immobilier/estimation-immobiliere.html&amp;sa=U&amp;ei=gYDSU-D3AsHXiwLj1oGwBg&amp;ved=0CDgQFjAG&amp;usg=AFQjCNGjSqsVQe0GB0uzTvewfR-FtfGUww"><b>Estimer</b> la valeur de son bien <b>immobilier</b>- Meilleurtaux.com</a>",
#     "<a href="/url?q=http://prix-immobilier.latribune.fr/estimation-immobiliere/&amp;sa=U&amp;ei=gYDSU-D3AsHXiwLj1oGwBg&amp;ved=0CD4QFjAH&amp;usg=AFQjCNFelUOIWlvj09l5RIG0KF8CiY9kLw"><b>Estimation immobiliere</b> gratuite avec MeilleursAgents.com</a>",
#     "<a href="/url?q=http://www.refleximmo.com/estimation-immobiliere-gratuite-appartement&amp;sa=U&amp;ei=gYDSU-D3AsHXiwLj1oGwBg&amp;ved=0CEQQFjAI&amp;usg=AFQjCNErmk1sUrmrAPU188KyyfYG_O0cMw"><b>Estimation</b> gratuite de votre appartement en ligne - Refleximmo</a>",
#     "<a href="/url?q=http://www.capital.fr/immobilier/estimation-immobiliere&amp;sa=U&amp;ei=gYDSU-D3AsHXiwLj1oGwBg&amp;ved=0CEoQFjAJ&amp;usg=AFQjCNEVRbp_kOwOmT86TWHEvFbjm6W3nA"><b>Estimation Immobiliu00E8re</b> - Immobilier - Capital.fr</a>"]

更全面的CSS大大缩小了返回结果的范围。

稍微调整一下,结果是:

doc.search('.g h3.r a').map{ |a| a['href'] }
# => ["/url?q=http://www.meilleursagents.com/estimation-immobiliere/&sa=U&ei=OoHSU7KaEszwoAS__YDoCA&ved=0CBQQFjAA&usg=AFQjCNFNCH0iR3pr0fQX6wSjcj1_s3CsRg",
#     "/url?q=http://www.drimki.fr/estimation-immobiliere-gratuite&sa=U&ei=OoHSU7KaEszwoAS__YDoCA&ved=0CBoQFjAB&usg=AFQjCNGUbFcsWWQY-bc8Vu-d-GD9YFcbVg",
#     "/url?q=http://www.pap.fr/evaluation/estimation-immobiliere&sa=U&ei=OoHSU7KaEszwoAS__YDoCA&ved=0CCAQFjAC&usg=AFQjCNGztbZlDWWGS4kNPHzR06ayRdAQKg",
#     "/url?q=http://www.lacoteimmo.com/&sa=U&ei=OoHSU7KaEszwoAS__YDoCA&ved=0CCYQFjAD&usg=AFQjCNEZK_JVduJKJvFpDDXu4yIsTXGMFg",
#     "/url?q=http://www.efficity.com/estimation-immobiliere/&sa=U&ei=OoHSU7KaEszwoAS__YDoCA&ved=0CCwQFjAE&usg=AFQjCNHHc-GuJoHXTx3N3_Ex_fz1KUp1cg",
#     "/url?q=http://www.paruvendu.fr/pa/prix-immobilier-prix-m2-estimation-gratuite-bien-immobilier/&sa=U&ei=OoHSU7KaEszwoAS__YDoCA&ved=0CDIQFjAF&usg=AFQjCNGmwWmo19asoooWz6Lbh0YMOC8wlg",
#     "/url?q=http://www.meilleurtaux.com/services-immo/vendre-un-bien-immobilier/estimation-immobiliere.html&sa=U&ei=OoHSU7KaEszwoAS__YDoCA&ved=0CDgQFjAG&usg=AFQjCNFJ_fAsPBmZvVU60jRLh-yKzvuEiw",
#     "/url?q=http://prix-immobilier.latribune.fr/estimation-immobiliere/&sa=U&ei=OoHSU7KaEszwoAS__YDoCA&ved=0CD4QFjAH&usg=AFQjCNHHaVmKGg4jiaT-6AwZAfby2-H4sg",
#     "/url?q=http://www.refleximmo.com/estimation-immobiliere-gratuite-appartement&sa=U&ei=OoHSU7KaEszwoAS__YDoCA&ved=0CEQQFjAI&usg=AFQjCNGiBMMYrK-EO9wqIh82eW2uFT0n8w",
#     "/url?q=http://www.capital.fr/immobilier/estimation-immobiliere&sa=U&ei=OoHSU7KaEszwoAS__YDoCA&ved=0CEoQFjAJ&usg=AFQjCNEf8FQuKCYBMXBB5FA2dJ2gor4Wmg"]

很明显,我们看到的是一个绝对url数组,它可以使用Ruby的内置URI类来处理:

require 'uri'
doc.search('.g h3.r a').map{ |a| 
  uri = URI.parse(a['href'])
  query_hash = Hash[URI::decode_www_form(uri.query)]
  query_hash['q']
}
# => [
    "http://www.meilleursagents.com/estimation-immobiliere/",
    "http://www.drimki.fr/estimation-immobiliere-gratuite",
    "http://www.pap.fr/evaluation/estimation-immobiliere",
    ...

这应该给你足够的信息来重写你的代码更健壮一点。正则表达式不是解析HTML的好工具,最好尽可能使用经过良好测试的预构建的轮子,比如URI。

我之所以说这种方法更健壮,是因为这段代码:

links << tempo.scan(/<a href="/url?q=(.*)&amp;sa=U/)[0][0]

这个搜索很容易出错。URL格式可以很快改变,特别是如果一个网站怀疑人们正在抓取他们的页面,而他们不希望抓取发生,比如谷歌。他们可以很容易地改变参数的顺序,他们可以改变在页面中写入链接的方式,等等,因为HTML允许非常自由的源格式,浏览器仍然会向用户呈现相同的视图。想象一下,如果谷歌选择呈现这样的链接,你会有多么有趣:

<a
 href="/url?amp;sa=U&q=...

正则表达式将中断,导致您的代码中断,而使用URI和Nokogiri向下钻取将继续工作。

如果您将links和实例变量设置为:

require 'open-uri'
require 'nokogiri'
doc = Nokogiri::HTML(open('https://www.google.fr/search?q=estimation+immobilier'))
@links = []
def parse_results(doc)
    doc.search('.g').map do |element|
      parse_block(element)
    end
end

def parse_block(element)
    tempo = element.search('.r').to_s
    @links << tempo.scan(/<a href="/url?q=(.*)&amp;sa=U/)[0][0]
end
parse_results(doc)
puts @links

相关内容

  • 没有找到相关文章

最新更新