【问题标题】:Extract specific numeric data from curl output从 curl 输出中提取特定的数字数据
【发布时间】:2013-11-12 05:34:51
【问题描述】:

"curl -s http://122.160.230.125:8080/gbod/gb_on_demand.do | head -115 | tail -3" 的输出如下

<li>Balance quota:&nbsp;&nbsp;&nbsp;78.26&nbsp;GB</li>
<li>High speed data limit:&nbsp;&nbsp;&nbsp;80.0&nbsp;GB</li>
<li>No. of days left in the current bill cycle:&nbsp;&nbsp;&nbsp;28</li>

curl -s http://122.160.230.125:8080/gbod/gb_on_demand.do | head -115 | tail -3 | awk '{gsub (/&amp;nbsp;/, " "); gsub (/\&lt;li&gt;/, ""); gsub (/\&lt;\/li&gt;/, " "); print}' 给出了

Balance quota:   78.26 GB
High speed data limit:   80.0 GB
No. of days left in the current bill cycle:   28

如何只提取每行的数字数据?另外,有没有更好的方法来提取这些数据?

【问题讨论】:

  • 欢迎来到 StackOverflow.com。请更新您的个人资料以包含您的姓名。然后该名称将显示在您的徽章上,您无需在每个问题中都包含它。如果您完成个人资料,还可以获得徽章。

标签: python shell curl awk


【解决方案1】:

使用行数和正则表达式来解析 HTML 非常笨拙且非常脆弱。

但是如果你想扩展你已经在做的事情,那么健壮性就该死,你只需要一个简单的正则表达式来匹配数字:

curl -s http://122.160.230.125:8080/gbod/gb_on_demand.do | 
    head -115 | tail -3 | 
    awk '{gsub (/&nbsp;/, " "); gsub (/\<li>/, ""); gsub (/\<\/li>/, " "); print} |
    grep -o -E -e '[0-9][0-9.]+'

(我永远不记得我是否拥有适用于所有 grep 变体的标志。这绝对适用于 BSD grep;如果它不适用于你的,标志是 -o 只打印匹配而不是整行,-E 使用扩展的正则表达式而不是基本的,当然-e 来指定模式。)

【讨论】:

  • 我认为你的正则表达式有问题。它允许多个小数点。所以9……也会出现。 (更不用说点本身是一个特殊字符,可以匹配任何字符)我认为正确的正则表达式是'[0-9]*\.?[0-9]+'
  • @Chandranshu:当然,但我们谈论的代码和head -115 | tail -3 一样脆弱,所以我认为我们可以假设它看起来非常接近 OP 发布的内容,或者它将有很多更糟糕的问题。所以最好保持简单。同时,您的正则表达式仍然不正确 - 它无法处理 -4242.1e6 或许多其他有效数字。
【解决方案2】:

如果您想要一些不那么脆弱的东西,而不是依赖于您想要的行恰好位于第 113-115 行,这里有一些 Python 代码使用 BeautifulSoup 更好地完成同样的事情。

在不知道您的源文件是什么样子的情况下,我不得不做出很多假设。特别是,我假设您想从文件中的 every &lt;li&gt; 标记中提取数字。如果您只想从具有数字的&lt;li&gt; 标记中提取数字,或者仅从具有良好id 属性的特定&lt;ul&gt; 标记下的&lt;li&gt; 标记中提取数字,或者通过根的一些简单路径访问,或者其他什么,代码会有点不同。

import re
import urllib.request
import bs4

url = 'http://122.160.230.125:8080/gbod/gb_on_demand.do'
page = urllib.request.urlopen(url).read()
soup = bs4.beautifulSoup(page)
for li in soup.find_all('li'):
    print re.search('\d[\d.]+', li.text).group()

【讨论】:

  • 请参阅我对其他答案中使用的正则表达式的评论。
【解决方案3】:

一种方法:

curl -s http://122.160.230.125:8080/gbod/gb_on_demand.do | awk -F"[;&<]" 'NR>115-3 && NR<=115 {print $8}'
78.26
80.0
28

PS,如果您发布 curl -s http://122.160.230.125:8080/gbod/gb_on_demand.do 的输出,我们肯定可以清理更多。

【讨论】:

    【解决方案4】:

    假设响应是正确的 XML,您可以使用 xmlstarlet 来获取 &lt;li&gt; 元素的内容:

    http://xmlstar.sourceforge.net/doc/UG/xmlstarlet-ug.html#d0e270

    您必须了解如何定义查询,但恕我直言,这是值得的,因为您可能会发现您获得的知识对未来的 xml/html 查询很有帮助。

    有一些浏览器插件可帮助您定义所需的 css 选择器,以便准确选择所需的 li-items(而不是假设它们总是出现在同一行)。很遗憾,我现在找不到参考资料。

    从那里开始,按照其他建议使用 grep 或 sed 或 awk。

    【讨论】:

      【解决方案5】:

      按照建议,我尝试了以下方法并得到了我想要的东西。

      import urllib2
      import re
      from bs4 import BeautifulSoup
      url = 'http://122.160.230.125:8080/gbod/gb_on_demand.do'
      page = urllib2.urlopen(url).read()
      soup = BeautifulSoup(page)
      data = []
      for li in soup.find_all('li', limit=4):
              somevar =  re.search('\d[\d.]+', li.text).group();
              data.append(somevar)
      
      print "DSL Number: ", data[0]
      print "Balance: ", data[1], "GB"
      print "Limit: ", data[2], "GB"
      print "Days Left: ", data[3]
      

      对于我的项目,使用这个 python 脚本比使用 curl 更有意义。

      谢谢大家的帮助。

      【讨论】:

        猜你喜欢
        • 2023-03-29
        • 2015-09-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-22
        • 1970-01-01
        • 2020-07-24
        • 1970-01-01
        相关资源
        最近更新 更多