매주 손으로 하던 일 하나를 골라, 내가 없어도 정해진 시간에 돌게 만드는 것까지. 여기까지가 30분입니다.
처음부터 어려운 걸 고르면 반드시 중간에 멈춥니다. 조건 셋을 다 만족하는 일을 하나만 고르세요.
예를 들면 이런 것들입니다. 매일 아침 몇 개 사이트에서 새 글 제목을 모아 파일로 남기기, 매주 엑셀 하나를 열어 숫자를 뽑아 요약 만들기, 매일 폴더를 훑어 어제 만든 파일 목록을 정리하기.
예제로는 매일 아침 관심 있는 사이트들에서 새 글 제목을 모아 파일로 남기는 일을 씁니다. 짧고, 안전하고, 실제로 쓸모가 있어서 첫 자동화로 적당합니다. 여러분 일로 바꿔도 뼈대는 그대로입니다.
여기서 잘 만들려고 하지 마세요. 지금 손으로 하는 순서를 그대로 옮기기만 합니다. 외부 라이브러리도 안 씁니다.
"""매일 아침 새 글 제목을 모아 파일로 남긴다."""
import random, time, urllib.request
from datetime import date
from pathlib import Path
from xml.etree import ElementTree
D = Path(__file__).resolve().parent
OUT = D.parent / "data"
OUT.mkdir(exist_ok=True)
FEEDS = [
# 여러분이 매일 들여다보는 곳으로 바꾸세요
"https://example.com/rss.xml",
]
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " \
"(KHTML, like Gecko) Chrome/126.0 Safari/537.36"
def fetch(url):
req = urllib.request.Request(url, headers={"User-Agent": UA})
with urllib.request.urlopen(req, timeout=15) as r:
return r.read()
def main():
lines, dead = [], 0
for f in FEEDS:
try:
root = ElementTree.fromstring(fetch(f))
for it in root.iter("item"):
t = (it.findtext("title") or "").strip()
u = (it.findtext("link") or "").strip()
if t:
lines.append(f"{t}\t{u}")
except Exception as e:
dead += 1
print(f"[skip] {f} — {e}") # 한 곳이 죽어도 계속 간다
time.sleep(random.uniform(1.2, 2.6))
out = OUT / f"{date.today():%Y-%m-%d}.txt"
out.write_text("\n".join(lines), encoding="utf-8")
print(f"{len(lines)}건 저장 → {out} (실패한 곳 {dead})")
if __name__ == "__main__":
main()
실행해서 파일이 생기는지만 확인하세요. 여기까지가 자동화가 아니라 도구입니다.
python daily/collect.py
수집처마다 try로 감싸고 실패 개수를 찍은 것. 이게 없으면 사이트 한 곳이 응답을 안 하는 날 전체가 멈추고, 아무 일도 안 일어났다는 걸 며칠 뒤에 압니다. 조용한 실패가 자동화에서 제일 비쌉니다.
이제 자동화가 됩니다. 윈도우 기준으로 적습니다.
schtasks /create /tn "MY\collect" ^ /tr "\"C:\Python312\pythonw.exe\" \"C:\myauto\daily\collect.py\"" ^ /sc daily /st 08:30 /f
python.exe가 아니라 pythonw.exe로 등록하세요. 그냥 python으로 걸면 실행될 때마다 검은 창이 튀어나와 하던 작업의 포커스를 뺏고, 무심코 닫으면 그날 것이 죽습니다.
그리고 작업 속성에서 "예약 시간을 놓친 경우 가능한 한 빨리 작업 시작"을 켜세요. 안 켜면 그 시간에 컴퓨터가 꺼져 있거나 업데이트로 재부팅 중이었을 때 그날은 통째로 건너뜁니다.
launchd를 씁니다. ~/Library/LaunchAgents/에 plist 하나를 두고 launchctl load. 개념은 같습니다 — 정해진 시각에 인터프리터가 스크립트를 부르는 것.
스케줄러는 여러분의 환경변수도, 작업 폴더도 물려주지 않습니다. 손으로 실행할 땐 되던 게 예약으로 돌리면 안 되는 이유가 거의 이것입니다.
"""스케줄러가 부르는 단 하나의 파일. 환경은 여기서 다 세운다."""
import os, subprocess, sys
from pathlib import Path
D = Path(__file__).resolve().parent
os.chdir(D.parent) # 작업 폴더 고정
os.environ.setdefault("PYTHONIOENCODING", "utf-8") # 한글 출력이 깨지지 않게
r = subprocess.run([sys.executable, "daily/collect.py"],
capture_output=True, text=True,
encoding="utf-8", errors="replace")
print(r.stdout, r.stderr)
sys.exit(r.returncode)
등록도 이 파일 하나로 바꿉니다. 스케줄러에 넘기는 명령줄에는 길이 제한이 있어서, 인자가 늘어나면 조용히 잘립니다. 진입점을 하나로 두면 그 문제를 아예 안 만납니다.
예약을 걸어두고 다음 날 아침에 파일을 열어보는 건 확인이 아닙니다. 며칠은 그렇게 되다가, 안 보게 되고, 그 사이에 죽습니다.
"""오늘 것이 실제로 생겼는지 본다. 안 생겼으면 다시 돌린다."""
import subprocess, sys
from datetime import date
from pathlib import Path
D = Path(__file__).resolve().parent
EVIDENCE = D.parent / "data" / f"{date.today():%Y-%m-%d}.txt"
def ok():
# 파일이 있는 것만으로는 부족하다. 내용이 있어야 성공이다.
return EVIDENCE.exists() and EVIDENCE.stat().st_size > 0
if ok():
print("OK")
else:
print("오늘 것이 없다 — 다시 돌린다")
subprocess.run([sys.executable, str(D / "collect.py")])
print("복구 성공" if ok() else "복구 실패 — 사람이 봐야 한다")
이걸 몇 시간 뒤에 한 번 더 돌게 걸어두세요. 아침 8시 30분에 수집, 11시에 확인. 그러면 아침에 인터넷이 잠깐 끊겼어도 점심 전에 스스로 메꿉니다.
대부분의 자동화는 4단계가 없습니다. 그래서 두 달쯤 뒤에 조용히 멈춰 있고, 본인은 여전히 돌고 있다고 믿습니다. 감지만 하는 층은 만들지 마세요. 알림을 보내는 대신 다시 돌리는 게 낫습니다. 알림은 못 보는 날이 반드시 옵니다.
이 단계가 이 문서에서 제일 중요합니다. 30분 중에 5분을 여기 쓰세요.
대부분 이렇게 판정합니다 — 실행했더니 에러가 안 났으니 성공. 그런데 이 판정은 스크립트가 아무 일도 안 하고 끝났을 때도 통과합니다. 수집처 목록이 비어 있어도, 응답이 빈 값이어도 에러는 안 납니다.
성공은 상태로 판정해야 합니다. "이 일이 제대로 끝났다면 세상에 무엇이 남아 있어야 하는가"를 먼저 정하고, 그게 있는지를 봅니다. 위 check.py가 파일의 존재만이 아니라 크기까지 본 이유가 이것입니다.
나쁜 판정 좋은 판정 ───────────────────────────────────────────────────────── 에러 문구가 없다 → 오늘 날짜 파일이 있고 비어 있지 않다 스크립트가 끝났다 → 줄 수가 최소 N개 이상이다 로그에 성공이라고 찍혔다 → 결과물을 다시 읽어서 형식이 맞다 내 화면에서 보인다 → 로그인하지 않은 상태에서도 보인다
마지막 줄은 발행·업로드류를 자동화할 때 꼭 필요합니다. 내 세션으로는 임시저장이나 비공개 상태도 보이거든요. 남의 눈에 보이는 것만 발행입니다.
다섯 개가 다 체크되면 이제 하나가 혼자 도는 상태입니다. 상태 지도로 치면 1에서 10으로 넘어온 거예요. 시간이 남기 시작하는 자리입니다.
하나가 돌기 시작하면 곧 두 개가 되고, 두 개가 되면 새로운 문제가 생깁니다. 무엇을 만들지 판정하는 층이 없어서 매일 성실하게 쓸모없는 걸 만들게 되고, 잰 값이 다음 결과물을 바꾸지 못해 몇 달 전 규격에 멈춰 있게 됩니다. 그리고 반드시 어느 날 전부 죽습니다.
1권은 그 다음을 다룹니다. 판정 게이트, 규격 단일 소스, 조립과 출고, 자가복구, 측정과 학습 폐루프, 실험 설계, 그리고 우리가 실제로 밟은 함정 마흔여덟 개. 26장 + 부록 6. 코드는 복사해서 AI에게 시키면 됩니다.
1권 「혼자 도는 발행」 보기