【问题标题】:How to grab element content with Nokogiri using SAX如何使用 SAX 通过 Nokogiri 抓取元素内容
【发布时间】:2012-03-31 06:07:34
【问题描述】:

我想从一个网站解析几千个 XML 文件(我有权限) 并且必须使用 SAX 来避免将文件加载到内存中。然后将它们保存到 CSV 文件中。

xml 文件如下所示:

<?xml version="1.0" encoding="UTF-8"?><educationInfo xmlns="http://skolverket.se/education/info/1.2" xmlns:ct="http://skolverket.se/education/commontypes/1.2" xmlns:nya="http://vhs.se/NyA-emil-extensions" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expires="2013-08-01" id="info.uh.su.HIA80D" lastEdited="2011-10-13T10:10:05" xsi:schemaLocation="http://skolverket.se/education/info/1.2 educationinfo.xsd">
  <titles>
    <title xml:lang="sv">Arkivvetenskap</title>
    <title xml:lang="en">Archival science</title>
  </titles>
  <identifier>HIA80D</identifier>
  <educationLevelDetails>
    <typeOfLevel>uoh</typeOfLevel>
    <typeOfResponsibleBody>statlig</typeOfResponsibleBody>
    <academic>
      <course>
        <type>avancerad</type>
      </course>
    </academic>
  </educationLevelDetails>
  <credits>
    <exact>60</exact>
  </credits>
  <degrees>
    <degree>Ingen examen</degree>
  </degrees>
  <prerequisites>
    <academic>uh</academic>
  </prerequisites>
  <subjects>
    <subject>
      <code source="vhs">10.300</code>
    </subject>
  </subjects>
  <descriptions>
    <ct:description xml:lang="sv">
      <ct:text>Arkivvetenskap rör villkoren för befintliga arkiv och modern arkivbildning med fokus på arkivarieyrkets arbetsuppgifter: bevara, tillgängliggöra och styra information. Under ett år behandlas bl a informations- och dokumenthantering, arkivredovisning, gallring, lagstiftning och arkivteori. I kursen ingår praktik, där man under handledning får arbeta med olika arkivarieuppgifter.</ct:text>
    </ct:description>
  </descriptions>
</educationInfo> 

我使用此代码模板,请检查我的 cmets 是否有问题:

class InfoData  < Nokogiri::XML::SAX::Document

  def initialize
    # do one-time setup here, called as part of Class.new
    # But what should I use hashes or arrays?
  end

  def start_element(name, attributes = [])
  # check the element name here and create an active record object if appropriate
  # How do I grab specific element like: ct:text ?
  # how do I grab root-element?
  end

  def characters(s)
     # save the characters that appear here and possibly use them in the current tag object
  end

  def end_element(name)
     # check the tag name and possibly use the characters you've collected
     # and save your activerecord object now
  end

end

parser = Nokogiri::XML::SAX::Parser.new(InfoData.new)

# How do I parse every xml-link? 
parser.parse_file('')

我写了这个方法来获取链接,但不知道在类中的什么地方使用它或者我是否应该在那里使用它:

@items = Set.new 
def get_links(url)
  doc = Nokogiri::HTML(open(url))
  doc.xpath('//a/@href').each do |url|
  item = {}
  item[:url] = url.content
  items << item
end

【问题讨论】:

  • 如果那个 XML 样本是一个完整的 XML 文件,我会使用 DOM,而不是 SAX,因为它更容易一些。如今,大多数主机都有数 GB 的 RAM,这使得 SAX 变得不那么重要了。 SAX 将更快地处理 BIG XML 文件,但您的开发时间可能会更长。
  • @theTinMan 我尝试使用 DOM 解析它,但它不起作用。它大约有 46000 个 xml 文件。它使用 SAX 解析的正确方法..

标签: ruby nokogiri sax web-crawler


【解决方案1】:
require 'nokogiri'

class LinkGrabber < Nokogiri::XML::SAX::Document
  def start_element(name, attrs = [])
    if name == 'a'
      puts Hash[attrs]['href']
    end
  end
end

parser = Nokogiri::XML::SAX::Parser.new(LinkGrabber.new)
parser.parse(File.read(ARGV[0], 'rb'))

现在您可以在管道中使用它:

find . -name "*.xml" -print0 | xargs -P 20 -0 -L 1 ruby parse.rb > links

但是每次都会启动 ruby​​。所以你最好使用jruby (无论如何更快)和threach。

require 'threach'
require 'find'
require 'nokogiri'

class LinkGrabber < Nokogiri::XML::SAX::Document
  def start_element(name, attrs = [])
    if name == 'a'
      puts Hash[attrs]['href']
    end
  end
end

# let's hope it's threadsave
parser = Nokogiri::XML::SAX::Parser.new(LinkGrabber.new)
Find.find(ARGV[0]).threach do |path|
  next unless File.file?(path)
  parser.parse(File.read(path))
end

【讨论】:

  • 很棒的伙伴。什么是管道,您是解析 XML 文档还是仅解析链接?
  • SAX 的那部分采用名称为'a' 和puts 的所有元素的'href' 属性。管道包含一些 xargs 和并行处理魔法,我建议使用 jruby 解决方案,因为它是纯 ruby​​。用普通的 ruby​​ 运行它是没有用的,因为 MRI 不支持真正的线程。使用 jruby,您可以使用所有内核。
  • 所以这个解析器只用于抓取链接还是用于每个 xml?你能告诉我你是如何获取诸如此类的元素的吗:标题、学位和主题并将 dem 存储在哈希中..
  • 给我一个示例输入和一个示例输出。
  • 如果您在此处查看我的旧 s.o 问题:stackoverflow.com/questions/9573997/how-to-crawl-the-right-way/…,您会看到我的输入和输出示例。但是 DOM 解析不适​​用于我的项目。
【解决方案2】:

也许这可行:

   require 'open-uri'

   def get_links(url)

          doc = Nokogiri::HTML(open(url))

          doc.xpath('//a/@href').each do |href|

            parser.parse_io(open(href))

          end

    end

【讨论】:

  • Nokogiri::HTML(open(url)) 对于 XML 文档是错误的。 Nokogiri::HTML 放宽了解析器以允许 HTML 臭名昭著的缺乏标准。相反,使用 Nokogiri::XML() 解析 XML 以使用严格解析器。
  • 在 SAX 中没有 #xpath。这就是 DOM。
猜你喜欢
  • 1970-01-01
  • 2011-05-06
  • 2013-07-19
  • 1970-01-01
  • 1970-01-01
  • 2017-08-03
  • 1970-01-01
  • 2019-11-23
  • 2023-03-11
相关资源
最近更新 更多