在前10位中查找?
我正在使用Nokogiri来屏幕抓取网站的内容。在前10位中查找?
我设置了fetch_number
来指定我想检索的<divs>
的数量。例如,我可能需要first(10)
来自目标页面的推文。
的代码看起来是这样的:
doc.css(".tweet").first(fetch_number).each do |item|
title = item.css("a")[0]['title']
end
但是,当小于10个匹配div
标签返回,它将报告
NoMethodError: undefined method 'css' for nil:NilClass
这是因为,当没有匹配的HTML被发现,它将返回零。
如何让它返回10以内的所有可用数据?我不需要nils。
UPDATE:
task :test_fetch => :environment do
require 'nokogiri'
require 'open-uri'
url = 'http://themagicway.taobao.com/search.htm?&search=y&orderType=newOn_desc'
doc = Nokogiri::HTML(open(url))
puts doc.css(".main-wrap .item").count
doc.css(".main-wrap .item").first(30).each do |item_info|
if item_info
href = item_info.at(".detail a")['href']
puts href
else
puts 'this is empty'
end
end
end
返回resultes(接近端):
24
http://item.taobao.com/item.htm?id=41249522884
http://item.taobao.com/item.htm?id=40369253621
http://item.taobao.com/item.htm?id=40384876796
http://item.taobao.com/item.htm?id=40352486259
http://item.taobao.com/item.htm?id=40384968205
.....
http://item.taobao.com/item.htm?id=38843789106
http://item.taobao.com/item.htm?id=38843517455
http://item.taobao.com/item.htm?id=38854788276
http://item.taobao.com/item.htm?id=38825442050
http://item.taobao.com/item.htm?id=38630599372
http://item.taobao.com/item.htm?id=38346270714
http://item.taobao.com/item.htm?id=38357729988
http://item.taobao.com/item.htm?id=38345374874
this is empty
this is empty
this is empty
this is empty
this is empty
this is empty
count
仅报告24个元件,但它retuns 30阵列。 它实际上不是一个数组,但是Nokogiri::XML::NodeSet
?我不确定。
title = item.css("a")[0]['title']
是一种不好的做法。
而应考虑使用at
或at_css
代替search
或css
写着:
title = item.at('a')['title']
接下来,如果返回的<a>
标签没有一个title
参数,引入nokogiri和/或Ruby将是苦恼的原因, title
变量将为零。相反,提高你的CSS选择器,只允许比赛就像<a title="foo">
:
require 'nokogiri'
doc = Nokogiri::HTML('<body><a href="foo">foo</a><a href="bar" title="bar">bar</a></body>')
doc.at('a').to_html # => "<a href=\"foo\">foo</a>"
doc.at('a[title]').to_html # => "<a href=\"bar\" title=\"bar\">bar</a>"
注意如何第一个,这是不限制以查找标记有title
参数返回第一<a>
标签。使用a[title]
将只返回参数为title
的参数。
这意味着你的循环遍历值永远不会返回零,并且你不会有返回的数组需要compact
的问题。
作为一般的编程提示,如果你得到尼尔斯这样,看代码生成阵列,因为赔率是好它没有这样做的权利。你应该总是知道什么样的结果,你的代码生成。使用compact
清理阵列是不具有正确写入的代码的大部分时间下意识反应。
这是你更新的代码:
require 'nokogiri'
require 'open-uri'
url = 'http://themagicway.taobao.com/search.htm?&search=y&orderType=newOn_desc'
doc = Nokogiri::HTML(open(url))
puts doc.css(".main-wrap .item").count
doc.css(".main-wrap .item").first(30).each do |item_info|
if item_info
href = item_info.at(".detail a")['href']
puts href
else
puts 'this is empty'
end
end
而这里的什么是错的:
doc.css(".main-wrap .item").first(30)
这里有一个简单的例子表明,为什么不工作:
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
<html>
<body>
<p>foo</p>
</body>
</html>
EOT
在Nokogiri,search',
个CSS and
xpath`是等价的,但第一个是通用的,可以采取任何CSS或XPath,而最后两个特定于该语言。
doc.search('p') # => [#<Nokogiri::XML::Element:0x3fcf360ef750 name="p" children=[#<Nokogiri::XML::Text:0x3fcf360ef4f8 "foo">]>]
doc.search('p').size # => 1
doc.search('p').map(&:to_html) # => ["<p>foo</p>"]
表明这些节点集返回做一个简单的search
只返回一个节点,什么节点样子。
doc.search('p').first(2) # => [#<Nokogiri::XML::Element:0x3fe3a28d2848 name="p" children=[#<Nokogiri::XML::Text:0x3fe3a28c7b50 "foo">]>, nil]
doc.search('p').first(2).size # => 2
使用first(n)
进行搜索将返回“n”个元素。如果没有发现那么多,Nokogiri会使用零值来填充它们。
这是我们假定first(n)
要做的事情,因为Enumerable#first
返回最多为n,并且不会填充nils。这是不是一个错误,但它是意外的行为,因为可枚举的first
集使用该名称的方法预期的行为,但是,这是NodeSet#first
,不Enumerable#first
,所以它做什么,它直到引入nokogiri作者改变它。 (你可以看到为什么,如果你看一下源为特定的方法它发生。)
相反,切片NODESET 不显示预期的行为:
doc.search('p')[0..1] # => [#<Nokogiri::XML::Element:0x3fe3a28d2848 name="p" children=[#<Nokogiri::XML::Text:0x3fe3a28c7b50 "foo">]>]
doc.search('p')[0..1].size # => 1
doc.search('p')[0, 2] # => [#<Nokogiri::XML::Element:0x3fe3a28d2848 name="p" children=[#<Nokogiri::XML::Text:0x3fe3a28c7b50 "foo">]>]
doc.search('p')[0, 2].size # => 1
所以,不要使用NodeSet#first(n)
,使用片形式NodeSet#[]
。
应用的是,我会写的代码是这样的:
require 'nokogiri'
require 'open-uri'
URL = 'http://themagicway.taobao.com/search.htm?&search=y&orderType=newOn_desc'
doc = Nokogiri::HTML(open(URL))
hrefs = doc.css(".main-wrap .item .detail a[href]")[0..29].map { |anchors|
anchors['href']
}
puts hrefs.size
puts hrefs
# >> 24
# >> http://item.taobao.com/item.htm?id=41249522884
# >> http://item.taobao.com/item.htm?id=40369253621
# >> http://item.taobao.com/item.htm?id=40384876796
# >> http://item.taobao.com/item.htm?id=40352486259
# >> http://item.taobao.com/item.htm?id=40384968205
# >> http://item.taobao.com/item.htm?id=40384816312
# >> http://item.taobao.com/item.htm?id=40384600507
# >> http://item.taobao.com/item.htm?id=39973451949
# >> http://item.taobao.com/item.htm?id=39861209551
# >> http://item.taobao.com/item.htm?id=39545678869
# >> http://item.taobao.com/item.htm?id=39535371171
# >> http://item.taobao.com/item.htm?id=39509186150
# >> http://item.taobao.com/item.htm?id=38973412667
# >> http://item.taobao.com/item.htm?id=38910499863
# >> http://item.taobao.com/item.htm?id=38942960787
# >> http://item.taobao.com/item.htm?id=38910403350
# >> http://item.taobao.com/item.htm?id=38843789106
# >> http://item.taobao.com/item.htm?id=38843517455
# >> http://item.taobao.com/item.htm?id=38854788276
# >> http://item.taobao.com/item.htm?id=38825442050
# >> http://item.taobao.com/item.htm?id=38630599372
# >> http://item.taobao.com/item.htm?id=38346270714
# >> http://item.taobao.com/item.htm?id=38357729988
# >> http://item.taobao.com/item.htm?id=38345374874
试试这个
doc.css(".tweet").first(fetch_number).each do |item|
title = item.css("a")[0]['title'] rescue nil
end
让我知道它的工作原理或不?它不会显示错误
尝试compact
。
[1, nil, 2, nil, 3] # => [1, 2, 3]
http://www.ruby-doc.org/core-2.1.3/Array.html#method-i-compact
(即:first(fetch_number).compact.each do |item|
)
使用'compact'是一个bandaid来修补真正的问题,它没有使用适当的选择器。修复选择器和nils将消失,消除使用'compact'的需要。 – 2014-10-02 23:58:52
非常感谢。我希望我能同时接受2个答案。很有帮助! – cqcn1991 2014-10-03 13:39:03
真正的问题是这样的。我想获得一页20个项目。所以我用'first(20)'编写一个选择器。但是,它可能只有15个项目。所以剩余的20个阵列将有15个项目+ 5个零。我不觉得这可以通过使用更好的选择器来改进,而是将“第一(20)”更改为更合适的方式。但我不知道如何。 – cqcn1991 2014-10-03 13:50:18
'[] .first(2)#=> []'。除非你不正确地处理数组,否则你不能得到“15 + 5无”,你只能得到15。这是基于很多经验处理网站。所以,问题不在于你如何请求20,而是你在做什么。 – 2014-10-03 16:41:03