블로그 이미지
자유로운설탕

calendar

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Notice

'파이썬'에 해당되는 글 1

  1. 2017.04.19 구글로 공부하는 파이썬 - 14교시 (작업 자동화)
2017. 4. 19. 20:34 프로그래밍

  이번 시간에는 작업 자동화라는 주제를 진행해 보려고 한다. 뭐 그다지 거창한건 아니라는걸 먼저 밝힌다. '작업' 이라는 것은 이전 시간에 얘기했던 웹이나, GUI 등 다른 자동화의 측면도 포함되는 주제지만, 좀더 단순하게 축소해서 윈도우 상에서 작업 하는 여러 자잘한 일들을 파이썬을 이용해서 쉽게 동작되게 만드는 과정이라고 정의해 보자.

 

  예제로는 하위 폴더를 가진 특정 폴더에서 특정한 확장자 들을 가진 파일 들만 zip 으로 압축하여, ftp 에 업로드 한후, 로컬에서 기간이 오래된 zip 파일을 삭제하는 작업을 순차적으로 진행하는 파이썬 프로그램을 만들려고 한다. 그리고 마지막으로 해당 작업을 주기적으로 실행 할때 사용할 수 있는 방법에 대해 살펴 보려 한다. 해당 기능을 구현할때 오직 파이썬 모듈들만을 이용해서 구현이 가능 할 수도 있겠지만, 여기서는 윈도우에서 지원하는 몇 가지 명령어와 무료 압축 프로그램인 7-zip 등을 이용해, 파이썬 코드에서 호출을 통한 구성을 해보려고 한다.

 

 

[목차]

0. 왜 파이썬 공부에 구글을 이용하는게 좋은가?

1. 언어를 바라보는 방법. 파이썬을 어떻게 바라봐야 할까?

2. 파이썬 설치와 환경, 버전 선택 하기의 이유.

3. 만들고자 하는 기능을 모르는 조각으로 나눠 조사해 보기

4. 데이터 베이스에서 내용 가져와 출력하기

5. 암호화 모듈을 이용해 암복호화 해보기

6. 퍼즐 조각들을 합쳐보기

7. 엑셀 파일 사용해 보기 -> 부록 : fuction 을 이용해서, 코드 정리해 보기

8. 정규표현식을 왜 사용해야 할까? 언어속의 미니 언어 정규표현식 살펴보기

9. 입력과 결과를 GUI 화면과 연결해 보기

10. Whois API 이용해 보기

11. 웹페이지 호출해 내용 파싱 하기(BeautifulSoup 그리고 한계)

12. 자동화 - 웹 자동화(with Selenium)

13. 자동화 - 윈도우즈 GUI 자동화(with pywinauto)

14. 자동화 - 작업 자동화

15. 수학 라이브러리 살펴보기

16. 그래픽 라이브러리 살펴보기

17. 머신러닝에서의 파이썬의 역활

18. 웹 프로그래밍 - Legacy Web

19. 웹 프로그래밍 - Flask 살펴보기(feat. d3.js)

20. 웹 프로그래밍 - Django 살펴보기

21. 정리 - 이런저런 이야기

 

 

 

[들어가면서]

  작업 자동화에 대해 어떻게 얘기를 풀어볼까 하다가 옛날 얘기로 시작해 보려 한다. 예전에 윈도우가 나오기 전에 도스란 cmd 타입의 OS 만 있을때의 컴퓨터는 지금 x-windows 를 사용안하는 리눅스 서버와 비슷한 모드로, 모든 작업이 까만 cmd 화면에서의 명령어 중심으로 이루어져 있었다(물론 그 안에서도 여러가지 트릭을 사용해서 그래픽으로 표시는 했었다). 도스 기반으로 컴퓨터를 처음 접했던 사람들은 아직도 윈도우, 맥 화면의 PC 나, 스마트 폰의 화려한 화면을 볼때도 왠지 뒷면에 놓여있는 cmd 창의 존재를 쉽게 떨쳐버리진 못할 것 이다.

 

  윈도우즈 또한 많은 부분이 GUI 로 감싸 이루어져 있어, 거의 cmd 창을 사용 안하더라도 가능한 부분들도 많지만, GUI 화면으로는 복잡하게 해야되는 일들을 좀더 간단하게 만들어주는 여러 유용한 명령어라든지, 서버 관리자용 확장쉘인 powershell 이라든지 하는 컴퓨터 관리에 도움을 주는 텍스트 기반의 툴들이 많이 내장되어 있다. 리눅스 또한 여러 쉘이나 유틸 기반의 유용한 툴들이 많으며, 어찌보면 GUI 로 구현된 화면들은 그러한 명령어 기능 중에 사람들이 자주 쓸 것 같은 기능들을 편하게 사용하도록 구현된거라고 봐도 무방할 듯 하다. 그래서 윈도우즈 10같이 점점 사용자들이 잘 안쓰는 디테일한 기능들을 디폴트로 숨기는 최신 OS 의 경우 이것저것 시스템을 건드리는 작업이 필요한 사람들 한테는 어떻게 보면 불편한 느낌까지도 주게되는 것 같다.

 

  뭐 여튼 그래서, 파일 관련 여러 작업들(복사, 압축, 백업..) 등의 기본적인 작업 들에 대해서는 대부분의 언어에서 지원하는 라이브러리보다 시스템에서 기본, 확장 지원 하는 기능들을 호출하여 사용하는 것이 좀더 효율 적인 경우도 있게 된다. 적당히 해당 명령어를 실행하고, 결과가 완료 되기만 기다릴 수 있다면, 어떤 언어를 사용하든 비슷한 효과를 가진 프로그램을 쉽게 만들 수 있게 될 것이다.

 

 

 

[무료 ftp 설치하기]

  그럼 실습을 위해서, 무료 ftp 를 하나 설치해서 운영해 보려 한다. ftp 는 'file transfer protocol' 의 약자로, 서버와 클라이언트 사이에서 서로 파일을 교환하기 위한 오래된 방식이다. 해당 방식을 이용해서, 클라이언트의 파일을 원격지에 있는 서버의 특정 폴더로 이동 등의 작업이 가능하다. 뭐 요즘으로 따지면 구글 드라이브 등의 클라우드, 웹 드라이브와 기능이  비슷하다고 봐도 무방할 듯 하다. 비슷한 용도로 쓰이는 개념으로는 공유 폴더 같은게 있다. 개인적으로 사용하고 있는 ftp 가 있다면 소스의 ftp 코드의 연결 부분만 바꾸어서 그 쪽에서 실습해도 된다.

 

 

[ftp 서버 설치]

  구글에서 'free ftp' 라고 검색하여, 파일질라를 사용하기 위해 https://filezilla-project.org/ 페이지로 이동한다. 'Download FileZiller Server' 버튼을 클릭하고, 다음 페이지에서 소스포지에서 'Download Now' 버튼을 클릭 한다.

 

  다운로드한 파일을 실행을 하여 디폴트로 설치를 진행 하다가, 테스트로 설치한 ftp 가 계속 실행 되고 있는게 좋을 건 없으니 시작 유형만 'Start Manually' 로 바꿔준다.

 

 

  설치 완료 후 '모든 프로그램' > 'FileZiller Server' > 'FileZiller Server Interface' 를 실행 한다. 아래의 다이얼로그가 나오면 'Connect' 버튼을 누른다. 그럼 서버가 실행 되게 된다.

 

  그럼 익명 사용자로 사용해도 되긴 하지만, 아무나 자기 서버에 들어와 사용하는건 그러므로, 사용자를 등록해 세팅해 보자. 그전에 우리가 매 시간 코드를 실습했던 c:\python\code 폴더에 아래와 같이 실습에 사용할 2개의 폴더를 만들어 보자

c:\python\code\ftproot

c:\python\code\ftproot\mybackup

 

  그 후 'Edit' > 'Users' 메뉴를 선택해 보자. 

 

  'Users' 창이 나오면 왼쪽에서 'General' 항목을 선택하고(기본이긴 하다), 오른쪽 'Users' 섹션에서 'Add' 버튼을 클릭한다. 이후 'Add user account' 다이얼로그가 뜨면, 'pyftpuser' 라고 사용자 이름을 넣고, 'OK' 버튼을 누른다.

 

   그리고 패스워드를 'test1234' 라고 적어 준다. 그럼 사용자의 id/pass 가 정해졌다.

 

  사용자를 생성하였으니 그 담에는 사용자에게 사용 가능한 특정 폴더를 할당해 주어야 한다. 사용자가 로그인 하였을때 해당 폴더가 디폴트로 보이며, 해당 폴더 안에서만 이런저런 작업이 가능하다(리눅스의 유저 기본 폴더와 같은 개념이다). 왼쪽에서 'Shared folders' 항목를 선택하고, 아래쪽 'add' 버튼을 눌러서 아까 만든 'c:\python\code\ftproot' 폴더를 선택한다. 이후 오른쪽의 체크 박스를 다 체크해서 해당 폴더에 대해서 풀 권한을 준다. 그리고 맨 하단의 'OK' 버튼을 눌러서, 'Users' 다이얼로그 창을 닫고 메인창으로 온다. 그럼 ftp 운영을 위한 설정이 모두 완료되게 된다.

 

 

[ftp 서버 동작 확인]

  그럼 파이썬 코드를 작성하기 전에, 세팅한 ftp 의 정상 동작을 확인해 보도록 하자(반드시 외부에서 쓰이는 프로그램들은 파이썬 코드를 만들기 전에 다른 외부 수단으로 기본 동작을 확인해 보는게 좋다. 그래야 파이썬 코드에서 연결 에러가 발생 시, 서버 세팅 문제가 아니라 코딩이나 모듈 잘못이라고 체크 하기가 쉬워 덜 헤메게 된다). 아까 파일질라 홈페이지에 있던 클라이언트를 설치해 확인해도 되지만, 그럼 또 클라이언트 사용법도 익혀야 되니, 간단히 하기 위해 브라우저를 하나 띄운 후 주소창에 ftp://localhost 라고 입력한다. 그럼 id/password 를 입력하라는 창이 뜨게 된다(시스템 환경에 따라 좀 느릴 수도 있다). 아까 설정한 pyftpuser/test1234 를 넣는다.

 

  그럼 ftp 에 연결되면서 아까 우리가 c:\python\code\ftproot 안에 만들어 놓은 'mybackup' 폴더가 보이게 된다. (/ 로 표시되는 사용자의 현재 폴더가 ftproot 폴더이다)

 

 

 

 

[7-zip 설치하기]

  그럼 마찬가지로 실습을 하기 필요한 7-zip 이라는 무료 zip 프로그램을 설치해 보자. 구글에서 '7zip' 이라고 검색하여, http://www.7-zip.org/ 로 이동한다.

 

  아래의 다운로드 링크에서 '64비트' 다운로드 링크(제 컴퓨터가 windows 10 home 64bit 라서 그렇다)를 클릭하여 설치한다. 설치 할때는 특별히 신경 쓰지 말고 디폴트 옵션으로 설치하면 된다.

 

 

 

[테스트 파일 준비하기]

  우리가 매일 실습하던 c:\python\code 폴더에 아래와 같이 실습에 사용할 4개의 폴더를 만들어 보자.

c:\python\code\source  (원본 폴더)

c:\python\code\source\subfolder   (원본폴더 서브 폴더)

c:\python\code\target   (복사할 폴더)

c:\python\code\zipfile    (압축 파일 떨굴 폴더)

 

 

  c:\python\code\source 폴더에 png 파일 한개와, txt 파일 한개, ini 파일 한개, exe 파일 한개를 넣어보자. 저 같은 경우 아래 같이 넣었다.

mypic.png
win.ini
winhlp32.exe
사고싶은 책.txt

 

  c:\python\code\source\subfolder 에는 txt 파일 한개를 넣어보자(원래 샘플 파일을 첨부 할까 하다가 왠지 사람들이 다운받기는 찜찜해 할 듯 싶어서 직접 만드는 것으로 했다). 아래와 같이 넣었다.

     사고싶은 책 2.txt

 

  png 파일은 캡쳐 도구 등으로 만들면 되고, txt 파일은 메모장 등으로 적당히 만들면 되고, ini, exe 파일은 c:\windows 폴더에서 복사(시스템 파일이니 옮기면 안된다 복사!!)해서 장만했다. 이렇게 여러 개의 확장자를 가진 파일을 만드는 이유는, 이 중 2개 정도의 확장자를 가진 파일만 선택적으로 압축하는 예제를 보여주고 싶어서이다. 실제 소스등을 백업하려다 보면 용량만 차지하고 백업은 필요없는 파일도 있기 때문에 제외하기 위해서 이다. 뭐 대충 아래와 같은 모양이다.

 

 

 

 

[파이썬 코드 만들기]

  이제 모든 밑작업이 완료 되었으니, 코드 작성을 시작해 보자. 우리가 만드려는 기능을 위해 현재 필요한 사항들을 아래와 같다.

  1) 특정 폴더에서 특정 확장자들의 파일만 서브 디렉토리 까지 포함해서 zip 으로 압축 하기

  2) 압축이 끝날때까지 기다리기

  3) 압축 된 내용을 ftp 에 올리기

  4) 7일 지난 오래된 zip 파일은 하드 용량을 줄이기 위해 삭제 하기

 

  모든 내용이 다 앞의 수업에서는 다루진 않았던 거니 하나하나 살펴보도록 하자.

 

 

[zip 만들기와 기다리기 구현]

  우선 zip 을 만드는데, 2가지 제약 사항이 있다. 첫째는 서브 폴더까지 포함되서 압축이 되야하며, 둘째는 특정 확장자 파일만을 선택 적으로 압축해야 한다. 구글에서 'python zip only extension' 라고 찾으면 아래의 python 에서 사용하는 zip 모듈이 나온다.

https://docs.python.org/2/library/zipfile.html 

 

  해당 모듈을 사용해서 특정 확장자를 포함하려 하면, 아래와 같은 스택 오버플로우에 나오는 방식처럼 특정 확장자를 하나 하나 이름에서 체크하면서, 압축 하거나 풀어야 할것 같다.

http://stackoverflow.com/questions/41965026/extracting-all-the-files-of-a-selected-extension-from-a-zipped-file

 

 

  좀더 간단하게 명령어 하나로만 완료해 보려고 7-zip을 이용하기 위해서, 다시 구글에서,  '7zip include extensions' 이라고 찾았다.

https://superuser.com/questions/409456/how-do-i-use-7-zip-to-add-a-folder-to-an-archive-including-only-files-with-cert

 

  그런데 위에 나타난 방법은 7-zip 명령어 하나만 사용해 구현할 수 있지만, 우리가 원하던 바와는 반대로 특정 확장자들을 포함 하는게 아니라, 특정 확장자들만 제외하는 것이다. 빼야하는 확장자를 잘 알고 압축해야 할 확장자를 잘 모를 경우엔 유용하지만, 반대로 압축해야 될 확장자를 잘알고, 빼야하는 확장자가 많거나 늘어날 수 있다면 조금은 귀찮은 일이다.(뭐 빼는 것도 나쁜건 아닌거 같지만 이렇게 가정해 보자^^) 

 

 

 

  일단은 원하는 확장자만를 압축하는 방식을 찾기 위해서 조금 더 검색을 해본다. 구글에서 '7zip only some extensions' 라고 검색해서 아래와 같이 2개의 페이지를 보다보면. cmd 에서 이용할 수 있는 for 명령어를 사용해서 특정 확장자를 가진 각 파일들을 하나씩 선택해서, zip 으로 만드는 예제가 있다. 그래서 왠지 구현이 잘 될거 같아서, 아래와 같이 만들어 실행해 보았다(몇 가지 테스트를 해보니 아래 페이지들에서 제시된 명령어 그대로 실행 하려면 bat 파일 안에서만 수행이 되며, cmd 창에서 바로 호출해 쓰려면 인자의 %% 를 %로 바꾸어야 한다)

https://superuser.com/questions/923775/7zip-batch-compression-for-a-specific-file-extension-in-different-folders

http://stackoverflow.com/questions/19848192/a-batch-script-to-zip-only-certain-types-of-files 

1
for /R C:/python/code/source %x in (*.txt *.png) do ("c:\Program Files\7-Zip\7z" a "myzip.zip" "%x" )
cs

 

  cmd 창에서 아래 명령을 입력한다.

c:\Python\code>for /R C:/python/code/source %x in (*.txt *.png) do ("c:\Program Files\7-Zip\7z" a "myzip.zip" "%x" )

c:\Python\code>("c:\Program Files\7-Zip\7z" a "myzip.zip" "C:\python\code\source\사고싶은 책.txt"  )

7-Zip [64] 16.04 : Copyright (c) 1999-2016 Igor Pavlov : 2016-10-04

Open archive: myzip.zip
......
Files read from disk: 1
Archive size: 9223 bytes (10 KiB)
Everything is Ok

 

  압축된 zip 파일을 보면 zip 명령어는 넘어온 파일들의 상대 경로를 따지지 않아서, 모든 파일이 하나의 폴더에 들어가 있다. 아래의 그림을 보면 alzip 으로 열었을때, 서브폴더의 파일도 정상적으로 가져오긴 하지만 원래는 source 폴더 안의 subfolder 에 들어가 있어야 할 '사고싶은 책 2.txt' 가 루트에 '사고싶은 책.txt'와 같이 저장되 있는게 보일 것이다. 그럼 해당 방식은 디렉토리 구조를 유지 못하고, 만약 이름이 같은 파일이 있을 경우 충돌이 날테므로 사용할 수 없다.

 

 

 

  그럼 명령어 하나로는 조금 힘들겠다고 생각하고, 2개로 나누어 실행하는 방식으로 다시 전략을 짜보자. 첫번째는 아까 만들어 놓은 target 폴더로 특정 확장자들을 가진 파일들만을 폴더 구조를 유지하면서 복사 후, 7-zip 을 이용하여 원하는 파일만 들어있는 target 폴더를 압축하면 된다. target 폴더의 파일과 디렉토리 들은 압축 완료 후 삭제하여 처음 상태로 리셋하면 된다. 만약 백업 대상 파일 용량이 크거나 숫자가 많아 복사가 부담스러운 경우엔 맨 처음에 찾아봤던 특정 확장자 들을 제외하는 방식으로 구현해도 좋겠지만, 그 경우는 zip 방식이 아닌 폴더 자체를 원격지 폴더와 싱크 시키는 다른 프로그램 등을 이용하는게 더 날지도 모르겠다.

 

  그럼 일단 특정 확장자들만 복사하는 명령어를 찾기위해 구글에서 이것저것 헤메다가 'xcopy copy only certain file extensions' 로 검색해, 앞에 보았던 for 명령을 이용해 파일을 xcopy 명령어로 넘겨서 복사하는 코드를 찾았다.

http://stackoverflow.com/questions/15753420/how-to-copy-specific-file-types-from-one-folder-into-another-folder 

1
for %x in (png txt) do xcopy "c:\python\code\source\*.%x" "c:\python\code\target\" /S /Y
cs

  위의 xcopy 옵션은 아래와 같다. 옵션이 궁금하면 cmd 창에서 'xcopy /?' 를 입력해 본다. 

 /S           비어 있지 않은 디렉터리와 하위 디렉터리를 복사합니다.

 /Y           기존 대상 파일을 덮어쓸지 여부를 묻지 않습니다.

 

 

  해당 명령어를 cmd 창에 입력하면 앞의 zip 과는 달리 다행히 정상적으로 서브 폴더까지 유지되면서 특정 확장자만 복사가 된다.

c:\Python\code>for %x in (png txt) do xcopy "c:\python\code\source\*.%x" "c:\python\code\target\" /S /Y

c:\Python\code>xcopy "c:\python\code\source\*.png" "c:\python\code\target\" /S /Y
C:\python\code\source\mypic.PNG
1개 파일이 복사되었습니다.

c:\Python\code>xcopy "c:\python\code\source\*.txt" "c:\python\code\target\" /S /Y
C:\python\code\source\사고싶은 책.txt
C:\python\code\source\subfolder\사고싶은 책 2.txt
2개 파일이 복사되었습니다.

 

 

  그럼 이제 target 폴더만 이제 전체 압축하면 된다. 7-zip 명령어를 사용하는데 이왕이면 'backup_현재날짜.zip' 으로 날짜를 포함하게 압축파일 이름을 지정하고 싶어서 구글에서 'cmd file name date' 로 검색해 아래 페이지와 참조해서 명령어를 만들어 낸다.

http://stackoverflow.com/questions/4984391/cmd-line-rename-file-with-date-and-time

1
"c:\Program Files\7-Zip\7z" a c:\python\code\zipfile\backup_"%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%".zip c:\python\code\target
cs

 

  위의 명령어를 cmd 창에 입력하면, 우리가 원하는 데로 정상적으로 압축되는 것을 볼 수 있다. 

c:\Python\code>"c:\Program Files\7-Zip\7z" a c:\python\code\zipfile\backup_"%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%".zip c:\python\code\target

7-Zip [64] 16.04 : Copyright (c) 1999-2016 Igor Pavlov : 2016-10-04

Open archive: c:\python\code\zipfile\backup_20170423.zip
...
Files read from disk: 3
Archive size: 9557 bytes (10 KiB)
Everything is Ok

 

 

  그럼 cmd 상으로 위의 명령어를 순차적으로 실행 시키면, 특정 확장자를 가진 파일들이 target 파일로 복사 된후, 'backup_현재날짜.zip' 로 압축되는 작업이 일어난다. 그럼 이젠 이용할 외부 로직은 다 해결 났으니, python 에서 해당 두 명령어를 순차적으로 실행해 주면서, 각각의 명령어가 끝날때까지 다음 코드의 실행을 안하고 기다리게 해야 한다. 구글에서 'python run windows cmd' 라고 검색하면 subprocess 모듈에 있는 'check_output' 명령어를 사용해 보라고 권한다. 근데 문제는 해당 subprocess 모듈로 cmd 명령을 실행 했을때, 실행한 명령이 끝날때까지 파이썬이 다음 코드를 실행 안하고 기다려 줄까 하는 부분이다.

http://stackoverflow.com/questions/14894993/running-windows-shell-commands-with-python

 

  해당 문제를 확인 하기 위해 'python subprocess check_output' 로 검색해 아래 파이썬 라이브러리 메뉴얼을 보면, 다행이 실행한 서브 프로세스가 끝날 때까지 기다린다고 한다(하나의 프로그램이 생성되면 윈도우 내부에 프로세스가 생성되고, 해당 프로세스가 다른 프로세스를 실행 했을때 해당 프로세스를 subprocess 또는 자식 프로세스라고 그런다). call 명령어는 성공 실패 코드만 반환해 가져오는 듯 하고, check_output 은 화면 출력등의 메시지도 받아 올수 있나 보다.

https://docs.python.org/2/library/subprocess.html

 

 

  그럼 첫번째 복사하는 cmd 명령어를 python 의 코드를 이용해서 호출해 동작하는지 검증해 보자.

1
2
3
4
import subprocess 
from subprocess import check_output
 
check_output('for %x in (png txt) do xcopy "c:\python\code\source\*.%x" "c:\python\code\target\" /S /Y', shell=True) 
cs

 

  위의 코드를 복사하여 'c:\python\code' 폴더에 'copytest.py' 라는 이름으로 'uft-8' 포맷으로 저장한다. 실행을 하면 계속 무한 루프가 나면서 이상하게 종료가 안된다. 'ctrl+z' 로 종료를 해본다.

c:\Python\code>python copytest.py

 

  흠 cmd 창으로 그대로 잘 실행됬던 명령어를 그대로 파이썬에서 실행했는데 에러가 나는 듯 하다. 왜 그런가 하고 상상의 나래를 펼치다가 보니 뭔가 하나 걸리는 게 있긴 하다. escape 문자 이다. escape 문자는 보통 어떤 언어에서든 문법적 요소로 쓰는 문자를 사용자의 문자열 안에 넣고 싶을때 해당 문자 앞에 적어주는 회피 문자 이다. 그 회피 문자를 보고 해당 언어는 이 문자가 문법 문자가 아닌 일반 표시 문자라는 것을 인식한다. 구글에서 'python string Double Quotation' 로 검색하면, 아래의 페이지에 escape 문자를 쓰는 방법이 나온다. 예를 들어 " 문자는 \" 로 넣어주어야 하는거다. (한국어 키보드 \(금액 표시) 문자가 밑의 예제 코드에 나오는 역 슬레쉬 이다). escape 문자는 '\n' 같이 키보드로 표시 못하는 기호를 표시할때도 쓴다.

https://docs.python.org/2.0/ref/strings.html

 

  이것 저것 조정해 보다보니 아래 코드로 정리됬다.

1
2
3
4
import subprocess 
from subprocess import check_output
 
check_output('for %x in (png txt) do xcopy \"c:\\python\\code\\source\\*.%x\" \"c:\\python\\code\\target\\\" /S /Y', shell=True) 
cs

 

  다시 실행해 보니 정상적으로 복사가 된다. 그럼 압축 하는 코드 까지 같이 적용해 만들어 보면 아래의 코드가 된다.

1
2
3
4
5
6
import subprocess 
from subprocess import check_output
 
check_output('for %x in (png txt) do xcopy \"c:\\python\\code\\source\\*.%x\" \"c:\\python\\code\\target\\\" /S /Y', shell=True) 
 
check_output('\"c:\\Program Files\\7-Zip\\7z\" a c:\\python\\code\\zipfile\\backup_\"%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%\".zip c:\\python\\code\\target', shell=True)
cs

 

  아래와 같이 실행 하면, cc:\Python\code\zipfile\ 폴더안에 backup_20170423.zip 파일이 생성되게 된다(날짜는 실행한 날짜별로 달라진다).

c:\Python\code>python copytest.py

 

 

 

[ftp 업로드 코드 만들기]

  그럼 만들어진 파일을 ftp 로 업로드하는 코드를 만들어 보려 한다. 구글에서 'python ftp upload' 로 검색을 하면, 아래의 스택오버플로우 페이지에서 바이너리와, 텍스트 형태의 파일을 각각 저장하는 ftp 샘플이 보인다.

http://stackoverflow.com/questions/17438096/ftp-upload-files-python

 

  추가로 만들어진 zip 파일 이름이 'backup_yyyymm' 형식이기 때문에 구글에서 'python filename date' 라고 검색하여 아래 페이지에서 datetime 모듈을 통해 날짜로 이름을 만드는 코드를 얻을 수 있다.

http://stackoverflow.com/questions/10607688/how-to-create-a-file-name-with-the-current-date-time-in-python

 

  두 개의 코드를 합쳐서 아까의 만들어진 zip 파일이 올라가는 코드를 만들어 보면 아래와 같다. 이미 zip 파일은 만들어져 있을테니 위의 압축하는 코드는 일단 제외하고 ftp 코드 부분만 만들어 검증해 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#-*- coding: utf-8 -*-
import ftplib
import os
from datetime import datetime
 
# datatime 모듈을 사용하여 오늘의 압축 파일 이름을 생성
filename = "backup_" + datetime.now().strftime("%Y%m%d"+ ".zip"
 
# ftp에 연결
ftp = ftplib.FTP("127.0.0.1")
ftp.login("pyftpuser""test1234")
 
# ftp 에서 myback 폴더로 이동함
ftp.cwd("/mybackup")
 
# zip 파일이 있는 폴더로 이동
os.chdir(r"c:\python\code\zipfile")
 
# 바이너리 형태로 파일을 업로드 함
ftp.storbinary("STOR " + filename, open(filename, 'rb'))
 
print ('upload completed')
cs

 

  위의 코드를 'c:\python\code' 폴더에 'utf-8' 인코딩으로 'ftpuplodtest.py' 라고 저장 후 실행해 본다.

c:\Python\code>python ftpuplodtest.py
upload completed

 

  위와 같이 업로드가 완료되었다고 출력되며, ftp 로 로그인 시 사용자에게 할당된 폴더인, 'c:\Python\code\ftproot\mybackup' 폴더로 가보면 backup_20170423.zip 파일이 업로드되어 있다(하나의 컴퓨터에서 ftp 서버를 같이 실행해서, 로컬 경로에서 확인을 하긴 했지만, 실제 프로그램 입장에서는 원격에 있는 ftp 폴더에 업로드 된 것이다)

 

 

[임시파일 삭제와 오래된 zip 파일 삭제]

  target 폴더안에 복사된 폴더와 파일들이 압축 후에는 필요 없기 때문에, 모두 삭제 하기 위해서 구글에서 'delete file and directory in directory' 를 찾았는데, powershell 명령어 이외에는 파일만 지우거나, 폴더 자체를 삭제 하는거나 둘 중에 하나만 가능한 것 같다. 밑에 제시된 바와같이 target 폴더를 지우고 같은 이름의 빈 폴더를 다시 생성하는 방법으로 구현하려 한다(파일 삭제를 테스트 할때는 조심히 테스트 폴더를 만들어 그 안에서만 명령어를 사용하는게 좋다. 저도 code 폴더에서 이것저것 시도해 보다가, 만들어 놨던 샘플 파일들을 싹 지워 버려 블로그에서 주섬주섬 복원해야 했다 --;). 리눅스 rm 명령 처럼 사용법이 모호한 상태에서 잘못 날리게 되면 시스템 파일과 같은 중요한 파일들을 다 지워 버릴 수도 있다.)

1
2
3
4
5
6
7
8
9
#-*- coding: utf-8 -*-
import subprocess 
from subprocess import check_output
 
# target 폴더를 통채로 삭제
check_output('rd /s /q c:\\python\\code\\target', shell=True) 
 
# target 폴더 다시 생성
check_output('md c:\\python\\code\\target', shell=True)
cs

 

  위와 비슷하게 c:\python\code 폴더에 utf-8 인코딩으로 deltest.py 라고 저장해 실행하면 target 폴더 전체를 삭제 된 후, 같은 이름의 빈 폴더를 생성한 것을 볼수 있다.

c:\Python\code>python deltest.py

 

 

  마지막으로 오래된 zip 파일들을 삭제하는 코드이다. 여기서는 7일이 지난 파일을 삭제한다고 해보자. 구글에서 'cmd delete file older than' 이라고 찾으면 아래 스택오버플로우 페이지가 나온다. forfiles 라는 명령어를 통해 7일 이내의 파일을 찾아 각각의 파일에 대해서 del 로 삭제 하는 코드는 아래와 같다. (비슷하게 escape 처리를 했는데, " 문자는 ' 안에 들어 있을때는 굳이 escape 처리를 안해도 되는듯 해서 가독성을 위해 제외했다).

http://stackoverflow.com/questions/51054/batch-file-to-delete-files-older-than-n-days

1
subprocess.call('forfiles /p "c:\\python\\code\\zip " /s /m backup*.zip /d -7 /c "cmd /c del @path"', shell=True)
cs

 

  'check_output' 대신 'call' 을 사용한 이유는 1주일 이상된 파일이 없어 forfiles 결과가 없을 경우엔 에러가 나버리는데, 해당 에러를 출력하는 부분이 파이썬 코드에 영향을 주어서 아래와 같은 오류가 나서, 이것저것 고민하다가 call 은 에러가 나도 실행에 관계가 없어서 대체 했다. 
오류: 검색 조건에 해당되는 파일을 찾을 수 없습니다.
Traceback (most recent call last):
  File "deltest.py", line 7, in <module>

 

 

[최종 코드]

그럼 긴 헤멤을 거쳐서 만들어진 최종 코드는 아래와 같다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#-*- coding: utf-8 -*-
import ftplib
import os
from datetime import datetime
import subprocess 
from subprocess import check_output
 
# 압축 코드
# png, txt 파일만 source 폴더에서 target 폴더로 복사한다. 
check_output('for %x in (png txt) do xcopy \"c:\\python\\code\\source\\*.%x\" \"c:\\python\\code\\target\\\" /S /Y', shell=True) 
 
# 7-zip 을 이용해 backcup_yyyymmdd 형식으로 압축을 한다.
check_output('\"c:\\Program Files\\7-Zip\\7z\" a c:\\python\\code\\zipfile\\backup_\"%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%\".zip c:\\python\\code\\target', shell=True)
 
print ('zip completed')
 
 
# ftp 코드 
# datatime 모듈을 사용하여 오늘의 압축 파일 이름을 생성
filename = "backup_" + datetime.now().strftime("%Y%m%d"+ ".zip"
 
# ftp에 연결
ftp = ftplib.FTP("127.0.0.1")
ftp.login("pyftpuser""test1234")
 
# ftp 에서 myback 폴더로 이동함
ftp.cwd("/mybackup")
 
# zip 파일이 있는 폴더로 이동
os.chdir(r"c:\python\code\zipfile")
 
# 바이너리 형태로 파일을 업로드 함
ftp.storbinary("STOR " + filename, open(filename, 'rb'))
 
print ('ftp upload completed')
 
 
# 삭제 코드
# target 폴더를 지움
check_output('rd /s /q c:\\python\\code\\target', shell=True) 
 
# taget 폴더를 재생성
check_output('md c:\\python\\code\\target', shell=True)
 
# 7일 이상 된 로컬의 backup 일을 삭제 함
subprocess.call('forfiles /p "c:\\python\\code\\zipfile " /s /m backup*.zip /d -7 /c "cmd /c del @path"', shell=True)
 
print ('del completed')
 
cs

 

  해당 내용을 'c:\python\code' 폴더에 'utf-8' 인코딩으로 'fileftpbackup.py' 파일로 저장 후 아래와 같이 실행해 본다.

c:\Python\code>python fileftpbackup.py
zip completed
ftp upload completed
오류: 검색 조건에 해당되는 파일을 찾을 수 없습니다.
del completed

 

 

[해당 기능을 주기적으로 돌리기]

  해당 기능을 주기적으로 돌리는 부분도 반복 주기가 짧다면 파이썬의 timer 모듈 등을 사용하여 구현할 수도 있겠지만, 하루에 한 번이라든지 몇 시간에 한번씩 돌릴 예정이라면, 파이썬을 계속 실행시켜 놓는 것보단, 윈도우즈 경우 작업 스케줄러에 걸어놓음 컴퓨터가 재시작 해도, 알아서 지정된 시간이나, 간격으로 돌아가기 때문에 딱히 신경 안 쓰고 반복적으로 실행할 수 있다. 내용이 넘 길어 졌으니 해당 내용은 구글에서 '윈도우즈 10 작업 스케줄러' 로 찾아서 아래와 같은 블로그를 보면 된다. 실행할 프로그램은 'python c:\python\code\fileftpbackup.py' 식으로 등록하면 될듯 하다.

http://blog.naver.com/PostView.nhn?blogId=celine2011&logNo=220673965249&beginTime=0&jumpingVid=&from=search&redirect=Log&widgetTypeCall=true

 

  참고로 만약 실행시 콘솔이 뜨는게 싫다면 아래 안내된 바와 같이,

소스 확장자를 pyw 라고 바꾸어 실행만 하면, pythonw.exe 가 실행이 되면서 콘솔 창이 없는 사일런스 모드로 실행 되는 듯하다.

http://stackoverflow.com/questions/764631/how-to-hide-console-window-in-python

 

 

 

[마무리 하면서]

  어찌 보면 그다지 복잡하지 않은 기능을 꼬아서 복잡하게 설명한 것 같기도 하다 --; 요지는 작업 자동화를 할때 꼭 해당 언어의 스콥 안에서 작업할 필요는 없다는 것이다. 그러다 보면 오히려 외부 cmd 방식의 명령어를 이용하면 좀더 쉽게 구현할 수 있는 코드를 복잡하게 구현하게 되면서 시간이 낭비될 수도 있다. 특히 파일이나 디렉토리 등을 기반으로 하는 작업들은 for 나 forfiles 같이 일괄로 작업하는 명령어 들이나 powershell 기반의 명령어들이 있으니, 가능한 필요한 기능을 구글에 검색해서 가져다 쓰는 것도 좋은 것 같다. 특별한 사정이 없는 이상 내부 모듈이 있다고 꼭 그 모듈을 쓸 필요는 없다고 생각한다. 여튼 이렇게 해서 자동화 시리즈를 마무리 하고, 다음 시간에는 파이썬으로 접근해 보는 머신러닝에 발을 살짝 담궈보기 위한 사전 작업으로 파이썬의 몇몇 수학 라이브러리들이 하는 일들을 살펴보려고 한다.

 

 

[보충]

  최근에 내용을 다시 리뷰하다가, 7zip 으로 여러확장자의 파일이 디렉토리 구조까지 유지하면서 압축 가능하다는 부분을 알게 되었습니다(어쩐지 그런 명령어가 없는게 이상하긴 했습니다--;)

 

 왜 글 쓰는 시점에서 놓쳤는지 모르겠지만, 아래 링크를 보시면 있습니다.

https://stackoverflow.com/questions/28636349/7zip-cli-whitelist-files-to-add-by-extension

 

이 글의 샘플을 예로들면 아래와 같습니다. 삽질을 했네요;

c:\"Program Files"\7-Zip\7z a -r -tzip test.zip c:\python\code\source\*.txt c:\python\code\source\*.jpg

 

 

2017.4.23 by 자유로운설탕
cs
posted by 자유로운설탕
prev 1 next