bash - 从包含多个链接的 html 文件中提取文件名

bash - 从包含多个链接的 html 文件中提取文件名

我已经下载了一个由网页上的脚本自动生成的 html 文件。该文件包含多个链接,包括图像的链接我正在尝试提取图像的全名,例如

<a href="000000.jpg" title="image name.jpg" target="_blank">Image name.jpg</a>

从上面我想"Image name.jpg"存储在一个文件中。由于有数百个这样的名称,我解析该文件并存储每个名称,因为它出现了以下命令:

grep -i -E -o "target=\"_blank\">([[:graph:]]*)\.(jpg|png|gif|webm)" "$thread" | cut -f 2 -d '>' | sed 's/ /_/g' - > "$names"

其中“ $thread”是 html 文件的名称,“ $names”是作为输出的文件名列表。我使用“ cut”删除该'target="_blank">'部分,然后将空格转换为下划线。

由于文件中还有其他几个链接,我指定了要抓取的扩展名(图像和 webm)。其他一切都应该被忽略。我已经达到了只抓取这些链接的地步,但随后它错过了一些链接。

某些文件包含空格和非字母数字字符。如果我使用[[:print:]]which 应该涵盖所有这些情况,我什么也得不到,或者我得到一点<head>html 部分而没有其他。如果我使用[[:graph:][:space:]],我也什么也得不到。如果我只是使用[[:graph:]](如上所述)或者[[:alnum:][:punct:]]我可以获得包含字母数字/其他字符(例如“ filenamewith(parenthesis).jpg”)但不是空格的文件,反之亦然,[[:alnum:][:space:]]可以工作但忽略其他可打印字符(“ file name with spaces.jpg”可以工作但不能使用“with”) (括号、逗号或其他.jpg")。

据说[[:print:]]涵盖了所有情况,但我没有得到我需要的东西,如果我理解正确的话,

grep -E -o应该只匹配(根据上面的情况): *.jpg *.png *.gif*.webm

我尝试过grep有和没有-E/-o/-e不同的变化。

有任何想法吗?我正在使用 Arch Linux,grep 2.20,bash 4.3.18

答案1

最好的策略是使用合适的 html 解析器,它可以输出所有<a>标签的值。

这里xmlstarlet具体是一个 XML 解析器,您的 HTML 可能不是格式良好的 XML,但您可能会明白:

echo '<html>
<a href="000000.jpg" title="image name.jpg" target="_blank">Image name.jpg</a>
</html>' | xmlstarlet sel -t -v //a
Image name.jpg

答案2

你的正则表达式是

target="_blank">([[:graph:]]*)\.(jpg|png|gif|webm)

这与文字 text 匹配target="_blank">,后跟任意数量的非空白字符,最后带有四个字符串.jpg.png.gif或之一。.webm例如,grep 命令将输出以下行的粗体部分:

<一...target="_blank">某物.jpg</a>
<一...目标=“_blank”>a.gifted.child.txt</a>
<a … target="_blank">其他东西.jpg</a>
<一...target="_blank">某事.jpg</a>+more.jpg

如果你使用[[:print:]]而不是[[:graph:]],那么它会匹配类似的东西

<一...target="_blank">something.jpg</a> wibble wobble <a … target="_blank">something else.jpg</a>

target …线路上第一个匹配位和最后一个匹配扩展之间的所有内容都是匹配的。

您需要从匹配中排除 HTML 标记字符。

target="_blank">[^<>]*\.(jpg|png|gif|webm)</a>

使用 GNU grep,您可以使用该-P选项来获取构造Perl正则表达式,特别是零宽度断言允许您指定某些内容之前或之后是一些常量文本,而不在匹配部分中包含该文本。

grep -o -P '(?<target="_blank">)[^<>]*\.(jpg|png|gif|webm)(?=</a>)'

<a>如果存在意外的空格(例如标记和结束的, 或之间的换行符</a>),这仍然可能会失败。你会最好使用合适的 HTML 解析器

例如,在 Python 中美丽汤(未经测试):

import re, sys, BeautifulSoup
soup = BeautifulSoup(sys.stdin)
for hit in soup.find_all('a', target='_blank'):
    if re.match(r'.*\.(jpg|png|gif|webm)\Z', hit.string):
        print(hit.string)

类似的代码可以写成HTML::Parser在 Perl 中,野科切在红宝石等

答案3

我最终这样做了:

w3m -dump -T text/html "$thread" | grep -i -E -o 'File\:+([[:print:]]*)\.(jpg|png|webm|gif)'

w3m 清理代码,然后我可以 grep 查找文件名。 (我需要文字“文件:”部分来区分链接文件与其标题)。我确实需要 [[:print:]] 因为它捕获大多数空白、unicode 字符和其他可打印内容。

其按我的预期工作(尽管我仍然需要弄清楚如何防止覆盖同名文件,但那是另一天的战斗)

相关内容