如何使用 Mechanize 的解析值忽略循环中的 nil 值?
How do I ignore the nil values in the loop with parsed values from Mechanize?
在我的文本文件中有一个 URL 的列表。使用 Mechanize 我正在使用该列表来解析标题和元描述。但是,其中一些 URL 页面没有元描述,这会导致我的脚本停止并出现 nil 错误:
undefined method `[]' for nil:NilClass (NoMethodError)
如果我使用 Rails,我已经阅读并看到了解决方案,但是对于 Ruby,我只看到 reject
和 compact
作为可能的解决方案忽略零值。我在循环末尾添加了 compact
,但这似乎没有任何作用。
require 'rubygems'
require 'mechanize'
File.readlines('parsethis.txt').each do |line|
page = Mechanize.new.get(line)
title = page.title
metadesc = page.at("head meta[name='description']")[:content]
puts "%s, %s, %s" % [line.chomp, title, metadesc]
end.compact!
它只是像这样的文本中的 url 列表:
http://www.a.com
http://www.b.com
这是控制台输出的例子:
http://www.a.com, Title, This is a description.
如果在 URL 的列表中该特定页面上没有描述或标题,则会抛出 nil 错误。我不希望它跳过任何网址,我希望它遍历整个列表。
这是一种方法:
编辑(增加了不跳过任何 url 的要求):
metadesc = page.at("head meta[name='description']")
puts "%s, %s, %s" % [line.chomp, title, metadesc ? metadesc[:content] : "N/A"]
这是未经测试的,但我会这样做:
require 'open-uri'
require 'nokogiri'
page_info = {}
File.foreach('parsethis.txt') { |url|
page = Nokogiri::HTML(open(url))
title = page.title
meta_desc = page.at("head meta[name='description']")
meta_desc_content = meta_desc ? meta_desc[:content] : nil
page_info[url] = {:title => title, :meta_desc => meta_desc_content}
}
page_info.each do |url, info|
puts [
url,
info[:title],
info[:meta_desc]
].join(', ')
end
File.foreach
迭代读取文件,return 单独读取每一行。
如果页面没有标题,page.title
可能 return 为 nil;标题在页面中是可选的。
我将 meta-description 的访问分为两个步骤。元标记在 HTML 中是可选的,因此它们可能不存在,此时 nil 将被 returned。尝试访问 content=
参数会导致异常。我想这就是你所看到的。
相反,在我的代码中,如果找到 meta-description 标记,则有条件地为 meta_desc_content
分配一个值,否则为零。
该代码使用 key/value 对 URL 及其相关标题和 meta-description 填充 page_info
散列。我这样做是因为 hash-of-hashes 或者可能是 array-of-hashes 是一种非常方便的结构,适用于各种二次操作,例如 return 将信息作为 JSON或插入数据库。
作为第二步,代码迭代该散列,检索每个 key/value 对。然后它将这些值连接成一个字符串并打印出来。
你的代码中有很多地方是错误的,或者不是我的做法:
File.readlines('parsethis.txt').each
returns 一个数组,然后您必须对其进行迭代。这不是可扩展的,也不是有效的。 File.foreach
比 File.readlines(...).each
快,所以要养成使用它的习惯,除非你完全确定你知道为什么要使用 readlines
。
- 您将 Mechanize 用于 Nokogiri 和 OpenURI 可以更快完成的事情。 Mechanize 是一个很棒的工具 如果 您正在使用表单并需要浏览网站,但您没有这样做,所以您要拖拽额外的 code-weight没有必要。不要那样做;它会导致程序运行缓慢。
page.at("head meta[name='description']")[:content]
是等待中的异常。正如我上面所说,meta-descriptions 不一定会存在于页面中。如果没有,那么您正在尝试执行 nil[:content]
,这肯定会引发异常。取而代之的是,逐步找到所需的数据,以便在尝试获取其内容之前确保 meta-description 存在。
- 您不能像以前那样使用
compact
或 compact!
。 each
块不是 return 数组,这是 compact
或 compact!
所需的 class。你可以使用 map
但逻辑会很混乱, map
里面的 puts
很少被使用。 (可能不应该使用的可能性更大,但这是另一回事。)
在我的文本文件中有一个 URL 的列表。使用 Mechanize 我正在使用该列表来解析标题和元描述。但是,其中一些 URL 页面没有元描述,这会导致我的脚本停止并出现 nil 错误:
undefined method `[]' for nil:NilClass (NoMethodError)
如果我使用 Rails,我已经阅读并看到了解决方案,但是对于 Ruby,我只看到 reject
和 compact
作为可能的解决方案忽略零值。我在循环末尾添加了 compact
,但这似乎没有任何作用。
require 'rubygems'
require 'mechanize'
File.readlines('parsethis.txt').each do |line|
page = Mechanize.new.get(line)
title = page.title
metadesc = page.at("head meta[name='description']")[:content]
puts "%s, %s, %s" % [line.chomp, title, metadesc]
end.compact!
它只是像这样的文本中的 url 列表:
http://www.a.com
http://www.b.com
这是控制台输出的例子:
http://www.a.com, Title, This is a description.
如果在 URL 的列表中该特定页面上没有描述或标题,则会抛出 nil 错误。我不希望它跳过任何网址,我希望它遍历整个列表。
这是一种方法:
编辑(增加了不跳过任何 url 的要求):
metadesc = page.at("head meta[name='description']")
puts "%s, %s, %s" % [line.chomp, title, metadesc ? metadesc[:content] : "N/A"]
这是未经测试的,但我会这样做:
require 'open-uri'
require 'nokogiri'
page_info = {}
File.foreach('parsethis.txt') { |url|
page = Nokogiri::HTML(open(url))
title = page.title
meta_desc = page.at("head meta[name='description']")
meta_desc_content = meta_desc ? meta_desc[:content] : nil
page_info[url] = {:title => title, :meta_desc => meta_desc_content}
}
page_info.each do |url, info|
puts [
url,
info[:title],
info[:meta_desc]
].join(', ')
end
File.foreach
迭代读取文件,return 单独读取每一行。
如果页面没有标题,page.title
可能 return 为 nil;标题在页面中是可选的。我将 meta-description 的访问分为两个步骤。元标记在 HTML 中是可选的,因此它们可能不存在,此时 nil 将被 returned。尝试访问
content=
参数会导致异常。我想这就是你所看到的。相反,在我的代码中,如果找到 meta-description 标记,则有条件地为
meta_desc_content
分配一个值,否则为零。
该代码使用 key/value 对 URL 及其相关标题和 meta-description 填充 page_info
散列。我这样做是因为 hash-of-hashes 或者可能是 array-of-hashes 是一种非常方便的结构,适用于各种二次操作,例如 return 将信息作为 JSON或插入数据库。
作为第二步,代码迭代该散列,检索每个 key/value 对。然后它将这些值连接成一个字符串并打印出来。
你的代码中有很多地方是错误的,或者不是我的做法:
File.readlines('parsethis.txt').each
returns 一个数组,然后您必须对其进行迭代。这不是可扩展的,也不是有效的。File.foreach
比File.readlines(...).each
快,所以要养成使用它的习惯,除非你完全确定你知道为什么要使用readlines
。- 您将 Mechanize 用于 Nokogiri 和 OpenURI 可以更快完成的事情。 Mechanize 是一个很棒的工具 如果 您正在使用表单并需要浏览网站,但您没有这样做,所以您要拖拽额外的 code-weight没有必要。不要那样做;它会导致程序运行缓慢。
page.at("head meta[name='description']")[:content]
是等待中的异常。正如我上面所说,meta-descriptions 不一定会存在于页面中。如果没有,那么您正在尝试执行nil[:content]
,这肯定会引发异常。取而代之的是,逐步找到所需的数据,以便在尝试获取其内容之前确保 meta-description 存在。- 您不能像以前那样使用
compact
或compact!
。each
块不是 return 数组,这是compact
或compact!
所需的 class。你可以使用map
但逻辑会很混乱,map
里面的puts
很少被使用。 (可能不应该使用的可能性更大,但这是另一回事。)