【问题标题】:wget download not completing all pageswget下载未完成所有页面
【发布时间】:2012-06-02 10:06:31
【问题描述】:

我需要在 Linux 上下载超过 30k 的页面,我想我可以用一个简单的 bash 脚本 + wget 来做到这一点,这就是我想出的:

#!/bin/bash

start_time=$(date +%s)
for i in {1..30802}
do
        echo "Downloading page http://www.domain.com/page:$i"
        wget "http://www.domain.com/page:$i" -q -o /dev/null -b -O pages/$i
        running=$(ps -ef | grep wget | wc -l)
        while [ $running -gt 1000 ]
        do
                running=$(ps -ef | grep wget | wc -l)
                echo "Current running $running process."
                sleep 1;
        done
done

while [ $running -gt 1 ]
do
        running=$(ps -ef | grep wget | wc -l)
        echo "Waiting for all the process to end..."
        sleep 10;
done

finish_time=$(date +%s)
echo "Time duration: $((finish_time - start_time)) secs."

某些页面没有完全下载!

  • 由于上面的代码会使1k wget并行运行进程和 等到它降低来添加更多的过程,可能是我 实际上用尽了所有可用的互联网链接?

  • 我怎样才能使它更可靠以确保页面实际上是 是否正确下载?

编辑:

  • 我听说 curl 是下载页面的更好选择是 真的吗?

【问题讨论】:

  • 1k 并发连接可能有点过头了...而且您没有检查 wget 的返回码...
  • 同意 Scottymac。如果你有 100 个并发连接,你有同样的问题吗?祝你好运。
  • @Scottymac,shellter 感谢您指出这一点我也同意我可能做得过火,但我需要它能够在 3 小时内获得所有页面,这就是我正在寻找的原因使用 bash 脚本 + Linux 上可用的任何东西进行优化的一种方法或某种可靠的方法。目前 1k 进程需要 2 小时 21 分钟。

标签: linux bash curl for-loop wget


【解决方案1】:

以下是针对您的情况的可能解决方案:

1) 将调用 wget 的方式更改为:

(wget "http://www.domain.com/page:$i" -q -o /dev/null -O pages/$i || touch $i.bad) &

2) 脚本完成后,搜索所有 *.bad 文件并为每个文件重新启动 wget。在新的重试之前删除对应的.bad文件。

3) 直到没有*.bad 文件存在为止。

这是一般的想法。希望对您有所帮助!

编辑:

对于wget进程消失、被杀死或突然结束的情况,有一个可能的细化:

(wget "http://www.domain.com/page:$i" -q -o /dev/null -O pages/$i || touch $i.bad && touch $i.ok) &

然后你就可以分析一下是某个页面已经下载完成还是wget没有结束。

编辑 2:

经过一些测试和挖掘,我发现我之前的提案有缺陷。条件句的顺序必须互换

(wget "http://www.domain.com/page:$i" -q -o /dev/null -O pages/$i && touch $i.ok || touch $i.bad) &

所以,

  • 如果wget正确执行了下载(即它以OK返回码完成),那么必须有两个文件:下载的页面和.ok文件。

  • 如果下载失败(即wget返回一个KO返回码),那么肯定有.bad文件,并且可能是页面的部分下载。

无论如何,只有.ok 文件很重要:他们说下载已正确完成(从wget 的角度来看,我将在稍后讨论)。

如果没有找到特定页面的.ok文件,那么肯定没有下载,所以必须重试。

然后,我们进入程序中最微妙的部分:如果 Web 服务器作为对大量请求的响应,取消了那些他无法通过 HTTP 200 响应和零内容长度提供服务的请求,会发生什么?这将是避免网络复制或某种服务器攻击的好方法。

如果是这种情况,您必须查看响应的模式。会有一个.ok 文件,但下载页面的文件大小可能为零。

您可以通过以下方式检测那些零长度下载

filesize=$(cat $i.html | wc -c)

然后在.ok.bad文件的前一个过程中添加一些逻辑:

retry=0
if [ -f $i.bad ]
then
  retry=1
elif [ -f $i.ok ]
then
  if [ $filesize -eq 0 ]
  then
    retry=1
  fi
else
  retry=1
fi

if [ $retry -eq 1 ]
then
  # retry the download
fi

希望这有帮助!

【讨论】:

  • 非常好的答案,但问题是坏文件也有 html 内容,而且它们不是由诸如 500 或 404 之类的错误引起的,那么它如何识别一个坏文件呢?
  • 如果 wget 以“OK”结束,那么您必须 grep 或其他文件搜索可能的错误文件,但我不明白在哪种情况下您将获得“OK”来自wget 并且是错误的下载...
  • 如果问题是wget进程被突然杀死或取消,可以通过执行'(wget "http://www.domain.com/page:$i" -q -o /dev/null -O pages/$i || touch $i.bad && touch $i.ok) &修改算法如果没有ok文件,也重试。
  • 我刚刚运行了您的代码,它正在创建 2 个文件,其中一个是错误的,而第一页的长度均为 0。第二个示例也是如此,生成 3 个空文件。
  • 你删除了-b开关吗?
【解决方案2】:

我不知道你的连接是什么类型的,当前连接数过多会导致丢包。还要考虑服务器有什么样的连接。如果这不是内部服务器,则托管服务器的一方可能会认为这是拒绝服务攻击并过滤您的 IP。一个一个地做比较靠谱。瓶颈几乎总是互联网连接,你不能再快了。

【讨论】:

  • 服务器是我的,它在服务器上有一个 1GigE 端口/链接,在我端有一个 20Mbps 的连接。
  • 那么并行化并没有太多好处。您生成的所有进程都将等待数据包。一些数据包会丢失,您必须进行越来越多的重试,这会使情况变得更糟。
猜你喜欢
  • 2011-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多