【问题标题】:Parse html table using Nokogiri and Mechanize使用 Nokogiri 和 Mechanize 解析 html 表
【发布时间】:2012-02-03 16:00:23
【问题描述】:

我正在尝试使用以下代码从我们的电话提供商的 Web 应用程序中抓取通话记录,以将信息输入到我的 Ruby on Rails 应用程序中。

desc "Import incoming calls"
task :fetch_incomingcalls => :environment do

    # Logs into manage.phoneprovider.co.uk and retrieved list of incoming calls.
    require 'rubygems'
    require 'mechanize'
    require 'logger'

    # Create a new mechanize object
    agent = Mechanize.new { |a| a.log = Logger.new(STDERR) }

    # Load the Phone Provider website
    page = agent.get("https://manage.phoneprovider.co.uk/login")

    # Select the first form
    form = agent.page.forms.first
    form.username = 'username
    form.password = 'password

    # Submit the form
    page = form.submit form.buttons.first

    # Click on link called Call Logs
    page = agent.page.link_with(:text => "Call Logs").click

    # Click on link called Incoming Calls
    page = agent.page.link_with(:text => "Incoming Calls").click

    # Prints out table rows
    # puts doc.css('table > tr')

    # Print out the body as a test
    # puts page.body

end

从最后五行可以看出,我已经测试了“puts page.body”可以成功运行,并且上面的代码也可以正常运行。它成功登录,然后导航到呼叫日志,然后是来电。来电表如下所示:

| Timestamp    |    Source    |    Destination    |    Duration    |
| 03 Jan 13:40 |    12345678  |    12345679       |    00:01:01    |    
| 03 Jan 13:40 |    12345678  |    12345679       |    00:01:01    |    
| 03 Jan 13:40 |    12345678  |    12345679       |    00:01:01    |    
| 03 Jan 13:40 |    12345678  |    12345679       |    00:01:01    |    

由以下代码生成:

<thead>
<tr>
<td>Timestamp</td>
<td>Source</td>
<td>Destination</td>
<td>Duration</td>
<td>Cost</td>
<td class='centre'>Recording</td>
</tr>
</thead>
<tbody>
<tr class='o'>
<tr>
<td>03 Jan 13:40</td>
<td>12345678</td>
<td>12345679</td>
<td>00:01:14</td>
<td></td>
<td class='opt recording'>
</td>
</tr>
</tr>
<tr class='e'>
<tr>
<td>30 Dec 20:31</td>
<td>12345678</td>
<td>12345679</td>
<td>00:02:52</td>
<td></td>
<td class='opt recording'>
</td>
</tr>
</tr>
<tr class='o'>
<tr>
<td>24 Dec 00:03</td>
<td>12345678</td>
<td>12345679</td>
<td>00:00:09</td>
<td></td>
<td class='opt recording'>
</td>
</tr>
</tr>
<tr class='e'>
<tr>
<td>23 Dec 14:56</td>
<td>12345678</td>
<td>12345679</td>
<td>00:00:07</td>
<td></td>
<td class='opt recording'>
</td>
</tr>
</tr>
<tr class='o'>
<tr>
<td>21 Dec 13:26</td>
<td>07793770851</td>
<td>12345679</td>
<td>00:00:26</td>
<td></td>
<td class='opt recording'>
</td>
</tr>
</tr>

我正在尝试研究如何只选择我想要的单元格(时间戳、源、目标和持续时间)并输出它们。然后我可以担心将它们输出到数据库而不是终端中。

我曾尝试使用 Selector Gadget,但如果我选择多个,它只会显示 'td' 或 'tr:nth-child(6) td , tr:nth-child(2) td'。

任何帮助或指点将不胜感激!

【问题讨论】:

    标签: html ruby-on-rails html-table nokogiri mechanize


    【解决方案1】:

    表格中有一个模式,使用 XPath 很容易利用。具有所需信息的行的&lt;tr&gt; 标记缺少class 属性。幸运的是,XPath 提供了一些简单的逻辑操作,包括not()。这正好提供了我们需要的功能。

    一旦我们减少了要处理的行数,我们就可以使用 XPath 的 element[n] 选择器遍历行并提取必要列的文本。这里有一个重要的注意事项是 XPath 从 1 开始计算元素,因此表格行的第一列将是 td[1]

    使用 Nokogiri(和规范)的示例代码:

    require "rspec"
    require "nokogiri"
    
    HTML = <<HTML
    <table>
      <thead>
        <tr>
          <td>
            Timestamp
          </td>
          <td>
            Source
          </td>
          <td>
            Destination
          </td>
          <td>
            Duration
          </td>
          <td>
            Cost
          </td>
          <td class='centre'>
            Recording
          </td>
        </tr>
      </thead>
      <tbody>
        <tr class='o'>
          <td></td>
        </tr>
        <tr>
          <td>
            03 Jan 13:40
          </td>
          <td>
            12345678
          </td>
          <td>
            12345679
          </td>
          <td>
            00:01:14
          </td>
          <td></td>
          <td class='opt recording'></td>
        </tr>
        <tr class='e'>
          <td></td>
        </tr>
        <tr>
          <td>
            30 Dec 20:31
          </td>
          <td>
            12345678
          </td>
          <td>
            12345679
          </td>
          <td>
            00:02:52
          </td>
          <td></td>
          <td class='opt recording'></td>
        </tr>
        <tr class='o'>
          <td></td>
        </tr>
        <tr>
          <td>
            24 Dec 00:03
          </td>
          <td>
            12345678
          </td>
          <td>
            12345679
          </td>
          <td>
            00:00:09
          </td>
          <td></td>
          <td class='opt recording'></td>
        </tr>
        <tr class='e'>
          <td></td>
        </tr>
        <tr>
          <td>
            23 Dec 14:56
          </td>
          <td>
            12345678
          </td>
          <td>
            12345679
          </td>
          <td>
            00:00:07
          </td>
          <td></td>
          <td class='opt recording'></td>
        </tr>
        <tr class='o'>
          <td></td>
        </tr>
        <tr>
          <td>
            21 Dec 13:26
          </td>
          <td>
            07793770851
          </td>
          <td>
            12345679
          </td>
          <td>
            00:00:26
          </td>
          <td></td>
          <td class='opt recording'></td>
        </tr>
      </tbody>
    </table>
    HTML
    
    class TableExtractor  
      def extract_data html
        Nokogiri::HTML(html).xpath("//table/tbody/tr[not(@class)]").collect do |row|
          timestamp   = row.at("td[1]").text.strip
          source      = row.at("td[2]").text.strip
          destination = row.at("td[3]").text.strip
          duration    = row.at("td[4]").text.strip
          {:timestamp => timestamp, :source => source, :destination => destination, :duration => duration}
        end
      end
    end
    
    describe TableExtractor do
      before(:all) do
        @html = HTML
      end
    
      it "should extract the timestamp properly" do
        subject.extract_data(@html)[0][:timestamp].should eq "03 Jan 13:40"
      end
    
      it "should extract the source properly" do
        subject.extract_data(@html)[0][:source].should eq "12345678"
      end
    
      it "should extract the destination properly" do
        subject.extract_data(@html)[0][:destination].should eq "12345679"
      end
    
      it "should extract the duration properly" do
        subject.extract_data(@html)[0][:duration].should eq "00:01:14"
      end
    
      it "should extract all informational rows" do
        subject.extract_data(@html).count.should eq 5
      end
    end
    

    【讨论】:

    【解决方案2】:
    【解决方案3】:

    您应该能够使用 XPath 选择器从根(最坏的情况)到达您需要的确切节点。列出了将 XPath 与 Nokogiri 结合使用 here

    有关如何使用 XPath 访问所有元素的详细信息,请查看 here

    【讨论】:

    • 您链接的文档是否仅用于解析 xml 数据,还是也适用于 html 网页?
    • Yes.Check this one too nokogiri.org/tutorials/searching_a_xml_html_document.html
    猜你喜欢
    • 1970-01-01
    • 2012-04-23
    • 2011-11-16
    • 2011-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-08
    • 1970-01-01
    相关资源
    最近更新 更多