使用AWK / Grep / Bash从HTML中提取数据

时间:2014-05-19 20:39:08

标签: bash awk grep html-parsing

我正在尝试制作一个Bash脚本来从HTML页面中提取结果。 我实现了使用Curl获取页面内容,但下一步是解析输出,这是有问题的。

页面的有趣内容如下所示:

<div class="result">
    ...
                <div class="item">
                    <div class="item_title">ITEM 1</div>
                </div>
                ...                                 
                <div class="item_desc">
                    ITEM DESCRIPTION 1
                </div>
...              
</div>
<div class="result">
    ...
                <div class="item">
                    <div class="item_title">ITEM 2</div>
                </div>
                ...                                 
                <div class="item_desc">
                    ITEM DESCRIPTION 2
                </div>
    ...              
</div>

我想输出类似的内容:

ITEM1;ITEM DESCRIPTION 1
ITEM2;ITEM DESCRIPTION 2

我知道一点Grep,但是我无法想到让它在这里工作,也有些人告诉我使用Awk,这似乎最适合这种任务。

我很感激任何帮助。

非常感谢。

2 个答案:

答案 0 :(得分:3)

处理HTML的一个简单的最小程序,松散地,没有验证,并且容易被HTML中的变体混淆,是:

sed.script

/ *<div class="item_title">\(.*\)<\/div>/ { s//\1/; h; }
/ *<div class="item_desc">/,/<\/div>/ {
    /<div class="item_desc">/d
    /<\/div>/d
    s/^  *//
    G
    s/\(.*\)\n\(.*\)/\2;\1/p
}

第一行与项目标题行匹配。 s///命令仅捕获<div …></div>之间的部分; h复制到保留空间(内存)。

脚本的其余部分与项目描述<div>及其</div>之间的行匹配。前两行删除(忽略)<div></div>行。 s///删除前导空格; G在换行符后将保留空间附加到模式空间; s///p捕获换行符之前的部分(描述)和换行符之后的部分(保留空间中的标题),并用标题和描述替换它们,用分号分隔,并打印出来结果

实施例

$ sed -n -f sed.script items.html
ITEM 1;ITEM DESCRIPTION 1
ITEM 2;ITEM DESCRIPTION 2
$

注意-n;这意味着“除非被告知这样做,否则不要打印”。

您可以在没有脚本文件的情况下执行此操作,但如果您使用脚本文件,则不必担心。如果你小心的话,你甚至可以把它全部挤到一条线上。请注意,;之后的h对于BSD sed是必要的,并且对GNU sed无害但不重要。

修改

有各种各样的方法可以使它更接近防弹(但值得商榷是值得的)。例如:

/ *<div class="item_title">\(.*\)<\/div>/

可以修改为:

/^[[:space:]]*<div class="item_title">[[:space:]]*\(.*\)[[:space:]]*<\/div>[[:space:]]*$/

处理<div>组件之前,中间和之后的任意空白序列。对其他正则表达式重复广告恶心。你可以安排单词之间有单个空格。您可以安排将多行描述作为单行打印一次,而不是像现在一样单独打印每个行段。

您也可以将整个构造包装在文件中:

/^<div class="result">$/,/^<\/div>$/ {
    …script as before…
}

您可以重复这个想法,以便只在<div class="item"></div>等内选择项目标题。

答案 1 :(得分:2)

只需使用awk:

awk -F '<[^>]+>' '
    found { sub(/^[[:space:]]*/,";"); print title $0; found=0 }
    /<div class="item_title">/ { title=$2 }
    /<div class="item_desc">/  { found=1 }
' file
ITEM 1;ITEM DESCRIPTION 1
ITEM 2;ITEM DESCRIPTION 2