이것저것

[SK shieldus Rookies 29기] 6일차 본문

SK Shieldus Rookies 29

[SK shieldus Rookies 29기] 6일차

atfield1988 2025. 12. 4. 10:58

1️⃣ OpenPyXL 소개

정의

openpyxl은 파이썬에서 Microsoft Excel 2010 이상의 파일을 읽고, 쓰고, 조작할 수 있는 라이브러리입니다.

주요 기능

  • Excel 파일 생성 및 편집
  • 워크북 및 워크시트 관리
  • 셀 데이터 읽기/쓰기
  • 수식 적용
  • 스타일링 및 포맷팅
  • 데이터 자동화 작업

설치

pip install openpyxl

2️⃣ 기본 개념: 워크북과 워크시트

워크북 (Workbook)

  • 워크북: Excel 파일 자체
  • 워크시트 (Worksheet): 워크북 내의 각 시트
  • 하나의 워크북은 하나 이상의 워크시트를 포함
Workbook (balances.xlsx)
├── 📄 Sheet1 (활성 워크시트)
├── 📄 Sheet2
└── 📄 Sheet3

3️⃣ 워크북 생성 및 저장

새로운 워크북 생성

from openpyxl import Workbook

# 새로운 워크북 생성
wb = Workbook()

# 활성 워크시트 접근
ws = wb.active

파일로 저장하기

from openpyxl import Workbook

wb = Workbook()
wb.save('balances.xlsx')

4️⃣ 워크시트 관리

새로운 워크시트 생성

from openpyxl import Workbook

wb = Workbook()

# 마지막에 삽입
ws1 = wb.create_sheet("Mysheet")

# 첫 번째에 삽입
ws2 = wb.create_sheet("Mysheet", 0)

# 끝에서 두 번째에 삽입
ws3 = wb.create_sheet("Mysheet", -1)

워크시트 이름 변경

from openpyxl import Workbook

wb = Workbook()
ws = wb.active

# 워크시트 이름 변경
ws.title = "New Title"

# 모든 워크시트 이름 확인
print(wb.sheetnames)  # ['New Title']

특정 워크시트 접근

# 이름으로 워크시트 접근
ws3 = wb["New Title"]

# 모든 워크시트 이름 확인
print(wb.sheetnames)  # ['Sheet2', 'New Title', 'Sheet1']

워크시트 순환 처리

from openpyxl import Workbook

wb = Workbook()

# 모든 워크시트의 제목 출력
for sheet in wb:
    print(sheet.title)

워크시트 삭제

from openpyxl import Workbook

wb = Workbook()
wb.create_sheet("SK Shieldus Rookies")

# 워크시트 삭제
del wb["Sheet"]

print(wb.sheetnames)  # ['SK Shieldus Rookies']

wb.save('sheet_management.xlsx')

5️⃣ 셀(Cell) 데이터 다루기

특정 셀 접근 - 방법 1: 직접 접근(not recommend)

from openpyxl import Workbook

wb = Workbook()
ws = wb.active

# 'A4' 셀에 접근
c = ws['A4']

# 셀에 값 할당
ws['A4'] = 4

print(ws['A4'].value)  # 4

특정 셀 접근 - 방법 2: cell() 메서드

from openpyxl import Workbook

wb = Workbook()
ws = wb.active

# cell() 메서드 사용 (행, 열 번호로 접근)
# 4번째 행, 2번째 열(B)에 값 할당
ws.cell(row=4, column=2, value=10)

# 4번째 행, 2번째 열 값 읽기
d = ws.cell(row=4, column=2)
print(d.value)  # 10

6️⃣ 셀 범위 접근

범위 내의 모든 셀에 값 할당

from openpyxl import Workbook

wb = Workbook()
ws = wb.active

# 'A1'에서 'D4'까지의 모든 셀에 "Hello World" 입력
for row in ws['A1:D4']:
    for cell in row:
        cell.value = 'Hello World'

wb.save('range_test.xlsx')

셀 범위 읽기

from openpyxl import load_workbook

wb = load_workbook("excel_data.xlsx")
ws = wb.active

# A1부터 C7까지 범위 읽기
for row in ws["A1:C7"]:
    result = []
    for cell in row:
        result.append(cell.value)
    print(result)

7️⃣ 실습 1️⃣: 기본 데이터 입력

from openpyxl import Workbook

wb = Workbook()
ws = wb.active
ws.title = "New Title"

# A1부터 D4까지 "Hello World" 입력
for row in ws['A1:D4']:
    print(f"row:{row}")
    for cell in row:
        print(f"cell:{cell}")
        cell.value = 'Hello World'

wb.save('test_ex1.xlsx')

결과


8️⃣ 실습 2️⃣: 대규모 데이터 입력

from openpyxl import Workbook

wb = Workbook()
ws = wb.active

# 첫 번째 열의 첫 10개 행에 데이터 입력
for i in range(1, 11):
    ws.cell(row=i, column=1).value = f'Item {i}'

wb.save('bulk_data.xlsx')

결과


번호를 포함한 데이터 입력

import openpyxl as excel

book = excel.Workbook()
ws = book.active

# 10개의 데이터 추가
for i in range(10):
    row_cell = ws.cell(row=(i+1), column=1)
    row_cell.value = str(i+1) + " 번째 데이터 저장"

book.save("py_excel01.xlsx")

결과


9️⃣ 실습 3️⃣: 웹 크롤링 + 엑셀 자동화 🌐

악성코드 사이트를 엑셀 파일로 저장

import requests
from bs4 import BeautifulSoup
from openpyxl import Workbook

url = "https://www.malware-traffic-analysis.net/2023/index.html"

header_info = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}

r = requests.get(url, headers=header_info, verify=False)
soup = BeautifulSoup(r.text, 'html.parser')

tags = soup.select("#main_content > div.content > ul > li > a.main_menu")

wb = Workbook()
ws = wb.active
ws['A1'] = "설명"
ws['B1'] = "URL 링크"

i = 2
for tag in tags:
    ws.cell(row=i, column=1, value=tag.text)
    ws.cell(row=i, column=2, value=f"https://www.malware-traffic-analysis.net/2023/{tag.get('href')}")
    i = i + 1

wb.save("malwares.xlsx")

결과


🔟 기존 워크북 열기 📂

기존 Excel 파일 불러오기

from openpyxl import load_workbook

# 파일 불러오기
wb = load_workbook(filename='empty_book.xlsx')

# 워크시트 접근
ws = wb['Sheet1']

# D18 셀의 값 읽기
cell_value = ws['D18'].value
print("The value in cell D18 is:", cell_value)

간단한 예제

from openpyxl import load_workbook

wb = load_workbook("excel_data.xlsx")
ws = wb['Sheet1']

# A1 셀의 값 읽기
cell_value = ws['A1'].value
print(f"value : {cell_value}")

1️⃣1️⃣ 범위 데이터 가져오기 📊

반복문으로 데이터 읽기

from openpyxl import load_workbook

wb = load_workbook("excel_data.xlsx")
ws = wb.active

# A1부터 C7까지 데이터 가져오기
for row in ws["A1":"C7"]:
    result = []
    for cell in row:
        result.append(cell.value)
    print(result)

결과


1️⃣2️⃣ 수식이 적용된 셀 데이터 가져오기

문제점: 수식만 가져오기

Excel에서 수식이 적용된 셀을 불러올 때, 기본적으로 수식만 가져옵니다.

from openpyxl import load_workbook

wb = load_workbook("excel_data2.xlsx")
ws = wb.active

# 수식만 반환됨 (=C2*D2 같은 형태)
for row in ws["A1":"E7"]:
    for cell in row:
        print(cell.value)

해결: data_only=True 옵션 사용 ✅

from openpyxl import load_workbook

# data_only=True로 계산된 값을 가져옴
wb = load_workbook("excel_data2.xlsx", data_only=True)
ws = wb.active

# 계산된 값을 반환 (예: 1000 같은 실제 값)
for row in ws["A1":"E7"]:
    values = [cell.value for cell in row]
    print(values)

data_only 옵션 비교

옵션 반환값 용도
data_only=False (기본값) 수식 문자열 수식 수정 필요 시
data_only=True 계산된 값 데이터 분석/추출

1️⃣3️⃣ append() 메서드로 행 추가 ➕

리스트를 한 번에 입력

from openpyxl import load_workbook

wb = load_workbook("sales_data.xlsx")
ws = wb.active

# 리스트 형태로 한 행을 한 번에 추가
ws.append(['2024-05-08', '아이폰', 1380000, 3, '=C3*D3'])

wb.save("sales_data.xlsx")

append( ) 사용의 장점

  • 여러 셀을 한 번에 입력
  • 코드가 간결함
  • 행 단위로 데이터 관리 용이

1️⃣4️⃣ 데이터 수정 및 삭제

데이터 수정

from openpyxl import load_workbook

wb = load_workbook("sales_data.xlsx")
ws = wb.active

# 기존 데이터 수정
ws['C2'] = 420000  # 가격 수정
ws['D2'] = 25      # 수량 수정

wb.save("sales_data.xlsx")

데이터 삭제

from openpyxl import load_workbook

wb = load_workbook("sales_data.xlsx")
ws = wb.active

# A3 행 삭제
del ws['A3']

wb.save("sales_data.xlsx")

1️⃣5️⃣ 실습 : append() 활용한 웹 크롤링

악성코드 사이트 - append( ) 버전

import requests
from bs4 import BeautifulSoup
from openpyxl import Workbook

url = "https://www.malware-traffic-analysis.net/2023/index.html"

header_info = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}

r = requests.get(url, headers=header_info)
soup = BeautifulSoup(r.text, 'html.parser')

tags = soup.select("#main_content > div.content > ul > li > a.main_menu")

# 워크북 생성
wb = Workbook()
ws = wb.active

# 헤더 추가
ws.append(["설명", "URL 링크"])

# append()로 데이터 추가
for tag in tags:
    ws.append([
        tag.text,
        f"https://www.malware-traffic-analysis.net/2023/{tag.get('href')}"
    ])

wb.save("malwares01.xlsx")

이전 코드와의 차이:

  • 간결한 코드
  • 수동 행 번호 계산 필요 없음
  • 유지보수 용이

1️⃣6️⃣ 실습 : RSS 피드를 엑셀로 저장 📰

feedparser 라이브러리 설치

pip install feedparser

RSS 피드 자동화

import feedparser
from openpyxl import Workbook

# 공신력 있는 보안 뉴스 RSS
url = "https://www.dailysecu.com/rss/allArticle.xml"

# RSS 파싱
feed = feedparser.parse(url)

# 워크북 생성
wb = Workbook()
ws = wb.active

# 헤더 추가
ws.append(["제목", "링크", "요약", "작성자", "날짜"])

# RSS 항목을 엑셀에 추가
for entry in feed.entries:
    row = [
        entry.title,
        entry.link,
        entry.description,
        entry.author,
        entry.published
    ]
    ws.append(row)

# 저장
wb.save('데일리시큐.xlsx')
print("파일이 생성되었어!")

코드 설명

항목 설명
feedparser.parse() RSS URL 파싱
feed.entries 모든 기사 항목 반복
entry.title 기사 제목
entry.link 기사 링크
entry.description 기사 요약
entry.author 작성자
entry.published 발행일

내가 짠 코드(살짝 노가다..st)

import feedparser
from openpyxl import Workbook

url = "https://www.dailysecu.com/rss/allArticle.xml"

feed = feedparser.parse(url)
wb = Workbook()
ws = wb.active
ws['A1'] = "제목"
ws['B1'] = "링크"
ws['C1'] = "요약"
ws['D1'] = "작성자"
ws['E1'] = "작성일자"

i = 2
for entry in feed.entries:
    ws.cell(row=i, column=1, value=entry.title)
    ws.cell(row=i, column=2, value=entry.link)
    ws.cell(row=i, column=3, value=entry.summary)
    ws.cell(row=i, column=4, value=entry.get('author', '')) 
    ws.cell(row=i, column=5, value=entry.get('published', ''))
    i += 1
wb.save("rss_feed.xlsx")

결과


1️⃣7️⃣ FTP란?

📌 정의

FTP (File Transfer Protocol)는 인터넷 상에서 파일을 송수신하는 표준 통신 규약입니다.

주요 기능

  • 서버에서 파일 업로드/다운로드
  • 디렉토리 생성/삭제
  • 파일 삭제 및 관리
  • 자동화된 백업 시스템 구축

1️⃣8️⃣ ftplib 라이브러리

📌 정의

ftplib 모듈은 FTP 클라이언트 세션을 생성하고 관리하는 기능을 제공합니다.

라이브러리 임포트

import ftplib

ftplib은 표준 라이브러리이므로 별도 설치 불필요


1️⃣9️⃣ FTP 서버 연결

FTP 서버 연결

import ftplib

# hostname: FTP 서버 도메인 또는 IP 주소
hostname = "192.168.134.128"(본인 것 입력)
ftp = ftplib.FTP(hostname)

FTP 서버 로그인

import ftplib

hostname = "192.168.134.128"
ftp = ftplib.FTP(hostname)

# username, password로 로그인
ftp.login('msfadmin', 'msfadmin')

FTP 연결 종료

# FTP 연결 종료
ftp.quit()

2️⃣0️⃣ 디렉터리 리스트 조회

현재 디렉터리 파일 목록

import ftplib

hostname = "192.168.134.128"
ftp = ftplib.FTP(hostname)
ftp.login('msfadmin', 'msfadmin')

# 현재 디렉터리 파일 목록 출력
ftp.retrlines('LIST')

ftp.quit()

2️⃣1️⃣ 주요 FTP 명령어

📊 명령어 요약 테이블

명령어 설명 예시
LIST 디렉터리 상세 정보 ftp.retrlines('LIST')
NLST 파일 이름 목록만 ftp.nlst()
RETR 파일 다운로드 ftp.retrbinary('RETR file.txt', ...)
STOR 파일 업로드 ftp.storbinary('STOR file.txt', ...)
DELE 파일 삭제 ftp.delete('file.txt')
MKD 디렉터리 생성 ftp.mkd('new_dir')
RMD 디렉터리 삭제 ftp.rmd('old_dir')
PWD 현재 디렉터리 print(ftp.pwd())
CWD 디렉터리 변경 ftp.cwd('new_dir')

1️⃣ LIST - 상세 목록 조회

import ftplib

ftp = ftplib.FTP("192.168.134.128")
ftp.login('msfadmin', 'msfadmin')

# 현재 디렉터리의 상세 정보 출력
ftp.retrlines('LIST')

ftp.quit()

출력:

-rw-r--r-- 1 owner group 1024 NOV 12 12:30 file.txt
-rw-r--r-- 1 owner group 2048 NOV 12 14:15 document.pdf
drwxr-xr-x 2 owner group 4096 NOV 12 11:45 folder

2️⃣ NLST - 간단한 목록 조회

import ftplib

ftp = ftplib.FTP("192.168.134.128")
ftp.login('msfadmin', 'msfadmin')

# 파일 이름만 간단히 출력
files = ftp.nlst()
for file in files:
    print(file)

ftp.quit()

출력:

file.txt
document.pdf
folder

3️⃣ PWD - 현재 디렉터리 확인

import ftplib

ftp = ftplib.FTP("192.168.134.128")
ftp.login('msfadmin', 'msfadmin')

# 현재 작업 디렉터리 경로 출력
current_dir = ftp.pwd()
print(f"현재 디렉터리: {current_dir}")

ftp.quit()

출력:

현재 디렉터리: /home/msfadmin

4️⃣ CWD - 디렉터리 변경

import ftplib

ftp = ftplib.FTP("192.168.134.128")
ftp.login('msfadmin', 'msfadmin')

print(f"변경 전: {ftp.pwd()}")

# 디렉터리 변경
ftp.cwd('vulnerable')

print(f"변경 후: {ftp.pwd()}")

ftp.quit()

5️⃣ MKD - 디렉터리 생성

import ftplib

ftp = ftplib.FTP("192.168.134.128")
ftp.login('msfadmin', 'msfadmin')

# 새로운 디렉터리 생성
ftp.mkd("new_folder")

print("디렉터리 생성 완료!")
ftp.retrlines('LIST')

ftp.quit()

6️⃣ RMD - 디렉터리 삭제

import ftplib

ftp = ftplib.FTP("192.168.134.128")
ftp.login('msfadmin', 'msfadmin')

# 디렉터리 삭제 (디렉터리는 비어있어야 함)
ftp.rmd('old_folder')

print("디렉터리 삭제 완료!")

ftp.quit()

7️⃣ DELE - 파일 삭제

import ftplib

ftp = ftplib.FTP("192.168.134.128")
ftp.login('msfadmin', 'msfadmin')

# 파일 삭제
ftp.delete('obsolete.txt')

print("파일 삭제 완료!")

ftp.quit()

2️⃣2️⃣ 실습 : FTP 기본 명령어 테스트

import ftplib

hostname = "192.168.134.128"
ftp = ftplib.FTP(hostname)
ftp.login('msfadmin', 'msfadmin')

# 현재 디렉터리 확인
print(ftp.pwd())

# 파일 목록 출력
ftp.retrlines('LIST')

print("===============")

# 새 디렉터리 생성
ftp.mkd("new_folder")

# 다시 파일 목록 출력
ftp.retrlines('LIST')

print("===============")

# 디렉터리 변경
ftp.cwd("vulnerable")

# vulnerable 폴더 내 파일 목록
ftp.retrlines('LIST')

ftp.quit()

2️⃣3️⃣ 파일 업로드

storbinary( ) 메서드

import ftplib

ftp = ftplib.FTP("192.168.134.128")
ftp.login('msfadmin', 'msfadmin')

# 로컬 파일을 서버에 업로드
with open('malwares.txt', 'rb') as f:
    ftp.storbinary(f'STOR malwares.txt', f)

print("파일 업로드 완료!")

# 업로드된 파일 확인
ftp.retrlines('LIST')

ftp.quit()

함수로 만든 업로드 (파이썬은 역시 함수지...)

import ftplib

def upload_file(ftp, filename):
    """파일을 FTP 서버에 업로드하는 함수"""
    with open(filename, 'rb') as f:
        ftp.storbinary(f'STOR {filename}', f)

# 사용 예
ftp = ftplib.FTP("192.168.134.128")
ftp.login('msfadmin', 'msfadmin')

upload_file(ftp, 'malwares.txt')

print("파일 업로드 완료!")
ftp.retrlines('LIST')

ftp.quit()

2️⃣4️⃣ 파일 다운로드

retrbinary() 메서드

import ftplib

ftp = ftplib.FTP("192.168.134.128")
ftp.login('msfadmin', 'msfadmin')

# 서버에서 파일 다운로드
with open('example.txt', 'wb') as f:
    ftp.retrbinary(f'RETR example.txt', f.write)

print("파일 다운로드 완료!")

ftp.quit()

함수로 만든 다운로드

import ftplib

def download_file(ftp, filename):
    """FTP 서버에서 파일을 다운로드하는 함수"""
    with open(filename, 'wb') as f:
        ftp.retrbinary(f'RETR {filename}', f.write)

# 사용 예
ftp = ftplib.FTP("192.168.134.128")
ftp.login('msfadmin', 'msfadmin')

download_file(ftp, 'example.txt')

print("파일 다운로드 완료!")

ftp.quit()

2️⃣5️⃣ 실습 : 파일 업로드/다운로드 전체 예제

import ftplib

def upload_file(ftp, filename):
    """FTP 서버에 파일 업로드"""
    with open(filename, 'rb') as f:
        ftp.storbinary(f'STOR {filename}', f)
    print(f"✅ {filename} 업로드 완료!")

def download_file(ftp, filename):
    """FTP 서버에서 파일 다운로드"""
    with open(filename, 'wb') as f:
        ftp.retrbinary(f'RETR {filename}', f.write)
    print(f"✅ {filename} 다운로드 완료!")

def main():
    hostname = "192.168.134.128"
    ftp = ftplib.FTP(hostname)
    ftp.login('msfadmin', 'msfadmin')

    print(f"현재 디렉터리: {ftp.pwd()}\n")

    # 파일 업로드
    upload_file(ftp, 'malwares.txt')

    # 업로드된 파일 확인
    print("\n📂 현재 디렉터리 파일 목록:")
    ftp.retrlines('LIST')

    ftp.quit()

if __name__ == "__main__":
    main()

2️⃣6️⃣ 파일 압축

zipfile 라이브러리로 압축하기

import zipfile
import os

# 압축할 디렉터리
RESULT_DIR = 'uploads'

# ZIP 파일 생성
zip_file = zipfile.ZipFile('results.zip', 'w')

# 디렉터리의 모든 파일을 ZIP에 추가
for root, dirs, files in os.walk(RESULT_DIR):
    for file in files:
        file_path = os.path.join(root, file)
        zip_file.write(file_path)

zip_file.close()

print("압축 완료! results.zip 파일이 생성되었습니다.")

2️⃣7️⃣ 실습 : RSS + 엑셀 + 압축 + FTP

📌 요구사항

  1. list.txt에서 RSS URL 읽기
  2. Feedparser로 RSS 정보 수집
  3. 수집된 정보를 엑셀 파일로 저장
  4. 엑셀 파일을 압축
  5. ZIP 파일을 FTP 서버에 업로드

📋 list.txt 파일 내용

https://www.dailysecu.com/rss/allArticle.xml
https://www.dailysecu.com/rss/S1N2.xml
https://www.dailysecu.com/rss/clickTop.xml

💻 통합 코드

import feedparser
from openpyxl import Workbook
import os
import zipfile
import ftplib

# ========== Step 1: RSS 정보 수집 및 엑셀 저장 ==========

RESULT_DIR = "rss_results"

# 결과 디렉터리 생성
if not os.path.exists(RESULT_DIR):
    os.makedirs(RESULT_DIR)

# list.txt에서 RSS URL 읽기
with open('list.txt', 'r', encoding='UTF-8') as file:
    rss_urls = file.readlines()

    # 각 RSS URL별로 처리
    for index, url in enumerate(rss_urls):
        # 공백 제거
        url = url.strip()

        # RSS 파싱
        feed = feedparser.parse(url)

        # 워크북 생성
        wb = Workbook()
        ws = wb.active
        ws.title = f"{index+1}번째 Data"

        # 헤더 추가
        ws.append(["제목", "링크", "요약", "작성자", "날짜"])

        # 데이터 추가
        for entry in feed.entries:
            row = [
                entry.title,
                entry.link,
                entry.description,
                entry.author,
                entry.published
            ]
            ws.append(row)

        # 엑셀 파일 저장
        file_path = os.path.join(RESULT_DIR, f'{index+1}_result.xlsx')
        wb.save(file_path)
        print(f"✅ {index+1}_result.xlsx 생성 완료!")

# ========== Step 2: 디렉터리 압축 ==========

zip_file = zipfile.ZipFile("result.zip", "w")

for root, dirs, files in os.walk(RESULT_DIR):
    for file in files:
        file_path = os.path.join(root, file)
        zip_file.write(file_path)

zip_file.close()
print("✅ result.zip 압축 완료!")

# ========== Step 3: FTP 서버에 업로드 ==========

hostname = "192.168.134.128"
ftp = ftplib.FTP(hostname)
ftp.login('msfadmin', 'msfadmin')

print(f"\n📂 FTP 현재 디렉터리: {ftp.pwd()}")
print("📋 업로드 전 파일 목록:")
ftp.retrlines('LIST')

# ZIP 파일 업로드
with open("result.zip", "rb") as f:
    ftp.storbinary("STOR result.zip", f)

print("\n✅ result.zip FTP 업로드 완료!")
print("📋 업로드 후 파일 목록:")
ftp.retrlines('LIST')

ftp.quit()

실행 결과 📊

✅ 1_result.xlsx 생성 완료!
✅ 2_result.xlsx 생성 완료!
✅ 3_result.xlsx 생성 완료!
✅ result.zip 압축 완료!

📂 FTP 현재 디렉터리: /home/msfadmin
📋 업로드 전 파일 목록:
-rw-r--r-- 1 msfadmin msfadmin 1024 NOV 12 12:30 example.txt
-rw-r--r-- 1 msfadmin msfadmin 2048 NOV 12 14:15 malwares.txt

✅ result.zip FTP 업로드 완료!
📋 업로드 후 파일 목록:
-rw-r--r-- 1 msfadmin msfadmin 1024 NOV 12 12:30 example.txt
-rw-r--r-- 1 msfadmin msfadmin 2048 NOV 12 14:15 malwares.txt
-rw-r--r-- 1 msfadmin msfadmin 5120 NOV 12 16:45 result.zip


📋 전체 흐름도

┌─────────────────────────────────────────┐
│  list.txt 파일 읽기                     │
│  (RSS URL 목록)                        │
└──────────────┬──────────────────────────┘
               ↓
┌─────────────────────────────────────────┐
│  feedparser로 RSS 파싱                   │
│  (각 URL에서 뉴스 정보 수집)            │
└──────────────┬──────────────────────────┘
               ↓
┌─────────────────────────────────────────┐
│  openpyxl로 엑셀 파일 생성               │
│  (1_result.xlsx, 2_result.xlsx, ...)    │
└──────────────┬──────────────────────────┘
               ↓
┌─────────────────────────────────────────┐
│  zipfile으로 압축                        │
│  (result.zip 생성)                     │
└──────────────┬──────────────────────────┘
               ↓
┌─────────────────────────────────────────┐
│  ftplib으로 FTP 업로드                   │
│  (result.zip을 서버에 전송)             │
└─────────────────────────────────────────┘

🎯 핵심 개념 요약

✅ 학습한 주요 기능

  • 워크북 생성 및 저장
  • 워크시트 관리 (생성, 이름변경, 삭제)
  • 셀 데이터 입력/수정/삭제
  • 범위 데이터 읽기
  • 수식 적용 및 계산
  • 웹 크롤링과 결합
  • RSS 피드 자동화
  • FTP 연결: 서버 접속, 로그인, 종료
  • 디렉터리 관리: 생성, 삭제, 이동, 확인
  • 파일 업로드: storbinary() 메서드
  • 파일 다운로드: retrbinary() 메서드
  • 파일 압축: zipfile 라이브러리
  • 자동화: RSS → 엑셀 → 압축 → FTP 통합

🚨 보안 주의사항

⚠️ FTP 보안 문제

  • FTP는 평문 전송 (암호화 없음)
  • 비밀번호가 노출될 위험
  • 본격적인 운영환경에서는 SFTP 사용 권장

권장 사항

  • 테스트 환경에서만 사용
  • 별도의 FTP 계정 생성
  • 정기적인 로그 확인
  • 크리덴셜 정보는 설정 파일에 분리 저장

오늘도 정리 끝!!!! 다행히 오늘은 좀 할 만 한...