안녕하세요. 명월입니다.
이 글은 Python에서 FTP에 접속하여 파일 다운로드, 업로드하는 방법(ftplib)에 대한 글입니다.
이전에 제가 Window환경에서 FTP Server를 만드는 방법에 대하 소개한 적이 있습니다.
링크 - [CentOS] FTP 설정, vsftpd 설정
FTP 프로토콜을 이전 만큼은 아니지만, 여러가지 파일 전송 프로토콜로써 아직 사용하는 곳이 있기에 소개하겠습니다.
C#으로 FTP 클라이언트를 설명했었는데 비슷한 흐름으로 작성하겠습니다.
링크 - [C#] FTP에 접속해서 파일 다운로드, 업로드하는 방법
# FTP 모듈
from ftplib import FTP
# os 모듈(디렉토리를 다루기 위해)
import os
# ftp의 파일 리스트와 디렉토리 리스트를 구하는 함수
def get_list_ftp(ftp, cwd, files = [], directories = []):
data = []
# 파라미터로 지정된 위치로 디렉토리 이동.
ftp.cwd(cwd)
# 파일 정보를 읽어 드림(\r\n 구분)
ftp.dir(data.append)
# 파일 정보를 읽어 드린 정보를 사용.
# MM-DD-YY HH:MM <DIR> 디렉토리이름
for item in data:
# 위에서 공백으로 디렉토리 이름까지의 위치를 찾음.
pos = item.rfind(' ')
# 이름만 구별해냄.
name = cwd + item[pos+1:]
# string에 <DIR>이 포함되어 있는지 확인(포함되어 있으면 디렉토리임)
if item.find('<DIR>') > -1:
# 디렉토리 리스트에 추가.
directories.append(name)
# 재귀적 함수 요청으로 아래 디렉토리 탐색
get_list_ftp(ftp, name+'/', files, directories)
else:
# 파일의 경우는 파일 리스트에 추가
files.append(name)
# 파일과 디렉토리 리스트를 리턴.
return files, directories
# 로컬 드라이브의 파일 리스트와 디렉토리 리스트를 구하는 함수.
def get_list_local(path, files = [], directories = []):
# 파일 리스트를 구함.
for file in os.listdir(path):
# 파일의 전체 패스는 ath + file 명으로 설정.
item = path + file
# item이 디렉토리인지 파일인지 확인.
if os.path.isdir(item):
# 디렉토리 리스트에 추가
directories.append(item + "\\")
# 디렉토리의 경우는 하위 디렉토리를 탐색.
get_list_local(item + "\\", files, directories)
else :
# 파일 리스트에 추가.
files.append(item)
# 파일과 디렉토리 리스트를 리턴.
return files, directories
##************FTP 모두 삭제***************
# FTP 커넥션을 얻음.
with FTP('localhost') as ftp:
# 디버그 모드로 설정 (설정하면 FTP 서버와 통신하는 내용이 콘솔에 표시됨)
ftp.set_debuglevel(1)
# 로그인 한다.
ftp.login('FTPUser', 'password')
# ftp의 파일과 디릭토리 구조를 취득한다.
files, directories = get_list_ftp(ftp, '/')
# 디렉토리의 경우 상위 폴더가 빠른 인덱스에 있기 때문에 리스트를 reverse한다.
directories = directories[::-1]
# 파일 삭제한다.
for file in files:
ftp.delete(file)
# 폴더 삭제한다.
for dir in directories:
ftp.rmd(dir)
##************업로드***************
# FTP 커넥션을 얻음. (왜인지 같은 커넥션에서 폴더을 삭제하고 같은 이름으로 다시 생성하면 에러가 발생한다.)
with FTP('localhost') as ftp:
# 디버그 모드로 설정 (설정하면 FTP 서버와 통신하는 내용이 콘솔에 표시됨)
ftp.set_debuglevel(1)
# 로그인 한다.
ftp.login('FTPUser', 'password')
# ftp 서버에 파일을 업로드할 로컬 디렉토리.
upload_path = "D:\\ftptest\\upload\\"
# 로컬 디렉토리의 파일과 디렉토리 구조를 취득한다.
files, directories = get_list_local(upload_path)
# 하위 디렉토리의 전부를 ftp에 작성한다.
for directory in directories:
# 절대 패스에서 상대 패스로 변경한다.
# Window의 Path 구분자(\\)와 FTP의 Path 구분자는(/) 다르기 때문에 변경한다.
path = directory.replace(upload_path,"").replace("\\","/")
# ftp에 디렉토리를 작성한다.
ftp.mkd(path)
# 콘솔 출력
print('Make directory is ' + path)
# 파일을 업로드한다.
for file in files:
# 절대 패스에서 상대 패스로 변경한다.
# Window의 Path 구분자(\\)와 FTP의 Path 구분자는(/) 다르기 때문에 변경한다.
path = file.replace(upload_path,"").replace("\\","/")
# 파일을 절대 패스로 읽어 온다.
with open(file, 'rb') as localfile:
# ftp로 업로드한다.
ftp.storbinary('STOR ' + path, localfile)
# 콘솔 출력
print('Upload file is ' + path)
##************다운 로드***************
# ftp 서버에서 파일을 다운로드 할 로컬 디렉토리.
download_path = "D:\\ftptest\\download\\"
# ftp의 파일과 디릭토리 구조를 취득한다.
files, directories = get_list_ftp(ftp, '/')
# 로컬 드라이브의 디렉토리를 생성한다.
for directory in directories:
# 상대 패스에서 절대 패스로 변경한다.
dir = download_path + directory
# 디렉토리가 존재하지 않으면 생성한다.
if os.path.isdir(dir) is False:
os.mkdir(dir)
# 파일을 다운로드한다.
for file in files:
# IO로 파일 커넥션을 얻는다.
with open(download_path + file, 'wb') as localfile:
# ftp로 다운로드한다.
ftp.retrbinary('RETR ' + file, localfile.write)
# 콘솔 출력
print('Download file is ' + file)
위의 소스는 먼저 ftp환경의 파일과 디렉토리를 모두 삭제하고 tptest/upload의 디렉토리의 파일과 하위 디렉토리, 파일을 전부 업로드를 하고, ftptest/download로 전부 다운로드하는 소스의 예제입니다.
위처럼 있는 파일들을 ftp://localhost(ftptest/ftp)로 업로드가 될 것입니다.
그리고 다시 위의 파일을 ftptest/download로 다운로드하는 것입니다.
프로그램을 실행하겠습니다.
다시 ftp://localhost(ftptest/ftp)로 이동하여 확인합니다.
ftp 서버에 제대로 업로드가 되었습니다.
다운로드도 잘 되었습니다.
ftp 소스가 java와 C#에 이어 3번째이네요. 패턴도 거의 비슷하니 FTP 프로토콜을 거의 외울 것같습니다.
특히나 python의 경우는 debug모드로 실행하면 FTP 통신하는 게 보이니 protocol의 상황을 더 자세히 볼 수 있어서 편하네요.
참조 - https://docs.python.org/3/library/ftplib.html
참조 - https://pythonprogramming.net/ftp-transfers-python-ftplib/
참조 - https://stackoverflow.com/questions/663171/how-do-i-get-a-substring-of-a-string-in-python
여기까지 Python에서 FTP에 접속하여 파일 다운로드, 업로드하는 방법(ftplib)에 대한 설명이었습니다.
궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.
'Development note > Python' 카테고리의 다른 글
[Python] Redis 데이터베이스를 접속해서 사용하는 방법 (0) | 2022.02.21 |
---|---|
[Python] Hash 암호화 md5와 바이너리 구조체 base64를 다루는 방법 (0) | 2020.04.02 |
[Python] 웹소켓을 이용해서 웹 페이지에서 파일 업로드하는 방법 (0) | 2020.03.27 |
[Python] wsgi를 이용해서 apache에 웹 서버를 구축하는 방법 (0) | 2020.02.21 |
[Python] 웹 서버를 구축하는 방법(bottle 모듈) (0) | 2020.02.17 |
[Python] Html 및 XML에서 데이터를 가져오는 모듈(Beautiful Soup) (0) | 2020.02.12 |
[Python] byte 타입을 다루는 방법(bytearray, struct 모듈) (0) | 2020.02.06 |
[Python] Selenium 라이브러리 (자동 웹 테스팅, 스크래핑) (0) | 2020.02.05 |