从网页上传图片

1 投票
2 回答
1360 浏览
提问于 2025-04-16 15:24

我想实现一个功能,类似于这个 http://www.tineye.com/parse?url=yahoo.com - 允许用户从任何网页上传图片。

我面临的主要问题是,对于有很多图片的网页,处理起来太慢了。

我是在Django中做这个的(使用curl或urllib),按照以下步骤进行:

  1. 抓取网页的HTML内容(对于大页面大约需要1秒):

    file = urllib.urlopen(requested_url)
    html_string = file.read()
    
  2. 用HTML解析器(BeautifulSoup)解析这个内容,寻找标签,并把所有图片的地址(src)写入一个列表中。(对于大页面也大约需要1秒)

  3. 检查我列表中所有图片的大小,如果它们足够大,就把它们返回为json格式的响应(当网页上有大约80张图片时,这个过程非常慢,大约需要15秒)。这是这个函数的代码:


 def get_image_size(uri):
    file = urllib.urlopen(uri)
    p = ImageFile.Parser()
    data = file.read(1024)
    if not data:
        return None
    p.feed(data)
    if p.image:
        return p.image.size
    file.close()
    #not an image
    return None

如你所见,我并不是加载完整的图片来获取它的大小,而只加载1kb的数据。但当图片数量很多时,这仍然需要太多时间(我对每张找到的图片都调用这个函数一次)。

那么,我该如何让这个过程更快呢?

有没有办法不对每一张图片都发请求呢?

任何帮助都将非常感激。

谢谢!

2 个回答

1

你可以使用通过urllib2.urlopen返回的文件对象的headers属性(我不太清楚urllib的情况)。

这里有一个我写的测试。你可以看到,它的速度还挺快的,不过我想有些网站可能会阻止你发送太多重复的请求。

|milo|laurie|¥ cat test.py
import urllib2
uri = "http://download.thinkbroadband.com/1GB.zip"

def get_file_size(uri):
    file = urllib2.urlopen(uri)
    content_header, = [header for header in file.headers.headers if header.startswith("Content-Length")]
    _, str_length = content_header.split(':')
    length = int(str_length.strip())
    return length

if __name__ == "__main__":
    get_file_size(uri)
|milo|laurie|¥ time python2 test.py
python2 test.py  0.06s user 0.01s system 35% cpu 0.196 total
1

我能想到一些优化的方法:

  1. 在从文件流中读取文件时,边读边解析。
  2. 使用SAX解析器(这和上面的方法配合起来会很不错)。
  3. 使用HEAD请求来获取图片的大小。
  4. 使用队列来存放你的图片,然后用几个线程来连接并获取文件大小。

HEAD请求的例子:

$ telnet m.onet.pl 80
Trying 213.180.150.45...
Connected to m.onet.pl.
Escape character is '^]'.
HEAD /_m/33fb7563935e11c0cba62f504d91675f,59,29,134-68-525-303-0.jpg HTTP/1.1
host: m.onet.pl

HTTP/1.0 200 OK
Server: nginx/0.8.53
Date: Sat, 09 Apr 2011 18:32:44 GMT
Content-Type: image/jpeg
Content-Length: 37545
Last-Modified: Sat, 09 Apr 2011 18:29:22 GMT
Expires: Sat, 16 Apr 2011 18:32:44 GMT
Cache-Control: max-age=604800
Accept-Ranges: bytes
Age: 6575
X-Cache: HIT from emka1.m10r2.onet
Via: 1.1 emka1.m10r2.onet:80 (squid)
Connection: close

Connection closed by foreign host.

撰写回答