使用 Mechanize/Nogokiri 按文本搜索
Searching by text with Mechanize/Nogokiri
我正在尝试从许多与此类似的页面中抓取一些关于平均 GPA 和更多的数据:
http://www.ptcas.org/ptcas/public/Listing.aspx?seqn=3200&navid=10737426783
require 'mechanize'
agent = Mechanize.new
page = agent.get('http://www.ptcas.org/ptcas/public/Listing.aspx?seqn=3200&navid=10737426783')
gpa_headers = page.xpath('//h3[contains(text(), "GPA")]')
pp gpa_headers
我的问题是 gpa_headers
为 nil 但至少有一个 h3 元素包含 "GPA".
是什么导致了这个问题?我想可能是因为页面有动态元素,Mechanize 对此有一些问题,但我可以 puts page.body
并且输出包括:
... <h3 style="text-align:center;">GPA REQUIREMENT</h3> ...
根据我的理解,我使用的xpath应该可以找到。
如果有更好的方法,我也想知道。
这看起来是站点 DOM 结构的问题,因为它包含一个名为 style
的标签,该标签没有被关闭,看起来像这样:
<td colspan='7'><style='text-align:center;font-style:italic'>The
institution has been granted Candidate for Accreditation status by the
Commission on Accreditation in Physical Therapy Education (1111 North
Fairfax Street, Alexandria, VA, 22314; phone: 703.706.3245; email: <a
href='mailto:accreditation@apta.org'>accreditation@apta.org</a>).
Candidacy is not an accreditation status nor does it assure eventual
accreditation. Candidate for Accreditation is a pre-accreditation
status of affiliation with the Commission on Accreditation in Physical
Therapy Education that indicates the program is progressing toward
accreditation.</td>
如您所见,td
标签关闭但内部 style
从未关闭。
如果您不需要这部分代码,我建议您在尝试使用整个 response
之前删除它。我没有使用 ruby
的经验,但我会做类似的事情:
- 获取响应的原始正文。
- 将与此正则表达式
'(<style=\'.*)</td>'
匹配的部分替换为空字符串,或自行关闭标签。
- 使用这个新的响应主体。
现在您可以使用 xpath 选择器了。
eLRuLL 给出了上述问题的根源。这是我如何解决问题的示例:
require 'mechanize'
require 'nokogiri'
agent = Mechanize.new
page = agent.get('http://www.ptcas.org/ptcas/public/Listing.aspx?seqn=3200&navid=10737426783')
mangled_text = page.body
fixed_text = mangled_text.sub(/<style=.+?<\/td>/, "</td>")
page = Nokogiri::HTML(fixed_text)
gpa_headers = page.xpath('//h3[contains(text(), "GPA")]')
pp gpa_headers
这将 return 我在上面寻找的 header:
[#<Nokogiri::XML::Element:0x2b28a8ec0c38 name="h3" attributes=[#<Nokogiri::XML::Attr:0x2b28a8ec0bc0 name="style" value="text-align:center;">] children=[#<Nokogiri::XML::Text:0x2b28a8ec0774 "GPA REQUIREMENT">]>]
更可靠的解决方案是使用像 nokogumbo 这样的 HTML5 解析器:
require 'nokogumbo'
doc = Nokogiri::HTML5(page.body)
gpa_headers = doc.search('//h3[contains(text(), "GPA")]')
我正在尝试从许多与此类似的页面中抓取一些关于平均 GPA 和更多的数据:
http://www.ptcas.org/ptcas/public/Listing.aspx?seqn=3200&navid=10737426783
require 'mechanize'
agent = Mechanize.new
page = agent.get('http://www.ptcas.org/ptcas/public/Listing.aspx?seqn=3200&navid=10737426783')
gpa_headers = page.xpath('//h3[contains(text(), "GPA")]')
pp gpa_headers
我的问题是 gpa_headers
为 nil 但至少有一个 h3 元素包含 "GPA".
是什么导致了这个问题?我想可能是因为页面有动态元素,Mechanize 对此有一些问题,但我可以 puts page.body
并且输出包括:
... <h3 style="text-align:center;">GPA REQUIREMENT</h3> ...
根据我的理解,我使用的xpath应该可以找到。
如果有更好的方法,我也想知道。
这看起来是站点 DOM 结构的问题,因为它包含一个名为 style
的标签,该标签没有被关闭,看起来像这样:
<td colspan='7'><style='text-align:center;font-style:italic'>The institution has been granted Candidate for Accreditation status by the Commission on Accreditation in Physical Therapy Education (1111 North Fairfax Street, Alexandria, VA, 22314; phone: 703.706.3245; email: <a href='mailto:accreditation@apta.org'>accreditation@apta.org</a>). Candidacy is not an accreditation status nor does it assure eventual accreditation. Candidate for Accreditation is a pre-accreditation status of affiliation with the Commission on Accreditation in Physical Therapy Education that indicates the program is progressing toward accreditation.</td>
如您所见,td
标签关闭但内部 style
从未关闭。
如果您不需要这部分代码,我建议您在尝试使用整个 response
之前删除它。我没有使用 ruby
的经验,但我会做类似的事情:
- 获取响应的原始正文。
- 将与此正则表达式
'(<style=\'.*)</td>'
匹配的部分替换为空字符串,或自行关闭标签。 - 使用这个新的响应主体。
现在您可以使用 xpath 选择器了。
eLRuLL 给出了上述问题的根源。这是我如何解决问题的示例:
require 'mechanize'
require 'nokogiri'
agent = Mechanize.new
page = agent.get('http://www.ptcas.org/ptcas/public/Listing.aspx?seqn=3200&navid=10737426783')
mangled_text = page.body
fixed_text = mangled_text.sub(/<style=.+?<\/td>/, "</td>")
page = Nokogiri::HTML(fixed_text)
gpa_headers = page.xpath('//h3[contains(text(), "GPA")]')
pp gpa_headers
这将 return 我在上面寻找的 header:
[#<Nokogiri::XML::Element:0x2b28a8ec0c38 name="h3" attributes=[#<Nokogiri::XML::Attr:0x2b28a8ec0bc0 name="style" value="text-align:center;">] children=[#<Nokogiri::XML::Text:0x2b28a8ec0774 "GPA REQUIREMENT">]>]
更可靠的解决方案是使用像 nokogumbo 这样的 HTML5 解析器:
require 'nokogumbo'
doc = Nokogiri::HTML5(page.body)
gpa_headers = doc.search('//h3[contains(text(), "GPA")]')