通过urllib和python下载图片

222
所以我正在尝试编写一个Python脚本,用于下载网络漫画并将其放在我的桌面文件夹中。在这里我发现了一些类似的程序可以实现类似的功能,但没有完全符合我的需求。我找到的最相似的一个是这个(http://bytes.com/topic/python/answers/850927-problem-using-urllib-download-images)。我尝试使用此代码:
>>> import urllib
>>> image = urllib.URLopener()
>>> image.retrieve("http://www.gunnerkrigg.com//comics/00000001.jpg","00000001.jpg")
('00000001.jpg', <httplib.HTTPMessage instance at 0x1457a80>)

我在电脑上搜索了一个文件名为“00000001.jpg”的文件,但我只找到了它的缓存图片。我甚至不确定它是否保存在我的电脑上。一旦我理解如何下载该文件,我认为我知道如何处理剩下的部分了。基本上只需使用for循环并将字符串拆分为“00000000”和“jpg”,并将“00000000”递增到最大数字,我需要某种方式来确定这个数字。您有关于如何完成此操作或正确下载文件的任何建议吗?
谢谢!
编辑6/15/10
以下是已完成的脚本,它可以将文件保存到您选择的任何目录中。由于某些奇怪的原因,文件未能下载,现在它们已经下载成功。如果您有任何清理建议,将不胜感激。我正在努力找出网站上有多少漫画,以便我只能获取最新的一本,而不是在发生一定数量的异常后程序退出。
import urllib
import os

comicCounter=len(os.listdir('/file'))+1  # reads the number of files in the folder to start downloading at the next comic
errorCount=0

def download_comic(url,comicName):
    """
    download a comic in the form of

    url = http://www.example.com
    comicName = '00000000.jpg'
    """
    image=urllib.URLopener()
    image.retrieve(url,comicName)  # download comicName at URL

while comicCounter <= 1000:  # not the most elegant solution
    os.chdir('/file')  # set where files download to
        try:
        if comicCounter < 10:  # needed to break into 10^n segments because comic names are a set of zeros followed by a number
            comicNumber=str('0000000'+str(comicCounter))  # string containing the eight digit comic number
            comicName=str(comicNumber+".jpg")  # string containing the file name
            url=str("http://www.gunnerkrigg.com//comics/"+comicName)  # creates the URL for the comic
            comicCounter+=1  # increments the comic counter to go to the next comic, must be before the download in case the download raises an exception
            download_comic(url,comicName)  # uses the function defined above to download the comic
            print url
        if 10 <= comicCounter < 100:
            comicNumber=str('000000'+str(comicCounter))
            comicName=str(comicNumber+".jpg")
            url=str("http://www.gunnerkrigg.com//comics/"+comicName)
            comicCounter+=1
            download_comic(url,comicName)
            print url
        if 100 <= comicCounter < 1000:
            comicNumber=str('00000'+str(comicCounter))
            comicName=str(comicNumber+".jpg")
            url=str("http://www.gunnerkrigg.com//comics/"+comicName)
            comicCounter+=1
            download_comic(url,comicName)
            print url
        else:  # quit the program if any number outside this range shows up
            quit
    except IOError:  # urllib raises an IOError for a 404 error, when the comic doesn't exist
        errorCount+=1  # add one to the error count
        if errorCount>3:  # if more than three errors occur during downloading, quit the program
            break
        else:
            print str("comic"+ ' ' + str(comicCounter) + ' ' + "does not exist")  # otherwise say that the certain comic number doesn't exist
print "all comics are up to date"  # prints if all comics are downloaded

我用这个程序将所有的.jpg文件合并成一个PDF。效果非常棒,而且是免费的! - Mike
10
考虑将你的解决方案发布为答案,并从问题中删除它。问题帖子用于提出问题,答案帖子用于回答 :-) - BartoszKP
如果有人仍在寻找它……现在它在urllib.request.URLopener()中。 - Filippo Mazza
1
@P0W 我已经移除了讨论标签。 - kmonsoor
这里的真正答案是使用 requests。 - AMC
显示剩余2条评论
20个回答

299

Python 2

使用 urllib.urlretrieve 方法。

import urllib
urllib.urlretrieve("http://www.gunnerkrigg.com//comics/00000001.jpg", "00000001.jpg")

Python 3

使用urllib.request.urlretrieve(Python 3的遗留接口之一,工作方式完全相同)。

import urllib.request
urllib.request.urlretrieve("http://www.gunnerkrigg.com//comics/00000001.jpg", "00000001.jpg")

当我将文件扩展名作为参数传递时,它似乎将其截断了(原始URL中存在该扩展名)。有任何想法是为什么? - JeffThompson
@JeffThompson,不是的。我的答案中的示例是否适用于您(我使用Python 2.7.8时可以)?请注意,它为本地文件明确指定了扩展名。 - Matthew Flaschen
1
是的,你的做法没错。我认为如果没有给出文件扩展名,那么文件的扩展名会被附加上去。当时这个想法对我来说很有道理,但现在我明白发生了什么。 - JeffThompson
为什么当我想将其下载到我的当前文件时,它似乎无法正常工作? - Charlie Parker
如果你从PyCharm的控制台运行这个程序,谁知道当前文件夹在哪里... - Charlie Parker

102

Python 2:

import urllib
f = open('00000001.jpg','wb')
f.write(urllib.urlopen('http://www.gunnerkrigg.com//comics/00000001.jpg').read())
f.close()

Python 3:

import urllib.request
f = open('00000001.jpg','wb')
f.write(urllib.request.urlopen('http://www.gunnerkrigg.com//comics/00000001.jpg').read())
f.close()

85

仅仅是为了记录,使用requests库。

import requests
f = open('00000001.jpg','wb')
f.write(requests.get('http://www.gunnerkrigg.com//comics/00000001.jpg').content)
f.close()

虽然它应该检查requests.get()错误。


2
即使这个解决方案没有使用urllib,你可能已经在你的Python脚本中使用了requests库(这是我在搜索时的情况),所以你也可以使用它来获取你的图片。 - Iam Zesh
感谢您将此答案发布在其他答案之上。最终我需要自定义标头才能使我的下载工作正常,而对requests库的指针则大大缩短了我让一切正常工作的过程。 - kuzzooroo
Python3 甚至无法使用 urllib,但 Requests 没有问题,而且已经加载了!我认为这是更好的选择。 - user3023715
@user3023715在Python 3中,您需要从urllib中导入request模块。请参考此处 - Yassine Sedrani

41

对于Python 3,您需要导入import urllib.request

import urllib.request 

urllib.request.urlretrieve(url, filename)

了解更多信息,请查看链接


15

@DiGMi的回答的Python 3版本:

from urllib import request
f = open('00000001.jpg', 'wb')
f.write(request.urlopen("http://www.gunnerkrigg.com/comics/00000001.jpg").read())
f.close()

10

我找到了这个答案,并以更可靠的方式进行编辑。

def download_photo(self, img_url, filename):
    try:
        image_on_web = urllib.urlopen(img_url)
        if image_on_web.headers.maintype == 'image':
            buf = image_on_web.read()
            path = os.getcwd() + DOWNLOADED_IMAGE_PATH
            file_path = "%s%s" % (path, filename)
            downloaded_image = file(file_path, "wb")
            downloaded_image.write(buf)
            downloaded_image.close()
            image_on_web.close()
        else:
            return False    
    except:
        return False
    return True

在下载过程中,您将不会获得任何其他资源或异常。


3
你应该移除 'self'。 - Euphe

8
如果您知道文件位于网站site的同一目录dir中,并且具有以下格式:filename_01.jpg,...,filename_10.jpg,则可以下载所有这些文件:
import requests

for x in range(1, 10):
    str1 = 'filename_%2.2d.jpg' % (x)
    str2 = 'http://site/dir/filename_%2.2d.jpg' % (x)

    f = open(str1, 'wb')
    f.write(requests.get(str2).content)
    f.close()

8

最简单的方法是使用.read()来读取部分或全部响应,然后将其写入您在已知良好位置打开的文件中。


5
也许你需要使用“User-Agent”:
import urllib2
opener = urllib2.build_opener()
opener.addheaders = [('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36')]
response = opener.open('http://google.com')
htmlData = response.read()
f = open('file.txt','w')
f.write(htmlData )
f.close()

也许页面不可用? - Alexander

4

使用urllib,您可以立即完成此操作。

import urllib.request

opener=urllib.request.build_opener()
opener.addheaders=[('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1941.0 Safari/537.36')]
urllib.request.install_opener(opener)

urllib.request.urlretrieve(URL, "images/0.jpg")

这需要放在顶部!添加头信息有助于解决403禁止错误。 - Gaurav Hazra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接