mech-dump

mech-dump

我曾经使用以下命令来获取网页的所有链接,然后获取grep我想要的内容:

curl $URL 2>&1 | grep -o -E 'href="([^"#]+)"' | cut -d'"' -f2 | egrep $CMP-[0-9].[0-9].[0-9]$ | cut -d'-' -f3

直到昨天为止都表现得很好。我尝试运行curl自身,然后看到它返回:

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                               Dload  Upload   Total   Spent    Left  Speed
0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0

是否有任何可能的更新导致命令不起作用或什么?

编辑1:

wget我改变了对待问题的态度这个答案

wget -q $URL -O - | grep -o -E 'href="([^"#]+)"' | cut -d'"' -f2 | egrep $CMP-[0-9].[0-9].[0-9]$ | cut -d'-' -f3

但仍然不知道为什么curl方法突然停止工作。

答案1

警告:使用正则表达式解析 HTML在大多数情况下(如果不是全部)是坏的,因此请自行决定继续。


这应该可以做到:

curl -f -L URL | grep -Eo "https?://\S+?\""

或者

curl -f -L URL | grep -Eo '"(http|https)://[a-zA-Z0-9#~.*,/!?=+&_%:-]*"'

笔记:

  • 这没有考虑到不“完整”的链接,或者基本上是我所说的“半链接”,其中仅显示完整链接的一部分。我不记得在哪里看到过这个,但它应该出现在某些网站上的某些/特定 HTML 标签下。 编辑:吉尔·奎诺请为我错误地描述为“半链接”(正确的术语是相对链接)提供解决方案:
curl -Ls URL |  grep -oP 'href="\K[^"]+'
  • 这也不会“清理”不属于链接一部分的任何内容(例如:“&”字符等)。如果你想删除它,请制作/使用 sed 或其他类似的东西:
curl -f -L URL | grep -Eo "https?://\S+?\"" | sed 's/&.*//'
  • 最后,这并没有考虑到链接显示的所有可能方式。因此需要一定的网页结构或 HTML 知识。鉴于您不能/不显示上述结构或网页本身的示例,很难做出适用于它的答案,除非涉及更多 HTML 知识。

  • PS:这可能很明显,也可能不明显,但这也没有考虑动态生成的链接/URL(例如:PHP、JS 等),因为curl 主要适用于静态链接。

  • PS(2):如果您想使用更好的方法来解析 HTML,您应该使用更好的答案来自吉尔·奎诺这更适合一般(例如:完整)和更优化的 HTML 语法支持。

我绝不推荐使用正则表达式来解析 HTML,除非您知道自己在做什么或者需求非常有限(例如:只需要链接),就像在本例中一样。

答案2

使用正则表达式解析 HTML 是一个常见的讨论:这是一个坏主意。相反,使用适当的解析器:

mech-dump

mech-dump --links --absolute --agent-alias='Linux Mozilla' <URL>

它随软件包一起提供www-mechanize-perl(基于 Debian 的发行版)。

(作者:安迪·莱斯特ack,以及更多...的作者)

机械转储文档

xidel或者saxon-lint

或者一个&感知工具,例如xidelsaxon-lint

xidel -se '//a/@href' <URL>
saxon-lint --html --xpath 'string-join(//a/@href, "^M")' <URL>

^MControl+v Enter

xmlstarlet

curl -Ls <URL> |
    xmlstarlet format -H - 2>/dev/null |  # convert broken HTML to HTML 
    xmlstarlet sel -t -v '//a/@href' -    # parse the stream with XPath expression

javascript生成的网页

您甚至可以XPathpuppeteerJavaScript 脚本

const puppeteer = require('puppeteer');

var base_url = 'https://stackoverflow.com';

(async () => {
    const browser = await puppeteer.launch({
        headless: true,
    });
    
    // viewportSize
    await page.setViewport({'width': 1440, 'height': 900});

    // UA
    await page.setUserAgent('Mozilla/5.0 (X11; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0')

    // open main URL
    await page.goto(base_url, { waitUntil: 'networkidle2' }); 

    const xpath_expression = '//a[@href]';
    await page.waitForXPath(xpath_expression);
    const links = await page.$x(xpath_expression);
    const link_urls = await page.evaluate((...links) => {
        return links.map(e => e.href);
    }, ...links);

    await browser.close();

    link_urls.forEach((elt) => console.log(elt));

})();

用法:

nodejs retrieve_all_links.js

答案3

您可以使用-scurl 的参数,它用于安静模式。它不会显示进度表或错误消息。

答案4

问题在于,curl 将其输出发送到STDERR,而|继续传递STDOUT请参阅此处的示例

两种可能的解决方案是:

  1. 通过管道传输STDERRSTDOUT,然后通过管道将其传输到 grep。curl -v http://vimcasts.org/episodes/archive/ 2>&1 | grep archive
  2. 使用--stderr标志并给它一个连字符作为参数。这将告诉curl 使用STDOUT它。curl -v --stderr - http://vimcasts.org/episodes/archive/ | grep archive

相关内容