我曾经使用以下命令来获取网页的所有链接,然后获取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
或者一个路径&网络感知工具,例如xidel
或saxon-lint
:
xidel -se '//a/@href' <URL>
saxon-lint --html --xpath 'string-join(//a/@href, "^M")' <URL>
^M
是Control+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
生成的网页
您甚至可以XPath
在puppeteer
JavaScript 脚本
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
您可以使用-s
curl 的参数,它用于安静模式。它不会显示进度表或错误消息。
答案4
问题在于,curl 将其输出发送到STDERR
,而|
继续传递STDOUT
。请参阅此处的示例。
两种可能的解决方案是:
- 通过管道传输
STDERR
到STDOUT
,然后通过管道将其传输到 grep。curl -v http://vimcasts.org/episodes/archive/ 2>&1 | grep archive
- 使用
--stderr
标志并给它一个连字符作为参数。这将告诉curl 使用STDOUT
它。curl -v --stderr - http://vimcasts.org/episodes/archive/ | grep archive