Ruby 无法访问块内的Nokogiri元素
我成功运行了以下程序:Ruby 无法访问块内的Nokogiri元素,ruby,nokogiri,Ruby,Nokogiri,我成功运行了以下程序: require 'nokogiri' require 'open-uri' own = Nokogiri::HTML(open('https://www.sec.gov/cgi-bin/own-disp?action=getowner&CIK=0001513362')) own_table = own.css('table#transaction-report') p own_table.css('tr').css('td')[4].css('a').attr
require 'nokogiri'
require 'open-uri'
own = Nokogiri::HTML(open('https://www.sec.gov/cgi-bin/own-disp?action=getowner&CIK=0001513362'))
own_table = own.css('table#transaction-report')
p own_table.css('tr').css('td')[4].css('a').attr('href').value
=>“/Archives/edgar/data/0001513362/000162828016019444/0001628280-16-019444-index.htm”
但是,当我尝试在块中使用上面的元素时(如下面的代码所示),我得到了nil:NilClass的NoMethodError
我感到困惑,因为我认为块中的局部变量链接与上面代码中的对象相同
此外,如果我将下面链接的定义更改为:
link=row.css('td')[4]。类
我得到了一个没有错误的散列,表示link的值是Nokogiri::XML::Element
有人能解释一下,为什么我有一个Nokogiri::XML::Element对象,但不能在其上运行css方法。特别是当我可以在第一段代码中运行它时
require 'nokogiri'
require 'open-uri'
own = Nokogiri::HTML(open('https://www.sec.gov/cgi-bin/own-disp?action=getowner&CIK=0001513362'))
own_table = own.css('table#transaction-report')
own_table.css('tr').each do |row|
names = [:acq, :transaction_date, :execution_date, :issuer, :form, :transaction_type, :direct_or_indirect_ownership, :number_of_securities_transacted, :number_of_securities_owned, :line_number, :issuer_cik, :security_name, :url]
values = row.css('td').map(&:text)
link = row.css('td')[4].css('a').attr('href').value
values << link
hash = Hash[names.zip values]
puts hash
end
secown.rb:11:in `block in <main>': undefined method `css' for nil:NilClass (NoMethodError)
from /Users/piperwarrior/.rvm/gems/ruby-2.2.1/gems/nokogiri-1.6.7.2/lib/nokogiri/xml/node_set.rb:187:in `block in each'
from /Users/piperwarrior/.rvm/gems/ruby-2.2.1/gems/nokogiri-1.6.7.2/lib/nokogiri/xml/node_set.rb:186:in `upto'
from /Users/piperwarrior/.rvm/gems/ruby-2.2.1/gems/nokogiri-1.6.7.2/lib/nokogiri/xml/node_set.rb:186:in `each'
from secown.rb:8:in `<main>'
需要“nokogiri”
需要“打开uri”
own=Nokogiri::HTML(打开)https://www.sec.gov/cgi-bin/own-disp?action=getowner&CIK=0001513362'))
own#table=own.css('表#事务报告')
own_table.css('tr')。每行|
名称=[:acq,:交易日期,:执行日期,:发行人,:表格,:交易类型,:直接或间接所有权,:交易证券数量,:持有证券数量,:行号,:发行人cik,:证券名称,:url]
values=row.css('td').map(&:text)
link=row.css('td')[4].css('a').attr('href').value
值关键的洞察是,在第一种情况下,own_table.css('tr')
返回一个NodeSet
,.css('td')
找到该NodeSet中任何节点的所有td
,然后找到第四个节点(作为程序员来说,第五个是普通人:p)
第二个代码段将每一行单独视为一个节点
,然后查找所有后代td
,然后选择第四个
因此,如果你有这种结构:
tr id=1
td id=2
td id=3
tr id=4
td id=5
td id=6
td id=7
td id=8
td id=9
然后第一个代码片段将为您提供ID7TD(它是所有tr中的第四个td);第二个代码段将尝试在ID1TR中查找第四个td
,然后在ID4TR中查找第四个td
,但它会出错,因为ID1TR没有第四个td
编辑:具体地说,检查完URL后,第一个tr
没有td
;其他的都有12个。所以own_table.css('tr')[0].css('td')[4]。class
是NilClass
,而不是您报告的Nokogiri::XML::Element
。关键的洞察是,在第一种情况下,own_table.css('tr')
返回一个节点集
,.css('td'))
查找该节点集中任何节点的后代的所有td
,然后查找第四个节点(作为程序员,第五个是普通人:P)
第二个代码段将每一行单独视为一个节点
,然后查找所有后代td
,然后选择第四个
因此,如果你有这种结构:
tr id=1
td id=2
td id=3
tr id=4
td id=5
td id=6
td id=7
td id=8
td id=9
然后第一个代码片段将为您提供ID7TD(它是所有tr中的第四个td);第二个代码段将尝试在ID1TR中查找第四个td
,然后在ID4TR中查找第四个td
,但它会出错,因为ID1TR没有第四个td
编辑:具体地说,检查完URL后,第一个tr
没有td
;其他的都有12个。所以own_table.css('tr')[0].css('td')[4].class
是NilClass
,而不是您报告的Nokogiri::XML::Element
。考虑以下几点:
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
<html>
<body>
<div><span><p>foo</p></span></div>
<div id="bar"><span><p>bar</p></span></div>
</body>
</html>
EOT
css
,如search
和xpath
返回一个节点集,text
将连接所有返回节点的文本,使得从单个节点检索文本变得困难。而是使用:
doc.css('bar p').map(&:text)
它将返回一个数组,其中包含找到的每个节点的文本:
doc.css('div p').text
# => "foobar"
与:
doc.css('div p').map(&:text)
# => ["foo", "bar"]
另请参见“”。考虑一下:
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
<html>
<body>
<div><span><p>foo</p></span></div>
<div id="bar"><span><p>bar</p></span></div>
</body>
</html>
EOT
css
,如search
和xpath
返回一个节点集,text
将连接所有返回节点的文本,使得从单个节点检索文本变得困难。而是使用:
doc.css('bar p').map(&:text)
它将返回一个数组,其中包含找到的每个节点的文本:
doc.css('div p').text
# => "foobar"
与:
doc.css('div p').map(&:text)
# => ["foo", "bar"]
另请参见“”。我的意思是将block中的局部变量link更改为link=row.css('td')[4]。类给出Nokogiri::XML::element我知道您的意思。它适用于80行(具有12个td
的行);不适用于第一行(没有td
)。@Amadan是对的,第一行有一个th
,而不是td
,这是因为你得到了NoMethodError
values=row.css('td')。map(&:text)=>[]
@Amadan我通过使用带有索引的每个_忽略了第一行,只在索引时迭代!=0这就行了。我的意思是将block中的局部变量link改为link=row.css('td')[4]。类给出了Nokogiri::XML::element我知道你们的意思。它适用于80行(具有12个td
的行);不适用于第一行(没有td
)。@Amadan是对的,第一行有一个th
,而不是td
,这是因为你得到了NoMethodError
values=row.css('td')。map(&:text)=>[]
@Amadan我通过使用带有索引的每个_忽略了第一行,只在索引时迭代!=0成功了,请读“成功”。当询问代码问题时,我们需要最少的输入数据(本例中为HTML)来说明问题本身。不要要求我们去一个网站浏览整个页面,因为这会减慢我们对您的响应时间,并影响我们帮助他人的能力。您不需要使用css
或search
链接每个标记。而是使用更复杂的选择器,从一个地标跳到另一个地标,再跳到标记中的目标。这就不那么脆弱了。此外,在选择答案之前,您应该等待更长的时间。请阅读“”。当询问代码问题时,我们需要最少的输入数据(本例中为HTML)来说明问题本身。不要要求我们去一个网站,并通过阅读
doc.css('div p').map(&:text)
# => ["foo", "bar"]