首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从外部网站下载数百万张图片

从外部网站下载数百万张图片
EN

Stack Overflow用户
提问于 2015-01-16 19:00:20
回答 3查看 1.1K关注 0票数 3

我在一个房地产网站上工作,我们将获得一个外部提要的大约100万份清单。假设每个清单都有10张与其相关的照片,大约有1000万张照片,我们需要将每一张照片下载到我们的服务器上,以避免“热链接”到它们。

我完全不知道如何有效地做这件事。我玩了一些数字,我得出结论,根据每幅图像下载速度为0.5秒,这可能需要58天以上的时间(从外部服务器下载10m张图像)。这显然是不可接受的。

每张照片的大小似乎都在50 be左右,但随着一些照片更大,更大,还有一些照片更小,照片的大小也会有所不同。

我一直在测试,只需使用:

代码语言:javascript
运行
复制
copy(http://www.external-site.com/image1.jpg, /path/to/folder/image1.jpg)

我也尝试过cURL、wget和其他。

我知道其他网站也会这么做,而且规模要大得多,但我一点也不知道他们是如何管理这类事情的,而不需要几个月的时间。

基于我们要接收的XML提要的Sudo代码。我们使用PHP解析XML:

代码语言:javascript
运行
复制
<listing>
    <listing_id>12345</listing_id>
    <listing_photos>
        <photo>http://example.com/photo1.jpg</photo>
        <photo>http://example.com/photo2.jpg</photo>
        <photo>http://example.com/photo3.jpg</photo>
        <photo>http://example.com/photo4.jpg</photo>
        <photo>http://example.com/photo5.jpg</photo>
        <photo>http://example.com/photo6.jpg</photo>
        <photo>http://example.com/photo7.jpg</photo>
        <photo>http://example.com/photo8.jpg</photo>
        <photo>http://example.com/photo9.jpg</photo>
        <photo>http://example.com/photo10.jpg</photo>
    </listing_photos>
</listing>

因此,我的脚本将遍历每一张照片以获得特定的列表,并将照片下载到我们的服务器,并将照片名插入到我们的照片数据库中(插入部分已经完成,没有问题)。

有什么想法吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-01-16 21:25:30

我很惊讶供应商不允许你热链接。事实是,你不会每个月服务每一张图片,所以为什么下载每一张图片呢?让你热连接是一个更好的利用每个人的带宽。

我管理一个包含数以百万计的项目的目录,其中的数据是本地的,但是图像大多是热链接的。有时,我们需要隐藏图像的来源,或者供应商要求我们缓存图像。为了实现这两个目标,我们使用一个代理。我们编写了自己的代理,但您可能会找到一些可以满足您需求的开源工具。

代理的工作方式是对加密的URL字符串进行加密和URL编码。于是http://yourvendor.com/img1.jpg变成了xtX957z。在我们的标记中,img标记类似于http://ourproxy.com/getImage.ashx?image=xtX957z

当我们的代理接收到图像请求时,它会解密图像URL。代理首先在磁盘上查找映像。我们从URL中派生出图像名,因此它正在查找类似于youvendorcom.img1.jpg的内容。如果代理无法在磁盘上找到映像,则使用解密的URL从供应商获取图像。然后,它将映像写入磁盘并将其服务于客户端。这种方法的优点是在没有浪费带宽的情况下按需运行。我只得到了我需要的图像,我只得到了一次。

票数 2
EN

Stack Overflow用户

发布于 2015-01-16 19:45:19

在你做这个之前

比如@BrokenBinar在评论中说。考虑到主机每秒可以提供多少请求。你不想在他们不知情的情况下向他们发出大量的请求。然后使用像睡眠这样的东西来限制您的请求,不管它们能提供多少。

卷曲多层

不管怎么说,用卷。答案有点重复,但还是抄袭了:

代码语言:javascript
运行
复制
$nodes = array($url1, $url2, $url3);
$node_count = count($nodes);

$curl_arr = array();
$master = curl_multi_init();

for($i = 0; $i < $node_count; $i++)
{
    $url =$nodes[$i];
    $curl_arr[$i] = curl_init($url);
    curl_setopt($curl_arr[$i], CURLOPT_RETURNTRANSFER, true);
    curl_multi_add_handle($master, $curl_arr[$i]);
}

do {
    curl_multi_exec($master,$running);
} while($running > 0);


for($i = 0; $i < $node_count; $i++)
{
    $results[] = curl_multi_getcontent  ( $curl_arr[$i]  );
}
print_r($results);

来自:PHP并行卷曲请求

另一种解决办法是:

丝线

代码语言:javascript
运行
复制
<?php

class WebRequest extends Stackable {
    public $request_url;
    public $response_body;

    public function __construct($request_url) {
        $this->request_url = $request_url;
    }

    public function run(){
        $this->response_body = file_get_contents(
            $this->request_url);
    }
}

class WebWorker extends Worker {
    public function run(){}
}

$list = array(
    new WebRequest("http://google.com"),
    new WebRequest("http://www.php.net")
);

$max = 8;
$threads = array();
$start = microtime(true);

/* start some workers */
while (@$thread++<$max) {
    $threads[$thread] = new WebWorker();
    $threads[$thread]->start();
}

/* stack the jobs onto workers */
foreach ($list as $job) {
    $threads[array_rand($threads)]->stack(
        $job);
}

/* wait for completion */
foreach ($threads as $thread) {
    $thread->shutdown();
}

$time = microtime(true) - $start;

/* tell you all about it */
printf("Fetched %d responses in %.3f seconds\n", count($list), $time);
$length = 0;
foreach ($list as $listed) {
    $length += strlen($listed["response_body"]);
}
printf("Total of %d bytes\n", $length);
?>

来源:线程和curl之间的PHP测试

你真的应该使用搜索功能,你知道:)

票数 2
EN

Stack Overflow用户

发布于 2015-01-16 19:45:42

您可以将所有链接保存到某个数据库表中(它将是您的“作业队列”),然后您可以创建一个脚本,该脚本在循环中获取作业并执行它(获取单个链接的图像并标记作业记录为已完成)--您可以多次执行该脚本。使用监督。因此,作业队列将并行处理。如果要放慢速度,您可以只执行另一个工作脚本(如果带宽没有使您慢下来)

如果任何脚本因为某种原因挂起,您可以轻松地再次运行它,只获得尚未下载的图像。顺便说一下,如果每个脚本失败,可以配置为自动重新启动每个脚本。

另一个优点是,您可以在任何时候通过supervisorctl检查这些脚本的输出。要检查还有多少图像在等待,您可以轻松地查询“作业队列”表。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27990937

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档