【问题标题】:Easiest way to extract the urls from an html page using sed or awk only仅使用 sed 或 awk 从 html 页面中提取 url 的最简单方法
【发布时间】:2010-12-25 06:31:57
【问题描述】:

我想从 html 文件的锚标记中提取 URL。 这需要使用 SED/AWK 在 BASH 中完成。请不要使用 perl。

最简单的方法是什么?

【问题讨论】:

  • 阅读本文并获得启发:stackoverflow.com/questions/1732348/…
  • 如果您不介意:无法保证您找到所有 url。 无法保证所有您找到的网址是有效的。 使用以下示例之一。如果你介意使用合适的工具来完成这项工作(perl、python、ruby)
  • 我之前的评论当然是针对您可能尝试的任何 easy 解决方案。 awk 足够强大,可以完成这项工作,理论上你可以在 awk 中实现 perl ...
  • 这是否像那些幸存者挑战之一,你必须活三天只吃白蚁?如果不是,严重的是,为什么要限制?每个现代系统都至少可以安装 Perl,然后你就拥有了整个网络

标签: html regex bash sed awk


【解决方案1】:

一个例子,因为你没有提供任何样本

awk 'BEGIN{
RS="</a>"
IGNORECASE=1
}
{
  for(o=1;o<=NF;o++){
    if ( $o ~ /href/){
      gsub(/.*href=\042/,"",$o)
      gsub(/\042.*/,"",$o)
      print $(o)
    }
  }
}' index.html

【讨论】:

  • 这是否适用于 'aktuell.de.selfhtml.org" target="_blank">SELFHTML aktuell'
  • 如果我说它有效(可能不是 100%,而是 99.99%),你会相信吗? :)。最好的办法是在各个页面上亲自试一试,然后看看。
  • 这确实奏效了,非常感谢这个很棒的 awk 包!
【解决方案2】:

您可以使用以下正则表达式轻松完成此操作,它非常适合查找 URL:

\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))

我是从John Gruber's article on how to find URLs in text那里拿到的。

这使您可以在文件 f.html 中查找所有 URL,如下所示:

cat f.html | grep -o \
    -E '\b(([\w-]+://?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))'

【讨论】:

  • 复杂,当 href 是这样时失败:... HREF="somewhere.com" ADD_DATE="1197958879" LAST_MODIFIED="1249591429"> ...
  • 我在 daringfireball 页面上尝试过,它找到了所有链接。其他解决方案可能会失败,因为 href= 可能位于常规文本中的某个位置。如果不根据其语法解析 HTML,就很难做到这一点。
  • 你不需要在 grep 之前有一只猫。只需将 f.html 放在 grep 的末尾
  • 而且 grep -o 可能由于某些 grep 版本中的错误而失败。
【解决方案3】:

我假设您想从一些 HTML 文本中提取 URL,而不是解析 HTML(正如其中一个 cmets 所建议的那样)。信不信由你,有人已经done this了。

OT:sed website 有很多很多很好的信息和许多有趣/疯狂的 sed 脚本。你甚至可以在 sed 中 play Sokoban

【讨论】:

  • 这是最简单最简单的答案。只是做例如wget http://sed.sourceforge.net/grabbag/scripts/list_urls.sed -O ~/bin/list_urls.sed &amp;&amp; chmod +x ~/bin/list_urls.sed 获取脚本,然后wget http://www.example.com -O - | ~/bin/list_urls.sed &gt; example.com.urls.txt 获取文本文件中的 url!
【解决方案4】:

你要求的:

$ wget -O - http://stackoverflow.com | \
  grep -io '<a href=['"'"'"][^"'"'"']*['"'"'"]' | \
  sed -e 's/^<a href=["'"'"']//i' -e 's/["'"'"']$//i'

这是一个粗略的工具,因此所有关于尝试使用正则表达式解析 HTML 的常见警告都适用。

【讨论】:

  • 几乎完美,但是这两种情况呢: 1. 你只匹配那些以 匹配我 2. 如果同一行有两个锚点我对原来的解决方案做了这个修改:codecat index.html | grep -o '' | sed -e 's/code
  • 谢谢,与上面提到的许多其他解决方案相比,在 Mac 上工作
【解决方案5】:

你也可以这样做(前提是你安装了 lynx)...

Lynx 版本

lynx -dump -listonly my.html

Lynx 版本 >= 2.8.8(@condit 提供)

lynx -dump -hiddenlinks=listonly my.html

【讨论】:

  • 在 Lynx 2.8.8 中,这已成为 lynx -dump -hiddenlinks=listonly my.html
【解决方案6】:

我对 Greg Bacon 解决方案做了一些更改

cat index.html | grep -o '<a .*href=.*>' | sed -e 's/<a /\n<a /g' | sed -e 's/<a .*href=['"'"'"]//' -e 's/["'"'"'].*$//' -e '/^$/ d'

这解决了两个问题:

  1. 我们正在匹配锚不以 href 作为第一个属性开始的情况
  2. 我们正在讨论在同一行中有多个锚点的可能性

【讨论】:

【解决方案7】:
grep "<a href=" sourcepage.html
  |sed "s/<a href/\\n<a href/g" 
  |sed 's/\"/\"><\/a>\n/2'
  |grep href
  |sort |uniq
  1. 第一个 grep 查找包含 url 的行。您可以添加更多元素 之后,如果您只想查看本地页面,则没有 http,但是 相对路径。
  2. 第一个 sed 将在每个带有 \n
  3. a href url 标记前添加一个换行符
  4. 第二个 sed 将通过用换行符替换 /a 标记来缩短行中第二个 " 之后的每个 url 两个 sed 都会在一行中为您提供每个 url,但是有垃圾,所以
  5. 第二个 grep href 清理混乱
  6. sort 和 uniq 将为您提供 sourcepage.html 中存在的每个现有 url 的一个实例

【讨论】:

  • 很好地分解了每个步骤应该做什么。
【解决方案8】:

你可以试试:

curl --silent -u "<username>:<password>" http://<NAGIOS_HOST/nagios/cgi-bin/status.cgi|grep 'extinfo.cgi?type=1&host='|grep "status"|awk -F'</A>' '{print $1}'|awk -F"'>" '{print $3"\t"$1}'|sed 's/<\/a>&nbsp;<\/td>//g'| column -c2 -t|awk '{print $1}'

【讨论】:

    【解决方案9】:

    使用Xidel - HTML/XML data extraction tool,可以通过以下方式完成:

    $ xidel --extract "//a/@href" http://example.com/
    

    转换为绝对 URL:

    $ xidel --extract "//a/resolve-uri(@href, base-uri())" http://example.com/
    

    【讨论】:

    • concat 需要 2 个参数,但这里只有一个(给出了基本 url)。 err:XPST0017: unknown function: concat #1 你的意思是: In module w3.org/2005/xpath-functions: concat #2-65535
    • @smihael:你说得对,这里是多余的。删除它。感谢您的关注!
    【解决方案10】:

    首先通过换行符 (\nhttp) 替换网址 (http) 的开头。然后你自己保证你的链接从行首开始,并且是行中唯一的 URL。

    其余的应该很简单,这里是一个例子:

    sed "s/http/\nhttp/g" &lt;(curl "http://www.cnn.com") | sed -n "s/\(^http[s]*:[a-Z0-9/.=?_-]*\)\(.*\)/\1/p"

    alias lsurls='_(){ sed "s/http/\nhttp/g" "${1}" | sed -n "s/\(^http[s]*:[a-Z0-9/.=?_-]*\)\(.*\)/\1/p"; }; _'

    【讨论】:

      【解决方案11】:

      扩展至kerkael's answer

      grep "<a href=" sourcepage.html
        |sed "s/<a href/\\n<a href/g" 
        |sed 's/\"/\"><\/a>\n/2'
        |grep href
        |sort |uniq
      # now adding some more
        |grep -v "<a href=\"#"
        |grep -v "<a href=\"../"
        |grep -v "<a href=\"http"
      

      我添加的第一个 grep 删除了本地书签的链接。

      第二个删除到上层的相对链接。

      第三个删除不以http开头的链接。

      根据您的具体要求选择使用其中的哪一种。

      【讨论】:

        【解决方案12】:

        为了更好的查看,我就是这样尝试的,创建 shell 文件并提供链接作为参数,它将创建 temp2.​​txt 文件。

        a=$1
        
        lynx -listonly -dump "$a" > temp
        
        awk 'FNR > 2 {print$2}' temp > temp2.txt
        
        rm temp
        
        >sh test.sh http://link.com
        

        【讨论】:

        • 我强烈建议使用管道而不是临时文件:lynx -listonly -dump "$url" | awk 'FNR > 2 {print$2}'
        【解决方案13】:

        这是我的第一篇文章,所以我尽量解释我为什么发布这个答案......

        1. 从前 7 个投票最多的答案中,有 4 个包含 GREP,即使 帖子明确表示“仅使用 sed 或 awk”。
        2. 即使帖子要求“请不要使用 perl”,由于之前的 点,因为在 grep 中使用 PERL 正则表达式。
        3. 因为这是最简单的方法(据我所知,并且是 required ) 在 BASH 中执行此操作。

        所以这是来自 GNU grep 2.28 的最简单的脚本:

        grep -Po 'href="\K.*?(?=")'
        

        关于 \K 开关,不是 info 是在 MAN 和 INFO 页面中建立的,所以我来here 寻求答案.... \K 开关摆脱以前的字符(和密钥本身)。 请记住遵循手册页中的建议: “这是高度实验性的, grep -P 可能会警告未实现的功能。”

        当然,您可以修改脚本以满足您的口味或需求,但我发现它非常适合帖子中的要求,也适合我们中的许多人......

        希望大家觉得它很有用。

        谢谢!!!

        【讨论】:

          【解决方案14】:

          在 bash 中,以下应该可以工作。请注意,它不使用 sed 或 awk,而是使用 trgrep,两者都非常标准且不是 perl ;-)

          $ cat source_file.html | tr '"' '\n' | tr "'" '\n' | grep -e '^https://' -e '^http://' -e'^//' | sort | uniq
          

          例如:

          $ curl "https://www.cnn.com" | tr '"' '\n' | tr "'" '\n' | grep -e '^https://' -e '^http://' -e'^//' | sort | uniq
          

          生成

          //s3.amazonaws.com/cnn-sponsored-content
          //twitter.com/cnn
          https://us.cnn.com
          https://www.cnn.com
          https://www.cnn.com/2018/10/27/us/new-york-hudson-river-bodies-identified/index.html\
          https://www.cnn.com/2018/11/01/tech/google-employee-walkout-andy-rubin/index.html\
          https://www.cnn.com/election/2016/results/exit-polls\
          https://www.cnn.com/profiles/frederik-pleitgen\
          https://www.facebook.com/cnn
          etc...
          

          【讨论】:

            【解决方案15】:

            避开awk/sed 要求:

            1. urlextract 就是为这样的任务而设计的 (documentation)。
            2. urlview 是一个交互式 CLI 解决方案 (github repo)。

            【讨论】:

              【解决方案16】:

              我专门使用 Bash 抓取网站以验证客户端链接的 http 状态,并在发现的错误时向他们报告。我发现 awk 和 sed 是最快和最容易理解的。给 OP 的道具。

              curl -Lk https://example.com/ | sed -r 's~(href="|src=")([^"]+).*~\n\1\2~g' | awk '/^(href|src)/,//'
              

              因为 sed 在一行上工作,这将确保所有 url 在新行上的格式正确,包括任何相对 url。第一个 sed 查找所有 href 和 src 属性并将每个属性放在一个新行上,同时删除该行的其余部分,包括链接末尾的结束双 qoute (")。

              请注意,我在 sed 中使用波浪号 (~) 作为替换的定义分隔符。这优于正斜杠 (/)。使用 html 时,正斜杠会混淆 sed 替换。

              awk 找到任何以 href 或 src 开头的行并输出它。

              一旦内容格式正确,就可以使用 awk 或 sed 来收集这些链接的任何子集。例如,您可能不想要 base64 图像,而是想要所有其他图像。我们的新代码如下所示:

              curl -Lk https://example.com/ | sed -r 's~(href="|src=")([^"]+).*~\n\1\2~g' | awk '/^(href|src)/,//' | awk '/^src="[^d]/,//'
              

              提取子集后,只需删除 href=" 或 src="

              sed -r 's~(href="|src=")~~g'
              

              这种方法非常快,我在 Bash 函数中使用这些函数来格式化数千个抓取页面的结果,以供希望有人一次性查看整个网站的客户使用。

              【讨论】:

                猜你喜欢
                • 2012-08-02
                • 1970-01-01
                • 2013-10-23
                • 2011-07-19
                • 2011-01-02
                • 1970-01-01
                • 2020-09-26
                • 2012-09-12
                • 1970-01-01
                相关资源
                最近更新 更多