다음은 Python에서 웹상의 이미지, ZIP, PDF 또는 기타 파일의 URL을 지정하고 다운로드하여 로컬 파일로 저장하는 방법을 설명합니다.
- URL을 지정하여 이미지를 다운로드합니다.
- 코드 예
urllib.request.urlopen()
:URL 열기open()
:바이너리 모드에서 파일에 쓰기- 더 간단한 코드 예제
- ZIP 파일, PDF 파일 등을 다운로드합니다.
- 웹 페이지에서 이미지의 URL을 추출합니다.
- 번호가 순차적인 경우
- 아름다운 수프로 추출
- URL 목록에서 여러 이미지를 일괄 다운로드
URL을 지정하여 이미지를 다운로드합니다.
표준 라이브러리는 URL을 지정하여 개별 파일을 다운로드하는 데만 사용할 수 있습니다. 추가 설치가 필요하지 않습니다.
코드 예
다음은 URL과 목적지 경로, 사용법을 지정하여 파일을 다운로드 및 저장하는 함수의 예이다. 이 코드는 설명을 위해 약간 장황합니다. 아래에 간단한 예가 나와 있습니다.
import os import pprint import time import urllib.error import urllib.request def download_file(url, dst_path): try: with urllib.request.urlopen(url) as web_file: data = web_file.read() with open(dst_path, mode='wb') as local_file: local_file.write(data) except urllib.error.URLError as e: print(e)
url = 'https://www.python.org/static/img/python-logo.png' dst_path = 'data/temp/py-logo.png' download_file(url, dst_path)
대상 디렉토리를 지정하고 URL 파일 이름으로 파일을 저장하려면 다음을 수행하십시오.
def download_file_to_dir(url, dst_dir): download_file(url, os.path.join(dst_dir, os.path.basename(url))) dst_dir = 'data/temp' download_file_to_dir(url, dst_dir)
os.path.basename()을 사용하여 URL에서 파일 이름을 추출하고 os.path.join()으로 지정된 디렉토리와 결합하여 대상 경로를 생성합니다.
다음 섹션에서는 데이터 수집 부분과 데이터를 파일로 저장하는 부분에 대해 설명합니다.
urllib.request.urlopen():URL 열기
urllib.request.urlopen()을 사용하여 URL을 열고 데이터를 검색합니다. urllib.urlopen()은 Python 2.6 및 이전 버전에서 더 이상 사용되지 않습니다. urllib.request.urlretrieve()는 아직 더 이상 사용되지 않지만 향후 사용되지 않을 수 있습니다.
예외가 발생했을 때 중지되지 않도록 하려면 try 및 except를 사용하여 오류를 잡아야 합니다.
예제에서 urllib.error를 가져오고 urllib.error.URLError만 명시적으로 캡처합니다. 파일의 URL이 존재하지 않는 경우 오류 메시지가 표시됩니다.
url_error = 'https://www.python.org/static/img/python-logo_xxx.png' download_file_to_dir(url_error, dst_dir) # HTTP Error 404: Not Found
로컬에 저장할 때 예외(FileNotFoundError 등)도 catch하려면 다음을 수행합니다.(urllib.error.URLError, FileNotFoundError)
표준 라이브러리 urllib 대신 타사 라이브러리 Requests를 사용하여 URL을 열고 데이터를 가져올 수도 있습니다.
open()에서 바이너리 모드로 파일에 쓰기
urllib.request.urlopen()으로 얻을 수 있는 데이터는 바이트열(bytes type)이다.
두 번째 인수로 mode=’wb’를 사용하는 Open()은 데이터를 바이너리로 씁니다. w는 쓰기를 의미하고 b는 바이너리를 의미합니다.
더 간단한 코드 예제
Nested with 문은 쉼표로 구분하여 한 번에 작성할 수 있습니다.
이를 이용하여 다음과 같이 쓸 수 있습니다.
def download_file(url, dst_path): try: with urllib.request.urlopen(url) as web_file, open(dst_path, 'wb') as local_file: local_file.write(web_file.read()) except urllib.error.URLError as e: print(e)
ZIP 파일, PDF 파일 등을 다운로드합니다.
지금까지의 예제는 이미지 파일을 다운로드하여 저장하는 것이었지만, 우리는 단순히 웹에서 파일을 열어 로컬 파일로 저장하기 때문에 다른 유형의 파일에도 동일한 기능을 사용할 수 있습니다.
URL을 지정하여 파일을 다운로드 및 저장할 수 있습니다.
url_zip = 'https://from-locas.com/sample_header.csv.zip' download_file_to_dir(url_zip, dst_dir) url_xlsx = 'https://from-locas/sample.xlsx' download_file_to_dir(url_xlsx, dst_dir) url_pdf = 'https://from-locas/sample1.pdf' download_file_to_dir(url_pdf, dst_dir)
이 함수에 지정된 URL은 파일 자체에 대한 링크여야 합니다.
예를 들어 GitHub 리포지토리 파일의 경우 다음 URL은 pdf 확장자를 갖지만 실제로는 html 페이지입니다. 위의 함수에서 이 URL을 지정하면 html 소스가 다운로드됩니다.
- https://github.com/from-locals/python-snippets/blob/master/notebook/data/src/pdf/sample1.pdf
파일 엔티티에 대한 링크는 다음 URL이며 파일을 다운로드하고 저장하려면 지정해야 합니다.
- https://github.com/from-locals/python-snippets/raw/master/notebook/data/src/pdf/sample1.pdf
또한 사용자 에이전트, 리퍼러 등에 의해 접근이 제한되어 다운로드가 불가능한 경우도 있습니다. 모든 파일이 다운로드된다는 보장은 없습니다.
Requests를 사용하여 사용자 에이전트와 같은 요청 헤더를 변경하거나 추가하는 것은 쉽습니다.
웹 페이지에서 이미지의 URL을 추출합니다.
페이지의 모든 이미지를 한 번에 다운로드하려면 먼저 이미지의 URL을 추출하고 목록을 만듭니다.
번호가 순차적인 경우
다운로드하려는 이미지의 URL이 간단한 일련번호이면 쉽습니다. URL이 일련번호일 뿐만 아니라 규칙성이 있으면 아름다운 국수(아래 참조)로 긁어내는 것보다 규칙에 따라 URL 목록을 만드는 것이 더 쉽습니다.
목록 이해 표기법을 사용합니다.
- 관련 기사:Python 목록 이해 표기법 사용
url_list = ['https://example.com/basedir/base_{:03}.jpg'.format(i) for i in range(5)] pprint.pprint(url_list) # ['https://example.com/basedir/base_000.jpg', # 'https://example.com/basedir/base_001.jpg', # 'https://example.com/basedir/base_002.jpg', # 'https://example.com/basedir/base_003.jpg', # 'https://example.com/basedir/base_004.jpg']
위의 예에서 {:03}은 0으로 채워진 3자리 순차 번호에 사용됩니다. {}는 0 채우기가 필요하지 않을 때 사용되고 {:05}는 3자리 대신 5자리 숫자에 사용됩니다. string str의 format 메서드에 대한 자세한 내용은 다음 문서를 참조하세요.
또한 여기에서는 출력을 읽기 쉽게 하기 위해 pprint를 사용하고 있습니다.
아름다운 수프로 추출
웹 페이지에서 이미지 URL을 대량으로 추출하려면 Beautiful Soup을 사용하십시오.
import os import time import urllib.error import urllib.request from bs4 import BeautifulSoup url = 'https://ko.from-locals.com/' ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) '\ 'AppleWebKit/537.36 (KHTML, like Gecko) '\ 'Chrome/55.0.2883.95 Safari/537.36 ' req = urllib.request.Request(url, headers={'User-Agent': ua}) html = urllib.request.urlopen(req) soup = BeautifulSoup(html, "html.parser") url_list = [img.get('data-src') for img in soup.find(class_='list').find_all('img')]
예제에서는 이 웹사이트의 썸네일 이미지의 URL을 추출합니다.
그 구조는 웹페이지에 따라 다르지만 기본적으로는 다음과 같이 얻어진다.
- <img> 다운로드하려는 여러 이미지가 포함된 블록의 클래스, ID 등을 지정하여 객체에 태그를 지정합니다.
soup.find(class_='list').find_all('img')
- <img> 꼬리표.
img.get('data-src')
위의 샘플 코드는 예시일 뿐이며 작동이 보장되지는 않습니다.
URL 목록에서 여러 이미지를 일괄 다운로드
URL 목록이 있는 경우 for 루프에서 이를 전환하고 함수를 호출하여 첫 번째 URL이 표시된 파일을 다운로드하고 저장할 수 있습니다. 임시 URL 목록으로 인해 download_image_dir() 함수 호출이 여기에서 주석 처리됩니다.
download_dir = 'data/temp' sleep_time_sec = 1 for url in url_list: print(url) # download_file_dir(url, download_dir) time.sleep(sleep_time_sec) # https://example.com/basedir/base_000.jpg # https://example.com/basedir/base_001.jpg # https://example.com/basedir/base_002.jpg # https://example.com/basedir/base_003.jpg # https://example.com/basedir/base_004.jpg
서버에 과부하가 걸리지 않도록 time.sleep()을 사용하여 각 이미지 다운로드에 대한 대기 시간을 만듭니다. 단위는 초이므로 위의 예에서는 time 모듈을 가져와 사용합니다.
예는 이미지 파일에 대한 것이지만 다른 유형의 파일도 나열되어 있으면 함께 다운로드할 수 있습니다.