अनुरोधों का उपयोग करके छवि कैसे डाउनलोड करें


367

मैं अजगर के requestsमॉड्यूल का उपयोग करके वेब से एक छवि को डाउनलोड करने और सहेजने की कोशिश कर रहा हूं ।

यहाँ (काम) कोड मैं इस्तेमाल किया है:

img = urllib2.urlopen(settings.STATICMAP_URL.format(**data))
with open(path, 'w') as f:
    f.write(img.read())

यहां नया (गैर-काम करने वाला) कोड का उपयोग किया गया है requests:

r = requests.get(settings.STATICMAP_URL.format(**data))
if r.status_code == 200:
    img = r.raw.read()
    with open(path, 'w') as f:
        f.write(img)

क्या आप मेरी सहायता कर सकते हैं कि किस विशेषता का उपयोग करने के लिए प्रतिक्रिया से requests?


15
r.raw का उपयोग करने के लिए आपको स्ट्रीम सेट करने की आवश्यकता है = True
clsung

क्या इससे आपके सवाल का जवाब मिलता है? अजगर के साथ बड़ी फ़ाइल डाउनलोड करें
AMC

जवाबों:


516

आप या तो response.rawफ़ाइल ऑब्जेक्ट का उपयोग कर सकते हैं , या प्रतिक्रिया पर पुनरावृति कर सकते हैं।

response.rawफ़ाइल की तरह ऑब्जेक्ट का उपयोग करने के लिए , डिफ़ॉल्ट रूप से, संपीड़ित प्रतिक्रियाओं (GZIP या अपस्फीति के साथ) को डीकोड नहीं किया जाएगा। आप इसे वैसे भी decode_contentविशेषता के लिए सेट करने के लिए डिकम्प्रेस करने के लिए बाध्य कर सकते हैं True( requestsइसे Falseस्वयं डिकोडिंग को नियंत्रित करने के लिए सेट करता है)। तब आप shutil.copyfileobj()पायथन को डेटा को किसी फ़ाइल ऑब्जेक्ट में स्ट्रीम करने के लिए उपयोग कर सकते हैं :

import requests
import shutil

r = requests.get(settings.STATICMAP_URL.format(**data), stream=True)
if r.status_code == 200:
    with open(path, 'wb') as f:
        r.raw.decode_content = True
        shutil.copyfileobj(r.raw, f)        

प्रतिक्रिया का उपयोग करने के लिए एक लूप का उपयोग करना; इस तरह से यह सुनिश्चित करना कि डेटा इस चरण से विघटित है:

r = requests.get(settings.STATICMAP_URL.format(**data), stream=True)
if r.status_code == 200:
    with open(path, 'wb') as f:
        for chunk in r:
            f.write(chunk)

यह 128 बाइट विखंडू में डेटा पढ़ेगा; यदि आपको लगता है कि एक और हिस्सा आकार बेहतर काम करता है, तो कस्टम चंक आकार के साथ Response.iter_content()विधि का उपयोग करें :

r = requests.get(settings.STATICMAP_URL.format(**data), stream=True)
if r.status_code == 200:
    with open(path, 'wb') as f:
        for chunk in r.iter_content(1024):
            f.write(chunk)

ध्यान दें कि पायथन को सुनिश्चित करने के लिए आपको गंतव्य फ़ाइल को बाइनरी मोड में खोलने की आवश्यकता नहीं है और आपके लिए नई रूपरेखाओं का अनुवाद करें। हम यह भी सेट करते हैं stream=Trueताकि requestsपूरी छवि पहले मेमोरी में डाउनलोड न हो।


2
आपके उत्तर की मदद से मैं पाठ फ़ाइल में डेटा ढूँढने में सक्षम हो सकता हूं, जो चरण मैंने उपयोग किए हैं r2 = requests.post(r.url, data); print r2.content। लेकिन अब मैं भी जानना चाहता हूं filename। क्या उनका कोई साफ तरीका है? - वर्तमान में मुझे हेडर में फ़ाइल का नाम मिला है - r2.headers['content-disposition'] जो मुझे आउटपुट देता है: 'attachment; filename=DELS36532G290115.csi' मैं फ़ाइल नाम के लिए इस स्ट्रिंग को पार्स कर रहा हूं ... क्या उनका क्लीनर तरीका है?
बृजेश चौहान

6
@GrijeshChauhan: हाँ, content-dispositionहेडर यहाँ जाने का रास्ता है; cgi.parse_header()इसे पार्स करने और मापदंडों को प्राप्त करने के लिए उपयोग करें; params = cgi.parse_header(r2.headers['content-disposition'])[1]तब params['filename']
मार्टिन पीटर्स

1
डिफ़ॉल्ट 128 बाइट हिस्सा पाने के लिए आपको करने की जरूरत से अधिक पुनरावृति requests.Responseही : for chunk in r: ...1 बाइट विखंडू में वसीयत के iter_content()बिना कॉल करनाchunk_size
dtk

@dtk: धन्यवाद, मैं उत्तर को अपडेट करूंगा। पुनरावृत्ति के बाद मैं अपने उत्तर पोस्ट बदल
मार्टिजन पीटरर्स

1
@KumZ दो कारणों से: response.okकभी भी प्रलेखित नहीं किया गया था, और यह किसी भी 1xx, 2xx या 3xx स्थिति के लिए सही है, लेकिन केवल 200 प्रतिसाद में एक प्रतिक्रिया निकाय है।
मार्टिन पीटर्स

232

अनुरोध से एक फ़ाइल जैसी वस्तु प्राप्त करें और इसे एक फ़ाइल में कॉपी करें। यह भी एक ही बार में पूरी बात को स्मृति में पढ़ने से बचना होगा।

import shutil

import requests

url = 'http://example.com/img.png'
response = requests.get(url, stream=True)
with open('img.png', 'wb') as out_file:
    shutil.copyfileobj(response.raw, out_file)
del response

14
वापस आने और इसका जवाब देने के लिए बहुत बहुत धन्यवाद। हालांकि दूसरा जवाब काम करता है, यह एक छलांग है और सरलता से सीमा है
dkroy

11
यह ध्यान देने योग्य है कि कुछ सर्वर अपनी छवियों को GZIP करने के लिए सेट हैं क्योंकि छवियों में पहले से ही अपना संपीड़न है। यह उल्टा है, थोड़ा लाभ के साथ सीपीयू चक्र बर्बाद करता है। तो जबकि यह पाठ सामग्री के साथ एक मुद्दा हो सकता है, विशेष रूप से छवियों के साथ यह नहीं है।
phette23

3
वहाँ किसी भी तरह से हम मूल फ़ाइल नाम
mahes

@ phette23 यह भी ध्यान देने योग्य है कि Google PageSpeed ​​रिपोर्ट करता है और डिफ़ॉल्ट रूप से करता है।
वर्धमान

8
r.raw.decode_content = Trueपहले सेट करना चाहिए , shutil.copyfileobj(response.raw, out_file)क्योंकि by default, decode compressed responses (with GZIP or deflate)आपको एक शून्य-फ़ाइल छवि मिलेगी।
सिमिन जी

166

इसके बारे में कैसे, एक त्वरित समाधान।

import requests

url = "http://craphound.com/images/1006884_2adf8fc7.jpg"
response = requests.get(url)
if response.status_code == 200:
    with open("/Users/apple/Desktop/sample.jpg", 'wb') as f:
        f.write(response.content)

1
इससे तुम्हारा क्या मतलब है ! f = open("/Users/apple/Desktop/sample.jpg", 'wb')इस रास्ते से आपका क्या मतलब है !? मैं छवि डाउनलोड करना चाहता हूँ
मुस्कुराओ

3
उस पथ में एक फ़ाइल विवरणक खोलता है जिसमें छवि फ़ाइल लिखी जा सकती है।
किरान्बकृष्णा

@AndrewGlazkov मुझे लगता है कि यह उपयोग करने के लिए अधिक पायथोनिक होगाif response.ok:
EndermanAPM

5
response.ok किसी भी 1xx, 2xx या 3xx स्टेटस के लिए सही है, लेकिन केवल 200 रिस्पॉन्स में बॉडी का एक रिस्पॉन्स बॉडी है जैसा कि @Martijn Pieters ने ऊपर टिप्पणियों में बताया है
annndrey

75

मुझे अनुरोधों का उपयोग करके छवियों को डाउनलोड करने की समान आवश्यकता है। मैंने पहली बार मार्टिज़न पीटर के उत्तर की कोशिश की, और यह अच्छी तरह से काम करता है। लेकिन जब मैंने इस सरल फ़ंक्शन पर एक प्रोफ़ाइल किया, तो मैंने पाया कि यह urllib और urllib2 की तुलना में कई फ़ंक्शन कॉल का उपयोग करता है।

फिर मैंने अनुरोध मॉड्यूल के लेखक द्वारा सुझाए गए तरीके की कोशिश की :

import requests
from PIL import Image
# python2.x, use this instead  
# from StringIO import StringIO
# for python3.x,
from io import StringIO

r = requests.get('https://example.com/image.jpg')
i = Image.open(StringIO(r.content))

इसने फ़ंक्शन कॉल की संख्या को बहुत कम कर दिया, इस प्रकार मेरे आवेदन को गति दी। यहाँ मेरे प्रोफाइलर का कोड और परिणाम है।

#!/usr/bin/python
import requests
from StringIO import StringIO
from PIL import Image
import profile

def testRequest():
    image_name = 'test1.jpg'
    url = 'http://example.com/image.jpg'

    r = requests.get(url, stream=True)
    with open(image_name, 'wb') as f:
        for chunk in r.iter_content():
            f.write(chunk)

def testRequest2():
    image_name = 'test2.jpg'
    url = 'http://example.com/image.jpg'

    r = requests.get(url)

    i = Image.open(StringIO(r.content))
    i.save(image_name)

if __name__ == '__main__':
    profile.run('testUrllib()')
    profile.run('testUrllib2()')
    profile.run('testRequest()')

TestRequest के लिए परिणाम:

343080 function calls (343068 primitive calls) in 2.580 seconds

और testRequest2 के लिए परिणाम:

3129 function calls (3105 primitive calls) in 0.024 seconds

12
ऐसा इसलिए है क्योंकि आपने उस chunk_sizeपैरामीटर को निर्दिष्ट नहीं किया है जो 1 iter_contentको चूकता है , इसलिए परिणाम स्ट्रीम 1 बाइट पर एक समय में पुनरावृत्ति करता है। प्रलेखन python-requests.org/en/latest/api/… देखें ।
CadentOrange

9
यह पूरी प्रतिक्रिया को मेमोरी में लोड करता है, जिसे आप बचना चाहते हैं। यहां कोई उपयोग करने के लिए नहीं है PIL, बस with open(image_name, 'wb') as outfile: outfile.write(r.content)पर्याप्त है।
मार्टिन पीटर्स

3
PILमानक पुस्तकालय में भी यह कम पोर्टेबल नहीं है।
jjj

2
@ZhenyiZhang iter_contentधीमा है क्योंकि आपका chunk_sizeबहुत छोटा है, अगर आप इसे 100k तक बढ़ाते हैं तो यह बहुत तेज होगा।
वांग

यह सबसे अच्छा जवाब है। फ़ाइल को मेमोरी में पढ़ना हमेशा सबसे अच्छा नहीं होता है, लेकिन ओपी निर्दिष्ट "इमेजेस" का अर्थ है कि फाइलें आमतौर पर 4 एमबी से कम होंगी, इस प्रकार मेमोरी पर एक तुच्छ प्रभाव पड़ता है।
क्रिस कॉनन

51

यह उपयोग करने की तुलना में आसान हो सकता है requests। यह एकमात्र समय है जब मैं कभी requestsभी HTTP सामान का उपयोग नहीं करने का सुझाव दूंगा ।

दो लाइनर का उपयोग urllib:

>>> import urllib
>>> urllib.request.urlretrieve("http://www.example.com/songs/mp3.mp3", "mp3.mp3")

एक अच्छा पायथन मॉड्यूल भी है जिसका नाम wgetउपयोग करना बहुत आसान है। यहां मिला ।

यह डिजाइन की सादगी को दर्शाता है:

>>> import wget
>>> url = 'http://www.futurecrew.com/skaven/song_files/mp3/razorback.mp3'
>>> filename = wget.download(url)
100% [................................................] 3841532 / 3841532>
>> filename
'razorback.mp3'

का आनंद लें।

संपादित करें: आप outएक पथ निर्दिष्ट करने के लिए एक पैरामीटर भी जोड़ सकते हैं ।

>>> out_filepath = <output_filepath>    
>>> filename = wget.download(url, out=out_filepath)

मैंने wgetबिना किसी परेशानी के इस्तेमाल किया । उपयोग करने के लाभों को urllib3
बताने

1
ध्यान दें कि यह उत्तर पायथन 2 के लिए है। पायथन 3 के लिए आपको करने की आवश्यकता है urllib.request.urlretrieve("http://example.com", "file.ext")
कर्कश

1
धन्यवाद @ हस्की। अपडेट किया गया।
ब्लेयरग 23

28

निम्नलिखित कोड स्निपेट एक फ़ाइल डाउनलोड करता है।

फ़ाइल को उसके फ़ाइल नाम से निर्दिष्ट URL में सहेजा गया है।

import requests

url = "http://example.com/image.jpg"
filename = url.split("/")[-1]
r = requests.get(url, timeout=0.5)

if r.status_code == 200:
    with open(filename, 'wb') as f:
        f.write(r.content)

16

2 मुख्य तरीके हैं:

  1. .content(सरल / आधिकारिक) का उपयोग करना ( झेंग्झी झांग का जवाब देखें ):

    import io  # Note: io.BytesIO is StringIO.StringIO on Python2.
    import requests
    
    r = requests.get('http://lorempixel.com/400/200')
    r.raise_for_status()
    with io.BytesIO(r.content) as f:
        with Image.open(f) as img:
            img.show()
  2. का उपयोग करना .raw(देखें मार्टिज़न पीटरर्स का जवाब ):

    import requests
    
    r = requests.get('http://lorempixel.com/400/200', stream=True)
    r.raise_for_status()
    r.raw.decode_content = True  # Required to decompress gzip/deflate compressed responses.
    with PIL.Image.open(r.raw) as img:
        img.show()
    r.close()  # Safety when stream=True ensure the connection is released.

दोनों समय को ध्यान देने योग्य अंतर नहीं है।


2
मैं जवाब में से एक गुच्छा की कोशिश की, और अपने 1.जवाब (का उपयोग करते हुए io.BytesIOऔर Image) पहले एक है कि अजगर 3.6 पर मेरे लिए काम किया था। मत भूलना from PIL import Image(और pip install Pillow)।
23

.Content और .raw के बीच क्या अंतर है?
फॉक्सिरिस

13

छवि और अनुरोधों को आयात करना जितना आसान है

from PIL import Image
import requests

img = Image.open(requests.get(url, stream = True).raw)
img.save('img1.jpg')

4

यहां एक अधिक उपयोगकर्ता-अनुकूल उत्तर है जो अभी भी स्ट्रीमिंग का उपयोग करता है।

बस इन कार्यों को परिभाषित करें और कॉल करें getImage()। यह समान फ़ाइल नाम का उपयोग url के रूप में करेगा और वर्तमान निर्देशिका में डिफ़ॉल्ट रूप से लिखेगा, लेकिन दोनों को बदला जा सकता है।

import requests
from StringIO import StringIO
from PIL import Image

def createFilename(url, name, folder):
    dotSplit = url.split('.')
    if name == None:
        # use the same as the url
        slashSplit = dotSplit[-2].split('/')
        name = slashSplit[-1]
    ext = dotSplit[-1]
    file = '{}{}.{}'.format(folder, name, ext)
    return file

def getImage(url, name=None, folder='./'):
    file = createFilename(url, name, folder)
    with open(file, 'wb') as f:
        r = requests.get(url, stream=True)
        for block in r.iter_content(1024):
            if not block:
                break
            f.write(block)

def getImageFast(url, name=None, folder='./'):
    file = createFilename(url, name, folder)
    r = requests.get(url)
    i = Image.open(StringIO(r.content))
    i.save(file)

if __name__ == '__main__':
    # Uses Less Memory
    getImage('http://www.example.com/image.jpg')
    # Faster
    getImageFast('http://www.example.com/image.jpg')

requestकी हिम्मत getImage()उत्तर के आधार पर कर रहे हैं यहाँ और की हिम्मत getImageFast()उत्तर के आधार पर कर रहे हैं इसके बाद के संस्करण


3

मैं एक उत्तर पोस्ट करने जा रहा हूं क्योंकि मेरे पास टिप्पणी करने के लिए पर्याप्त प्रतिनिधि नहीं है, लेकिन Blairg23 द्वारा पोस्ट किए गए विग के साथ, आप पथ के लिए एक आउट पैरामीटर भी प्रदान कर सकते हैं।

 wget.download(url, out=path)

2

यह पहली प्रतिक्रिया है जो अनुरोधों के साथ एक बाइनरी फ़ाइल डाउनलोड करने के तरीके के बारे में Google खोजों के लिए आती है। यदि आपको अनुरोधों के साथ एक मनमानी फ़ाइल डाउनलोड करने की आवश्यकता है, तो आप इसका उपयोग कर सकते हैं:

import requests
url = 'https://s3.amazonaws.com/lab-data-collections/GoogleNews-vectors-negative300.bin.gz'
open('GoogleNews-vectors-negative300.bin.gz', 'wb').write(requests.get(url, allow_redirects=True).content)

1
अच्छा! इसका एक निहितार्थ भी है .close()। यह मेरा 2019 का सबसे अच्छा जवाब है।
डैनियल डब्ल्यू

2

मैंने इस तरह से इसे किया

import requests
from PIL import Image
from io import BytesIO

url = 'your_url'
files = {'file': ("C:/Users/shadow/Downloads/black.jpeg", open('C:/Users/shadow/Downloads/black.jpeg', 'rb'),'image/jpg')}
response = requests.post(url, files=files)

img = Image.open(BytesIO(response.content))
img.show()

-1

आप ऐसा कुछ कर सकते हैं:

import requests
import random

url = "https://images.pexels.com/photos/1308881/pexels-photo-1308881.jpeg? auto=compress&cs=tinysrgb&dpr=1&w=500"
name=random.randrange(1,1000)
filename=str(name)+".jpg"
response = requests.get(url)
if response.status_code.ok:
   with open(filename,'w') as f:
    f.write(response.content)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.