Python 3의 웹에서 파일 다운로드


332

동일한 게임 / 응용 프로그램의 .jad 파일에 지정된 URL을 읽어 웹 서버에서 .jar (java) 파일을 다운로드하는 프로그램을 만들고 있습니다. 파이썬 3.2.1을 사용하고 있습니다

JAD 파일에서 JAR 파일의 URL을 추출했습니다 (모든 JAD 파일에는 JAR 파일의 URL이 포함되어 있음). 상상할 수 있듯이 추출 된 값은 type () 문자열입니다.

관련 기능은 다음과 같습니다.

def downloadFile(URL=None):
    import httplib2
    h = httplib2.Http(".cache")
    resp, content = h.request(URL, "GET")
    return content

downloadFile(URL_from_file)

그러나 위의 함수의 유형은 문자열이 아닌 바이트이어야한다는 오류가 항상 발생합니다. URL.encode ( 'utf-8') 및 bytes (URL, encoding = 'utf-8')을 사용해 보았지만 항상 동일하거나 유사한 오류가 발생합니다.

그래서 기본적으로 내 질문은 URL이 문자열 유형으로 저장 될 때 서버에서 파일을 다운로드하는 방법입니다.


4
@alvas, 이것에 대한 현상금? 응답자는 여전히 SO에서 활발하게 활동하고 있습니다. 왜 코멘트를 추가하고 물어 보지 않겠습니까?
Bhargav Rao

8
시간의 테스트를 지속하는 좋은 대답은 가치가 있습니다. 또한 오늘 답변이 적절한 지 확인하기 위해 다른 많은 질문에 대해서도이 작업을 시작해야합니다. 특히 SO 답변의 정렬이 다소 미친 경우, 때로는 오래되었거나 심지어 최악의 답변이 맨 위로 올라갑니다.
alvas

답변:


646

웹 페이지의 내용을 변수로 얻으려면 다음과 read같이 응답하십시오 urllib.request.urlopen.

import urllib.request
...
url = 'http://example.com/'
response = urllib.request.urlopen(url)
data = response.read()      # a `bytes` object
text = data.decode('utf-8') # a `str`; this step can't be used if data is binary

파일을 다운로드하고 저장하는 가장 쉬운 방법은 다음 urllib.request.urlretrieve기능 을 사용하는 것입니다.

import urllib.request
...
# Download the file from `url` and save it locally under `file_name`:
urllib.request.urlretrieve(url, file_name)
import urllib.request
...
# Download the file from `url`, save it in a temporary directory and get the
# path to it (e.g. '/tmp/tmpb48zma.txt') in the `file_name` variable:
file_name, headers = urllib.request.urlretrieve(url)

그러나 레거시urlretrieve 로 간주 되어 더 이상 사용되지 않을 수 있음을 명심하십시오 (그렇지만 이유는 확실하지 않음).

따라서이를 수행하는 가장 올바른 방법은이 urllib.request.urlopen함수 를 사용하여 HTTP 응답을 나타내는 파일과 유사한 객체를 반환하고를 사용하여 실제 파일로 복사하는 것 shutil.copyfileobj입니다.

import urllib.request
import shutil
...
# Download the file from `url` and save it locally under `file_name`:
with urllib.request.urlopen(url) as response, open(file_name, 'wb') as out_file:
    shutil.copyfileobj(response, out_file)

이것이 너무 복잡해 보인다면 전체 다운로드를 bytes객체 에 저장 한 다음 파일로 작성하는 것이 더 간단 할 수 있습니다. 그러나 이것은 작은 파일에만 효과적입니다.

import urllib.request
...
# Download the file from `url` and save it locally under `file_name`:
with urllib.request.urlopen(url) as response, open(file_name, 'wb') as out_file:
    data = response.read() # a `bytes` object
    out_file.write(data)

.gz압축 된 데이터를 즉석에서 추출 (및 다른 형식) 할 수 있지만 이러한 작업을 수행하려면 HTTP 서버가 파일에 대한 임의 액세스를 지원해야합니다.

import urllib.request
import gzip
...
# Read the first 64 bytes of the file inside the .gz archive located at `url`
url = 'http://example.com/something.gz'
with urllib.request.urlopen(url) as response:
    with gzip.GzipFile(fileobj=response) as uncompressed:
        file_header = uncompressed.read(64) # a `bytes` object
        # Or do anything shown above using `uncompressed` instead of `response`.

7
헤더 에서 문자 인코딩을 얻기 위해 response.info().get_param('charset', 'utf-8')하드 코딩 대신 사용할 수 있습니다.utf-8Content-Type
jfs

2
@OlehPrypin 왜 outfile.write(data)작은 파일에 대해서만 잘 작동합니까?
Startec

"urlretrieve는 레거시로 간주되어 더 이상 사용되지 않을 수 있습니다"그 아이디어를 어디서 얻었습니까?
Corey Goldberg

13
@Corey : 문서 에서 바로 : "21.6.24. 레거시 인터페이스 다음 함수와 클래스는 Python 2 모듈 urllib (urllib2가 아닌)에서 포팅됩니다. 나중에 언젠가 더 이상 사용되지 않을 수 있습니다." ... 그리고 나는 Oleh의 "왜 그런지 모르겠다"에 동의합니다
cfi

@ Oleh Prypin urllib.request.urlopen (url)을 응답으로 사용하고 open (file_name, 'wb')을 out_file : shutil.copyfileobj (response, out_file)으로 사용하면 catch 문에서 HTTP 상태 코드를 어떻게 찾을 수 있습니까 파일을 찾을 수 없다는 것을 알고?
Robert Achmann

145

requestsAPI는 시작하기 매우 쉽기 때문에 HTTP 요청과 관련된 것을 원할 때마다 패키지를 사용 합니다.

먼저 설치 requests

$ pip install requests

그런 다음 코드 :

from requests import get  # to make GET request


def download(url, file_name):
    # open in binary mode
    with open(file_name, "wb") as file:
        # get request
        response = get(url)
        # write to file
        file.write(response.content)

16

URL이 문자열 유형으로 저장된 경우 서버에서 파일을 다운로드하는 방법은 무엇입니까?

파일을 다운로드하고 아래 코드를 사용하여 로컬로 저장합니다.

import requests

url = 'https://www.python.org/static/img/python-logo.png'
fileName = 'D:\Python\dwnldPythonLogo.png'
req = requests.get(url)
file = open(fileName, 'wb')
for chunk in req.iter_content(100000):
    file.write(chunk)
file.close()

안녕하세요, 저는 또한 파일을 다운로드에 대한 코드의 동일한 유형을 사용하고 있지만, 약간의 시간이 내가 좋아하는 예외에 직면 한이 - '문자표'코덱은 인코딩 문자 '\ u010c'..... 당신은 나를 도울 수 없습니다
Joyson

10

파이썬 3에서 urllib의 레거시 인터페이스를 사용할 수 있습니다 :

다음 함수와 클래스는 Python 2 모듈 urllib에서 포팅되었습니다 (urllib2와 반대). 나중에 언젠가 더 이상 사용되지 않을 수 있습니다.

(2 줄 코드) :

import urllib.request

url = 'https://www.python.org/static/img/python-logo.png'
urllib.request.urlretrieve(url, "logo.png")

9

쉘 다운로드 도구 인 wget 을 사용할 수 있습니다 . https://pypi.python.org/pypi/wget 대상 파일을 열 필요가 없으므로 가장 간단한 방법입니다. 다음은 예입니다.

import wget
url = 'https://i1.wp.com/python3.codes/wp-content/uploads/2015/06/Python3-powered.png?fit=650%2C350'  
wget.download(url, '/Users/scott/Downloads/cat4.jpg') 

0

예, 확실히 요청은 HTTP 요청과 관련하여 사용하기에 좋은 패키지입니다. 그러나 우리는 들어오는 데이터의 인코딩 유형에주의해야합니다. 아래에 차이점을 설명하는 예가 있습니다.


from requests import get

# case when the response is byte array
url = 'some_image_url'

response = get(url)
with open('output', 'wb') as file:
    file.write(response.content)


# case when the response is text
# Here unlikely if the reponse content is of type **iso-8859-1** we will have to override the response encoding
url = 'some_page_url'

response = get(url)
# override encoding by real educated guess as provided by chardet
r.encoding = r.apparent_encoding

with open('output', 'w', encoding='utf-8') as file:
    file.write(response.content)

0

자극

때로는 사진을 찍고 싶지만 실제 파일로 다운로드 할 필요는 없습니다.

즉, 데이터를 다운로드하여 메모리에 보관하십시오.

예를 들어 기계 학습 방법을 사용하는 경우 숫자 (바코드)로 이미지를 인식 할 수있는 모델을 학습하십시오.

일부 웹 사이트를 스파이더 링하고 해당 이미지가 있으므로 모델을 사용하여이를 인식 할 수 있습니다.

디스크 드라이브에 사진을 저장하고 싶지 않습니다.

그런 다음 메모리에 다운로드 데이터를 유지하는 데 도움이되는 아래 방법을 시도해 볼 수 있습니다.

포인트들

import requests
from io import BytesIO
response = requests.get(url)
with BytesIO as io_obj:
    for chunk in response.iter_content(chunk_size=4096):
        io_obj.write(chunk)

기본적으로 @ Ranvijay Kumar와 같습니다.

import requests
from typing import NewType, TypeVar
from io import StringIO, BytesIO
import matplotlib.pyplot as plt
import imageio

URL = NewType('URL', str)
T_IO = TypeVar('T_IO', StringIO, BytesIO)


def download_and_keep_on_memory(url: URL, headers=None, timeout=None, **option) -> T_IO:
    chunk_size = option.get('chunk_size', 4096)  # default 4KB
    max_size = 1024 ** 2 * option.get('max_size', -1)  # MB, default will ignore.
    response = requests.get(url, headers=headers, timeout=timeout)
    if response.status_code != 200:
        raise requests.ConnectionError(f'{response.status_code}')

    instance_io = StringIO if isinstance(next(response.iter_content(chunk_size=1)), str) else BytesIO
    io_obj = instance_io()
    cur_size = 0
    for chunk in response.iter_content(chunk_size=chunk_size):
        cur_size += chunk_size
        if 0 < max_size < cur_size:
            break
        io_obj.write(chunk)
    io_obj.seek(0)
    """ save it to real file.
    with open('temp.png', mode='wb') as out_f:
        out_f.write(io_obj.read())
    """
    return io_obj


def main():
    headers = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7',
        'Cache-Control': 'max-age=0',
        'Connection': 'keep-alive',
        'Host': 'statics.591.com.tw',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36'
    }
    io_img = download_and_keep_on_memory(URL('http://statics.591.com.tw/tools/showPhone.php?info_data=rLsGZe4U%2FbphHOimi2PT%2FhxTPqI&type=rLEFMu4XrrpgEw'),
                                         headers,  # You may need this. Otherwise, some websites will send the 404 error to you.
                                         max_size=4)  # max loading < 4MB
    with io_img:
        plt.rc('axes.spines', top=False, bottom=False, left=False, right=False)
        plt.rc(('xtick', 'ytick'), color=(1, 1, 1, 0))  # same of plt.axis('off')
        plt.imshow(imageio.imread(io_img, as_gray=False, pilmode="RGB"))
        plt.show()


if __name__ == '__main__':
    main()

-3
from urllib import request

def get(url):
    with request.urlopen(url) as r:
        return r.read()


def download(url, file=None):
    if not file:
        file = url.split('/')[-1]
    with open(file, 'wb') as f:
        f.write(get(url))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.