대외활동/SK Shieldus rookies

[인프라 활용을 위한 파이썬] #4 FTP 서비스 연결 및 자동화

승요나라 2024. 3. 12. 12:58

FTP(File Transfer Protocol) 서비스는 파일 전송을 위한 서비스를 제공하는 것을 말한다.

 

가상머신 (VMware Workstation Pro 사용) 내에 Kali Linux를 올려놓고 FTP 서비스를 이용해 로컬 PC에서 Kali로 파일을 전송할 것이다.

Kali Linux ISO 파일은 2022.4 버전을 사용하다 중간에 실수로 밀어버려서 2023.3 버전을 사용했는데 큰 차이는 느끼지 못했다.

+ Kali의 초기 ID/PW는 kali/kali 이며 변경 가능하다.

 

 

Kali를 부팅시키면 터미널을 열고 리눅스 패키지 저장소를 업데이트한다.

┌──(kali㉿kali)-[~]

└─$ sudo apt update

 

다음으로 FTP 서버 사용을 위해 vsftpd(very secure FTP daemon)를 설치해준다.

┌──(kali㉿kali)-[~]

└─$ sudo apt install vsftpd

 

설치 이후 로컬 PC에서의 접근을 위해 vsftpd 설정 파일을 열고 수정하는 작업을 한다.

┌──(kali㉿kali)-[~]

└─$ sudo vim /etc/vsftpd.conf

 

 

수정해야하는 세 가지는 다음과 같다.   

  • local_enable=yes (로컬 계정 접근 허용)
  • write_enable=yes (로컬 계정 쓰기 허용)
  • local_umask=022 (로컬 계정 umask)

vsftpd.conf 파일 수정

 

 

설정 파일 수정이 끝나면 로컬 PC에서 ftp [Kali IP 주소] 명령어를 입력해 ftp 연결을 시도한다.

(실습 시 Kali의 IP가 192.168.20.128 이었으므로 ftp 192.168.20.128 명령어를 사용했다.)

kali/kali 로 로그인을 하면 ftp 서버로 접속되는 것을 확인할 수 있다.

로컬 PC에서 Kali ftp 서버 접속

 

 

ftp에 접속해 사용할 수 있는 주요 명령어는 다음과 같다.

quit FTP 연결 종료
pwd 현재 작업 디렉토리 경로 출력
cwd <경로> 작업 디렉토리 변경
dir 현재 작업 디렉토리의 파일 및 디렉토리 목록 출력
ls dir 명령어와 동일
mkdir <디렉토리명> 새 디렉토리 생성
rmdir <디렉토리명> 디렉토리 삭제
delete <파일명> 파일 삭제
get <원격파일명> [<로컬파일명>] 원격 서버에서 파일을 다운로드하여 로컬에 저장
put <로컬파일명> [<원격파일명>] 로컬에서 파일을 업로드하여 원격 서버에 저장
rename <원래파일명> <새파일명> 파일 이름 변경
size <파일명> 파일 크기 출력
type <방식> 전송 방식 변경 (바이너리/아스키)
passive 패시브 모드 전환
active 액티브 모드 전환
help [<명령어>] 명령어 도움말 출력

 

 

이제 파이썬으로 FTP 서비스 작업을 자동화해볼 것이다.

ftp_host 에는 Kali의 IP 주소를 입력한다.

 

import ftplib  # ftplib 모듈 임포트 (FTP 프로토콜을 사용하기 위해 필요함)

ftp_host = ""  # FTP 서버의 호스트 주소
ftp_user = "kali"  # FTP 서버에 로그인할 사용자 이름
ftp_pass = "kali"  # FTP 서버에 로그인할 비밀번호

ftp = ftplib.FTP(ftp_host)  # FTP 서버에 연결하기 위해 FTP 객체 생성
ftp.login(ftp_user, ftp_pass)  # FTP 서버에 사용자 이름과 비밀번호를 사용하여 로그인

# rb는 binary
with open("1_result.xlsx", "rb") as f:  # "1_result.xlsx" 파일을 이진 모드로 읽기 위해 open
    ftp.storbinary(f"STOR 1_result.xlsx", f)  # FTP 서버로 파일 업로드

print(f"현재 디렉터리 정보: {ftp.dir()}")  # 업로드 후에 현재 디렉터리의 정보 출력

ftp01.py

이 코드는 1_result.xlsx 파일을 FTP 서버로 업로드하고, 업로드 후에 현재 디렉터리의 정보를 출력하는 기능을 수행한다.

 

import zipfile
import os

dir_path = "static"  # 작업할 디렉터리 경로 설정

# listdir로 출력
all_files = os.listdir(dir_path)  # 해당 디렉터리 내의 모든 파일과 디렉터리 목록 반환
print(all_files)

# os.walk로 출력
# listdir은 파일 정보가 숨겨지므로 os.walk를 사용한다.
for root, dirs, files in os.walk(dir_path):
    # 여기서 말하는 root는 static
    print(root)  # 현재 탐색 중인 디렉터리 경로를 출력
    
    # dirs에는 현재 디렉터리의 하위 디렉터리 목록이 포함됨
    print(dirs)  # 현재 디렉터리 내의 모든 하위 디렉터리 목록을 출력
    
    # files에는 현재 디렉터리의 모든 파일 목록이 포함됨
    print(files)  # 현재 디렉터리 내의 모든 파일 목록을 출력

zip01.py

 

os.listdir()os.walk()는 둘 다 파일 시스템의 디렉토리 구조를 탐색하는 데 사용되는 함수이지만, 각각의 차이점이 있다.

  1. os.listdir():
    • os.listdir() 함수는 주어진 디렉토리에 있는 모든 파일과 디렉토리의 리스트를 반환한다.
    • 반환된 리스트에는 해당 디렉토리에 있는 모든 파일과 하위 디렉토리의 이름이 포함된다.
    • 하위 디렉토리에 대한 자세한 정보는 포함되지 않으며, 디렉토리와 파일의 이름만을 제공한다.
  2. os.walk():
    • os.walk() 함수는 주어진 디렉토리부터 시작하여 그 하위 디렉토리를 재귀적으로 탐색한다.
    • 각 디렉토리에 대해 다음과 같은 정보를 생성하는 제너레이터(generator)를 반환한다:
      • 현재 탐색 중인 디렉토리의 경로
      • 현재 디렉토리에 있는 모든 하위 디렉토리의 이름 리스트
      • 현재 디렉토리에 있는 모든 파일의 이름 리스트

따라서 os.walk()를 사용하면 디렉토리의 하위 디렉토리와 파일에 대한 보다 상세한 정보를 얻을 수 있다고 한다.

 

[ 선택하는 방법 ]

단순히 디렉토리에 있는 파일과 디렉토리의 이름만 필요하다 == os.listdir()

디렉토리의 하위 디렉토리와 파일에 대한 상세한 정보가 필요하거나, 재귀적으로 모든 하위 디렉토리를 탐색해야 한다 == os.walk()

 

 

따라서 os.walk()를 사용해 static 디렉토리와 그 하위 디렉토리를 모두 압축한 zip 파일을 생성하려면 다음 코드를 참고한다.

import zipfile
import os

dir_path = "static"  # 압축할 디렉토리의 경로 설정
zip_file = zipfile.ZipFile("static_folder.zip", "w")  # 새로운 ZIP 파일을 생성하고 쓰기 모드로 연다.

# os.walk로 출력
for root, dirs, files in os.walk(dir_path):
    for file in files:
        # 디렉토리의 모든 파일을 순회하면서 각 파일을 ZIP 파일에 추가함
        # os.path.join() 함수를 사용하여 각 파일의 절대 경로를 생성함
        zip_file.write(os.path.join(root, file))

# ZIP 파일 닫기 (파일을 닫지 않으면 변경 내용이 커밋되지 않을 수 있다.)
zip_file.close()

zip02.py

 

RSS + Excel + ZIP + FTP 예제는 다음과 같다.

import feedparser
import pandas as pd
from datetime import datetime
import os
import zipfile
import ftplib

# 현재 날짜를 가져와서 YYYY-MM-DD 형식의 문자열로 변환
now = datetime.now().strftime("%Y-%m-%d")
# RSS 피드를 저장할 디렉토리 생성 ex) 2023-11-27_rss
dir_path = f"{now}_rss"
os.mkdir(dir_path)

def rss_crawl():
    # rss.txt 파일에서 RSS 피드 URL을 읽어옴
    with open('rss.txt', 'r') as file:
        rss_urls = file.readlines()

    # 각각의 RSS 피드를 반복하며 데이터 수집
    for index, url in enumerate(rss_urls):
        feed = feedparser.parse(url)
        titles = []
        links = []
        descriptions = []
        authors = []

        # 각 항목의 제목, 링크, 설명, 저자 등을 추출하여 리스트에 추가
        for entry in feed.entries:
            titles.append(entry.title)
            links.append(entry.link)
            descriptions.append(entry.description)
            authors.append(entry.author)

        # 수집한 데이터를 DataFrame으로 변환하고 엑셀 파일로 저장
        data = {'Title':titles, 'Link':links, 'Description':descriptions, 'Author':authors}
        df = pd.DataFrame(data)
        df.to_excel(f'{dir_path}\\{index+1}_result.xlsx', index=False)

def zip_files():
    # 생성한 디렉토리를 압축하여 하나의 ZIP 파일로 만듦
    zip_file = zipfile.ZipFile(f"{now}.zip", "w")
    for root, dirs, files in os.walk(dir_path):
        for file in files:
            zip_file.write(os.path.join(root,file))
    zip_file.close()

def ftp_sender():
    # FTP 서버로 파일 전송
    ftp_host = "192.168.20.128"  # FTP 서버의 호스트 주소
    ftp_user = "kali"  # FTP 서버에 로그인할 사용자 이름
    ftp_pass = "kali"  # FTP 서버에 로그인할 비밀번호

    # FTP 서버에 연결
    ftp = ftplib.FTP(ftp_host)
    ftp.login(ftp_user, ftp_pass)

    # 생성한 ZIP 파일을 바이너리 읽기 모드로 엶
    with open(f"{now}.zip", "rb") as f:
        # FTP 서버로 파일을 업로드합니다.
        ftp.storbinary(f"STOR {now}.zip",f)

    # FTP 서버의 현재 디렉토리 위치와 정보 출력
    print(f"현재 디렉터리 위치: {ftp.pwd()}")
    print(f"현재 디렉터리 정보: {ftp.dir()}")

# 이 코드는 스크립트가 직접 실행될 때만 실행된다.
if __name__ == '__main__':
    # RSS 피드를 수집하고 엑셀 파일로 저장
    rss_crawl()
    # 생성한 엑셀 파일들을 하나의 ZIP 파일로 압축
    zip_files()
    # 압축한 ZIP 파일을 FTP 서버로 전송
    ftp_sender()

rss_excel_zip_ftp.py

RSS 피드에서 데이터를 수집하여 엑셀 파일로 저장하고, 이를 압축하여 FTP 서버로 전송하는 작업을 수행하는 코드이다.

  1. rss_crawl(): rss.txt 파일에 나열된 RSS 피드를 읽고, 각 피드에서 제목, 링크, 설명, 저자 등의 데이터를 수집하여 엑셀 파일로 저장한다.
  2. zip_files(): 이전 단계에서 생성한 엑셀 파일들을 하나의 ZIP 파일로 압축한다.
  3. ftp_sender(): 생성한 ZIP 파일을 FTP 서버로 전송한다.