글

4월, 2026의 게시물 표시

윈도우 작업 스케줄러: 파이썬 경로와 작업 폴더 확인

작업 스케줄러에서는 파이썬 실행 파일, 스크립트 인자, 시작 폴더를 각각 지정해야 상대 경로 오류를 줄일 수 있습니다. 어떤 상황에서 적용하나요? 같은 코드가 터미널에서는 실행되는데 예약 실행에서 실패한다면 먼저 실행 계정과 현재 폴더를 확인하세요. 아래는 외부 연결 없이 진단 정보를 출력하는 스크립트입니다. 검증 범위: 아래 코드는 외부 서비스에 요청하지 않는 로컬 예제입니다. 실제 서비스 연결은 별도로 검증해야 합니다. 최소 예제로 동작 확인하기 from pathlib import Path import sys script_dir = Path(__file__).resolve().parent if "__file__" in globals() else Path.cwd() print("python:", sys.executable) print("cwd:", Path.cwd()) print("script_dir:", script_dir) assert Path(sys.executable).is_absolute() 결과는 어떻게 확인하나요? python에는 실제 실행 중인 인터프리터 경로가, cwd에는 현재 작업 폴더가 표시됩니다. 시작 폴더가 스크립트 폴더와 다를 수 있다는 점을 로그로 확인하세요. 실제 업무에 적용할 때 확인할 점 프로그램에는 가상환경의 python.exe 절대 경로, 인자에는 스크립트 절대 경로, 시작 위치에는 자료를 읽는 기준 폴더를 설정합니다. 네트워크 드라이브 문자는 예약 계정에서 없을 수 있으므로 승인된 UNC 경로와 권한을 확인하세요. 중복 실행 정책과 절전 후 놓친 작업 처리도 점검합니다. 공식 자료와 다음 단계 관련 공식 문서 에서 사용하는 버전의 기능과 제한을 확인하세요. 학습 경로: 업무 자동화 가이드 · 입력 오류 처리 작성: 로그 · 2026-10-17 수정: 확인되지 않은 경험담과 성능 보장 표현을 제거하고 예제·적용 조건·공식 근거를 보완했...

파이썬 가상환경으로 배포 의존성 정리하기

가상환경은 프로젝트의 패키지를 분리하는 도구이며, 만들기만 한다고 실행 파일 용량이 자동으로 줄어들지는 않습니다. 어떤 상황에서 적용하나요? 새 작업 폴더에서 필요한 패키지만 설치하고 동작을 확인한 뒤 의존성을 기록하세요. 아래 명령은 Windows 터미널에서 사용하는 예이며 이 글을 읽는 것만으로 실행되지는 않습니다. 검증 범위: 아래는 터미널 명령 예시입니다. 실제 설치·빌드·오프라인 배포를 실행한 결과가 아닙니다. 최소 예제로 동작 확인하기 python -m venv .venv .venv\Scripts\python.exe -m pip install requests .venv\Scripts\python.exe -m pip freeze .venv\Scripts\python.exe -m pip check 결과는 어떻게 확인하나요? freeze는 해당 환경에 설치된 패키지 버전을 보여 주고 check는 설치된 의존성 충돌을 점검합니다. 출력에는 직접 설치한 패키지의 하위 의존성도 포함될 수 있습니다. 실제 업무에 적용할 때 확인할 점 freeze 결과를 아무 환경에서나 재현 가능한 완전한 잠금 파일로 간주하지 마세요. Python 버전과 운영체제, 네이티브 라이브러리도 영향을 줍니다. 용량을 줄이려고 필요한 라이브러리를 임의로 삭제하기보다 사용하지 않는 의존성이 들어오는 경로를 조사하세요. 공식 자료와 다음 단계 관련 공식 문서 에서 사용하는 버전의 기능과 제한을 확인하세요. 학습 경로: 업무 자동화 가이드 · 입력 오류 처리 작성: 로그 · 2026-10-17 수정: 확인되지 않은 경험담과 성능 보장 표현을 제거하고 예제·적용 조건·공식 근거를 보완했습니다.

PyInstaller 리소스 누락: 파일 경로를 코드 기준으로 찾기

PyInstaller 배포에서 이미지나 설정 파일을 읽을 때는 현재 작업 폴더와 패키지 내부 파일 위치를 구분해야 합니다. 어떤 상황에서 적용하나요? 아래는 읽기 전용 리소스를 현재 모듈 파일의 위치를 기준으로 찾는 예제입니다. 실제 bundle에는 해당 파일이 데이터로 포함되어 있어야 합니다. 이 검사는 임시 폴더에서 경로 계산만 확인합니다. 검증 범위: 아래 코드는 외부 서비스에 요청하지 않는 로컬 예제입니다. 실제 서비스 연결은 별도로 검증해야 합니다. 최소 예제로 동작 확인하기 from pathlib import Path from tempfile import TemporaryDirectory def resource_path(module_file, name): return Path(module_file).resolve().parent / "assets" / name with TemporaryDirectory() as folder: module = Path(folder) / "app.py" asset = resource_path(module, "logo.txt") asset.parent.mkdir() asset.write_text("sample", encoding="utf-8") assert asset.read_text(encoding="utf-8") == "sample" print(asset.name) 결과는 어떻게 확인하나요? logo.txt가 출력됩니다. 배포할 때는 사용 중인 PyInstaller 버전의 add-data 또는 spec 설정으로 assets를 포함하고, 번들 안의 실제 상대 위치를 확인하세요. 실제 업무에 적용할 때 확인할 점 번들 내부 리소스와 사용자가 변경하는 설정은 다른 위치에 두어야 합니다. one-file 임시 해제 폴더에 수정 데이터를 저장...

PyInstaller exe 만들기: 먼저 onedir로 오류 확인하기

처음 실행 파일을 만들 때는 콘솔과 onedir 구성을 유지해 오류를 확인하고, 동작을 검증한 뒤 배포 옵션을 정하는 편이 좋습니다. 어떤 상황에서 적용하나요? 아래 명령은 main.py가 있는 프로젝트 폴더에서 사용할 예시입니다. Python과 패키지 버전, 대상 운영체제를 함께 기록하세요. 실제 빌드 결과는 의존성에 따라 달라집니다. 검증 범위: 아래는 터미널 명령 예시입니다. 실제 설치·빌드·오프라인 배포를 실행한 결과가 아닙니다. 최소 예제로 동작 확인하기 python -m pip install pyinstaller python -m PyInstaller --onedir --name WorkReport main.py 결과는 어떻게 확인하나요? 성공하면 dist 안에 앱과 필요한 파일이 생성됩니다. 배포 테스트에서는 Python이 설치되지 않은 별도 대상 환경에서도 실행되는지 확인해야 합니다. 빌드 명령 성공만으로 배포 검증이 끝나지는 않습니다. 실제 업무에 적용할 때 확인할 점 windowed 옵션은 콘솔 오류를 보이지 않게 하므로 개발 초기에 바로 사용하지 마세요. one-file은 시작 시 파일을 해제하는 방식이라 실행 특성이 달라질 수 있습니다. Windows 실행 파일은 대상 OS와 아키텍처에 맞는 환경에서 빌드하고 보안 경고를 임의로 끄도록 안내하지 않습니다. 공식 자료와 다음 단계 관련 공식 문서 에서 사용하는 버전의 기능과 제한을 확인하세요. 학습 경로: 업무 자동화 가이드 · 입력 오류 처리 작성: 로그 · 2026-10-17 수정: 확인되지 않은 경험담과 성능 보장 표현을 제거하고 예제·적용 조건·공식 근거를 보완했습니다.

Selenium 헤드리스 실행: 화면 크기와 종료 처리

헤드리스 모드는 브라우저 UI 없이 실행하는 옵션이며, 모든 페이지가 일반 창과 완전히 같은 상태가 되는 것을 보장하지 않습니다. 어떤 상황에서 적용하나요? 다음은 Chrome과 Selenium이 설치된 환경에서 로컬 data URL을 여는 예제입니다. 설치와 브라우저 실행이 필요한 수동 검증 예제로, 외부 사이트나 로그인 자료를 수집하지 않습니다. 검증 범위: 아래 코드는 문법을 점검한 GUI·브라우저 예제입니다. 이 사이트의 점검 환경에서는 실제 창 실행을 검증하지 않았으며 해당 실행 환경에서 수동 확인이 필요합니다. 최소 예제로 동작 확인하기 from selenium import webdriver from selenium.webdriver.chrome.options import Options options = Options() options.add_argument("--headless=new") options.add_argument("--window-size=1200,800") driver = webdriver.Chrome(options=options) try: driver.get("data:text/html,<title>Local demo</title><h1>Report</h1>") assert driver.title == "Local demo" print(driver.title) finally: driver.quit() 결과는 어떻게 확인하나요? 동작 환경에서는 Local demo가 출력되고 finally에서 브라우저가 종료됩니다. 제목이 다르거나 브라우저 생성에 실패하면 Chrome·Selenium 버전과 드라이버 준비 상태부터 확인하세요. 실제 업무에 적용할 때 확인할 점 뷰포트, 글꼴, 다운로드 경로와 화면 요소의 대기 조건을 명시하세요. 헤드리스 실행은 접근 권한 제한이나 봇 정책을 우회하는 ...

회사 프록시를 사용하는 파이썬 요청 설정 점검

프록시는 승인된 네트워크 경로를 설정하는 도구이며, 차단된 서비스의 접근 권한을 얻거나 정책을 우회하는 수단이 아닙니다. 어떤 상황에서 적용하나요? 아래는 프록시 주소 형식을 검사하는 로컬 코드입니다. 외부 서버에 연결하지 않습니다. 실제 프록시 서버와 인증 방식은 회사의 네트워크 관리자 안내에 맞춰야 합니다. 검증 범위: 아래 코드는 외부 서비스에 요청하지 않는 로컬 예제입니다. 실제 서비스 연결은 별도로 검증해야 합니다. 최소 예제로 동작 확인하기 from urllib.parse import urlparse def validate_proxy(url): parsed = urlparse(url) if parsed.scheme not in {"http", "https"} or not parsed.hostname: raise ValueError("프록시 주소 형식 오류") if parsed.username or parsed.password: raise ValueError("예제 설정에 자격 증명을 직접 넣지 마세요") return parsed.hostname, parsed.port assert validate_proxy("http://proxy.example.com:8080") == ("proxy.example.com", 8080) print("프록시 주소 형식 확인") 결과는 어떻게 확인하나요? 주소 형식 확인 메시지는 프록시 사용 가능 여부와 다릅니다. 실제 연결에는 방화벽·인증·인증서 정책이 추가로 영향을 줍니다. HTTPS 목적지에 사용하는 프록시 URL이 반드시 https 스킴이라는 뜻도 아닙니다. 실제 업무에 적용할 때 확인할 점 Requests의 명시적 proxies 인자와 환경변수 설정이 어떻게 적용되는지 확인하세요. 인증서 검증을 끄는 verify=Fals...

API 일일 한도 관리: 시도 횟수와 성공 횟수 나누기

API 한도 카운터는 제공자의 계산 기준에 맞춰야 하며, 실패 요청도 한도에 포함될 수 있습니다. 어떤 상황에서 적용하나요? 아래는 실행 전에 남은 요청 수를 확인하는 로컬 예제입니다. 예제의 limit=3은 설명용이며 실제 서비스의 일일 한도를 뜻하지 않습니다. 검증 범위: 아래 코드는 외부 서비스에 요청하지 않는 로컬 예제입니다. 실제 서비스 연결은 별도로 검증해야 합니다. 최소 예제로 동작 확인하기 class Budget: def __init__(self, limit): self.limit = limit self.attempted = 0 def reserve(self): if self.attempted >= self.limit: return False self.attempted += 1 return True budget = Budget(3) results = [budget.reserve() for _ in range(4)] assert results == [True, True, True, False] print(results) 결과는 어떻게 확인하나요? 네 번째 시도는 허용되지 않습니다. 요청이 실제로 성공했는지는 별도로 기록하세요. 재시도를 추가한다면 재시도도 reserve를 거쳐야 시도 수가 누락되지 않습니다. 실제 업무에 적용할 때 확인할 점 프로세스가 여러 개면 메모리 카운터만으로 일관성을 보장할 수 없습니다. 영속 저장소와 원자적 차감을 사용하고, 일일 한도가 초기화되는 시간대를 확인하세요. 분당·계정별·프로젝트별 한도가 동시에 있을 수 있으므로 하나의 sleep 값으로 모두 대체하지 않습니다. 공식 자료와 다음 단계 관련 공식 문서 에서 사용하는 버전의 기능과 제한을 확인하세요. 학습 경로: API·운영 가이드 · 인증 오류 확인 작성: 로그 · 2026-10-17 수정: 확인되지 않은 경험담과 성능 보장 표현을 제...

공유 폴더 백업 자동화: 복사 후 해시로 결과 확인

파일 백업은 복사 작업이 끝났다는 사실과 원본 내용이 보존됐는지를 구분해 확인해야 합니다. 어떤 상황에서 적용하나요? 아래는 임시 폴더 안에서 샘플 파일을 복사하고 SHA-256 값이 같은지 확인합니다. 실제 네트워크 공유 폴더에 쓰지 않습니다. 공유 경로에 적용할 때는 허용된 대상 경로와 계정 권한을 먼저 확인하세요. 검증 범위: 아래 코드는 외부 서비스에 요청하지 않는 로컬 예제입니다. 실제 서비스 연결은 별도로 검증해야 합니다. 최소 예제로 동작 확인하기 from pathlib import Path from tempfile import TemporaryDirectory import hashlib import shutil def digest(path): return hashlib.sha256(path.read_bytes()).hexdigest() with TemporaryDirectory() as folder: base = Path(folder) source = base / "source.txt" target = base / "backup.txt" source.write_text("report", encoding="utf-8") shutil.copy2(source, target) assert digest(source) == digest(target) print("내용 일치") 결과는 어떻게 확인하나요? 내용 일치가 출력됩니다. read_bytes는 파일 전체를 읽는 작은 예제이므로 큰 파일은 블록 단위로 해시를 계산하세요. 복사 중 원본이 바뀌는 상황은 별도 잠금이나 스냅샷 정책이 필요합니다. 실제 업무에 적용할 때 확인할 점 네트워크 단절, 같은 이름의 기존 백업, 심볼릭 링크와 접근 권한을 고려하세요. 원본을 지우는 동작을 백업과 묶지 말고 복구 시험도 수행해야 합니다. 예약 실행 계정에는 사용자...

오프라인 파이썬 패키지 설치: 대상 환경에 맞는 wheel 준비

오프라인 설치는 인터넷이 되는 환경에서 대상 Python·OS·아키텍처에 맞는 패키지와 의존성을 준비한 뒤 검증하는 과정입니다. 어떤 상황에서 적용하나요? 아래 명령은 온라인 준비 단계와 오프라인 설치 단계를 구분한 예시입니다. requirements.txt에는 실제 프로젝트에서 검증한 버전을 기록합니다. 다른 OS에서 받은 바이너리 wheel을 그대로 사용할 수 있다고 가정하지 마세요. 검증 범위: 아래는 터미널 명령 예시입니다. 실제 설치·빌드·오프라인 배포를 실행한 결과가 아닙니다. 최소 예제로 동작 확인하기 # 온라인 준비 환경 python -m pip download -r requirements.txt -d wheelhouse # 오프라인 대상 환경 python -m pip install --no-index --find-links=wheelhouse -r requirements.txt python -m pip check 결과는 어떻게 확인하나요? no-index는 패키지 인덱스에 접속하지 않고 준비한 위치에서 찾도록 합니다. 설치 성공 후에는 실제 프로그램의 import와 최소 작업까지 시험해야 합니다. 소스 배포만 받은 패키지는 추가 빌드 도구가 필요할 수 있습니다. 실제 업무에 적용할 때 확인할 점 온라인 준비 환경과 대상 환경이 다르면 pip download의 platform·python-version·implementation·abi 옵션을 검토하세요. 파일 전송 전에 출처와 해시를 확인하고 조직의 반입 절차를 따릅니다. 무조건 최신 패키지로 갱신하기보다 재현 가능한 버전 구성을 유지하세요. 공식 자료와 다음 단계 관련 공식 문서 에서 사용하는 버전의 기능과 제한을 확인하세요. 학습 경로: 업무 자동화 가이드 · 입력 오류 처리 작성: 로그 · 2026-10-17 수정: 확인되지 않은 경험담과 성능 보장 표현을 제거하고 예제·적용 조건·공식 근거를 보완했습니다.

파이썬 예외 처리: 예상한 입력 오류만 복구하기

try-except는 모든 오류를 숨기는 장치가 아니라, 예상한 실패를 구분하고 복구하거나 원인을 전달하는 구조입니다. 어떤 상황에서 적용하나요? 빈 입력과 숫자 변환 실패를 처리하는 작은 예제입니다. 예외 범위를 좁히면 프로그래밍 오류까지 정상적인 빈 값으로 바꾸는 문제를 줄일 수 있습니다. 검증 범위: 아래 코드는 외부 서비스에 요청하지 않는 로컬 예제입니다. 실제 서비스 연결은 별도로 검증해야 합니다. 최소 예제로 동작 확인하기 def parse_count(raw): try: value = int(raw) except (TypeError, ValueError) as exc: raise ValueError("건수는 정수로 입력하세요") from exc if value < 0: raise ValueError("음수 건수는 허용하지 않습니다") return value assert parse_count("12") == 12 for bad in ["", "abc", None, "-1"]: try: parse_count(bad) except ValueError: pass else: raise AssertionError("잘못된 입력을 허용했습니다") print("입력 오류 검증 완료") 결과는 어떻게 확인하나요? 정상 입력은 정수로 변환되고 네 종류의 잘못된 입력은 ValueError가 됩니다. from exc는 원래 변환 오류의 원인을 보존합니다. 화면에는 간단한 메시지를 보여 주더라도 내부 로그에서는 원인을 추적할 수 있어야 합니다. 실제 업무에 적용할 때 확인할 점 except Exception: pass는 실패를 감추기 쉽습니다. 네트워크 시간 초과, 인증 오류, 데이...

GUI 설정 JSON 저장: 기본값과 원자적 교체

설정 파일은 읽은 값의 자료형을 검증하고, 새 파일을 완성한 뒤 같은 위치에서 교체하면 중간 쓰기 실패에 대응하기 쉽습니다. 어떤 상황에서 적용하나요? 아래는 임시 폴더에서 저장과 재읽기를 확인합니다. 비밀번호를 저장하지 않고 화면 너비 같은 비민감 설정만 다룹니다. 원자적 교체는 보통 같은 파일시스템 안에서 수행해야 합니다. 검증 범위: 아래 코드는 외부 서비스에 요청하지 않는 로컬 예제입니다. 실제 서비스 연결은 별도로 검증해야 합니다. 최소 예제로 동작 확인하기 from pathlib import Path from tempfile import TemporaryDirectory import json import os with TemporaryDirectory() as folder: path = Path(folder) / "settings.json" temporary = path.with_suffix(".tmp") settings = {"window_width": 800, "theme": "light"} temporary.write_text(json.dumps(settings), encoding="utf-8") os.replace(temporary, path) loaded = json.loads(path.read_text(encoding="utf-8")) if not isinstance(loaded.get("window_width"), int): raise ValueError("너비는 정수여야 합니다") assert loaded == settings print(loaded) 결과는 어떻게 확인하나요? 저장한 두 설정이 다시 출력됩니다. 실제 앱에서는 파일이 없을 때 기본값을 쓰고, 손상된 JSON일 때는 원본을 보...

자동화 실행 로그 만들기: 화면 출력과 파일 기록 분리

실행 로그는 발생 시각·단계·결과를 구조적으로 남기고, 화면 표시와 보관용 로그를 분리하는 편이 좋습니다. 어떤 상황에서 적용하나요? 아래 예제는 logging으로 메모리 스트림에 기록해 로그 문구를 검증합니다. 실제 GUI를 띄우지 않습니다. GUI에 표시할 때는 메인 스레드에서 스트림의 메시지나 큐 이벤트를 읽어 위젯에 추가하세요. 검증 범위: 아래 코드는 외부 서비스에 요청하지 않는 로컬 예제입니다. 실제 서비스 연결은 별도로 검증해야 합니다. 최소 예제로 동작 확인하기 import io import logging stream = io.StringIO() handler = logging.StreamHandler(stream) handler.setFormatter(logging.Formatter("%(levelname)s %(message)s")) logger = logging.getLogger("work-demo") logger.setLevel(logging.INFO) logger.addHandler(handler) logger.propagate = False try: logger.info("job=%s result=%s", "daily", "completed") text = stream.getvalue() assert "job=daily result=completed" in text print(text.strip()) finally: logger.removeHandler(handler) handler.close() 결과는 어떻게 확인하나요? INFO 수준의 작업 결과 한 줄이 출력됩니다. 같은 로거에 핸들러를 반복 추가하면 메시지가 여러 번 표시될 수 있으므로 생성과 종료 수명을 관리해야 합니다. 실제 업무에 적용할 때 확인할 점 긴 작업의 모든 행을 화면에 계속 쌓으면 UI가 느려질 수 있습니...

Tkinter 진행 표시줄: 작업 완료 수와 화면 갱신 연결

진행 표시줄은 완료한 작업 수를 value에 반영하고, 전체 작업 수를 maximum으로 정해 표시합니다. 어떤 상황에서 적용하나요? 아래 예제는 Tkinter 창에서 세 단계의 모의 작업을 표시합니다. after는 콜백 실행을 예약하는 기능이며 실제 긴 작업을 백그라운드에서 실행하는 기능은 아닙니다. 화면이 필요한 예제입니다. 검증 범위: 아래 코드는 문법을 점검한 GUI·브라우저 예제입니다. 이 사이트의 점검 환경에서는 실제 창 실행을 검증하지 않았으며 해당 실행 환경에서 수동 확인이 필요합니다. 최소 예제로 동작 확인하기 import tkinter as tk from tkinter import ttk root = tk.Tk() root.title("작업 진행 예제") bar = ttk.Progressbar(root, maximum=3, mode="determinate", length=300) bar.pack(padx=20, pady=20) status = tk.StringVar(value="대기") ttk.Label(root, textvariable=status).pack(pady=10) def advance(done=0): bar["value"] = done status.set(f"처리 {done}/3") if done < 3: root.after(500, advance, done + 1) ttk.Button(root, text="시작", command=advance).pack(pady=10) root.mainloop() 결과는 어떻게 확인하나요? 시작 버튼을 누르면 처리 0/3에서 3/3으로 바뀝니다. 여기서는 완료를 흉내 낸 것이므로 실제 파일 처리에 연결하려면 완료 이벤트를 받아야 합니다. 시간만 흘렀다고 성공 건수를 증가시키지 마세요. 실제 업무에 적용할 때 확인할 점 여러 번 시작을 ...

Tkinter 작업 스레드와 Queue: 멈추지 않는 화면 구조

오래 걸리는 작업은 작업 스레드에서 수행하고, Tkinter 위젯 변경은 메인 스레드에서 큐를 읽어 처리합니다. 어떤 상황에서 적용하나요? 아래는 백그라운드 함수가 계산 결과를 Queue에 넣고 메인 스레드가 꺼내는 최소 예제입니다. GUI 없이 통신 구조를 시험합니다. 실제 앱에서는 root.after로 큐 확인 함수를 반복 예약하세요. 검증 범위: 아래 코드는 외부 서비스에 요청하지 않는 로컬 예제입니다. 실제 서비스 연결은 별도로 검증해야 합니다. 최소 예제로 동작 확인하기 from queue import Queue from threading import Thread events = Queue() def worker(numbers): try: events.put(("done", sum(numbers))) except Exception as exc: events.put(("error", type(exc).__name__)) thread = Thread(target=worker, args=([1, 2, 3],)) thread.start() kind, value = events.get(timeout=2) thread.join(timeout=2) assert not thread.is_alive() assert (kind, value) == ("done", 6) print(kind, value) 결과는 어떻게 확인하나요? done 6이 출력됩니다. Tkinter 콜백에서 events.get처럼 기다리는 호출을 직접 쓰면 화면이 멈출 수 있으므로 실제 GUI에서는 get_nowait와 Empty 처리를 사용해 즉시 반환해야 합니다. 실제 업무에 적용할 때 확인할 점 실행 중 창 닫기와 취소 신호를 처리하고 네트워크 호출에도 시간 제한을 두세요. 메인 스레드에서 종료를 무한 join으로 기다리지 않습니다. 스레드는 CPU 계산을 항상 빠르게 만드는 도구가 아...

여러 사이트 주소 입력 검증: HTTPS와 허용 호스트 확인

여러 사이트를 입력받을 때는 줄 단위로 나누고 URL 구조·허용 호스트·중복을 검증한 뒤 작업 대상으로 확정합니다. 어떤 상황에서 적용하나요? 사용자가 입력한 URL을 그대로 서버에서 요청하면 내부 주소 접근 같은 문제가 생길 수 있습니다. 아래는 자신이 관리하는 두 예시 호스트만 허용하는 로컬 입력 검사이며 실제 접속은 하지 않습니다. 검증 범위: 아래 코드는 외부 서비스에 요청하지 않는 로컬 예제입니다. 실제 서비스 연결은 별도로 검증해야 합니다. 최소 예제로 동작 확인하기 from urllib.parse import urlsplit, urlunsplit allowed = {"www.example.com", "docs.example.com"} def targets(text): result = [] for line in text.splitlines(): if not line.strip(): continue p = urlsplit(line.strip()) if p.scheme != "https" or p.hostname not in allowed or p.username or p.password: raise ValueError("허용된 HTTPS 주소만 입력하세요") if p.port not in (None, 443): raise ValueError("허용되지 않은 포트") normalized = urlunsplit((p.scheme, p.netloc.lower(), p.path or "/", p.query, "")) if normalized not in result: result.append(normalized) return result ...

블로그 글 공유 초안 만들기: 링크 스팸을 피하는 파이썬 예제

새 글을 다른 채널에 소개할 때는 각 채널의 독자에게 필요한 요약을 만들고, 실제 발행 전에 링크와 내용을 검토하는 방식으로 운영합니다. 검색 순위 조작을 목적으로 같은 문구와 링크를 대량 배포하는 자동화는 피해야 합니다. 공유와 링크 스팸의 차이 공유문이 그 채널의 독자에게도 독립적인 정보를 제공하는지 확인하세요. 제목과 URL만 여러 계정에 반복 게시하거나, 원문 전체를 그대로 복제하거나, 링크를 얻는 것만 목표로 운영하면 콘텐츠 품질과 플랫폼 정책 문제가 생길 수 있습니다. 외부 전송 없이 공유 초안 만들기 다음 Python 3 코드는 공유할 제목과 URL을 정리할 뿐, 소셜 계정에 로그인하거나 게시하지 않습니다. from urllib.parse import urlparse import json url = "https://www.goodkyoungs.com/p/automation.html" parts = urlparse(url) if parts.scheme != "https" or parts.hostname != "www.goodkyoungs.com": raise ValueError("검토 대상 도메인이 아닙니다") draft = { "title": "반복 업무 자동화는 어디서 시작할까요?", "summary": "입력과 결과가 분명한 작업을 고르고, 실패 로그를 붙이는 순서를 정리했습니다.", "url": url, "status": "review", } print(json.dumps(draft, ensure_ascii=False, indent=2)) assert draft["status"] == "review" 출력물을 검토한 뒤 채널에 맞는 설명을 더하세요. 외부 게시 AP...

WordPress REST API 연동: 공개 전 초안 본문 검사

WordPress 게시 자동화는 초안 상태와 필수 본문을 먼저 검증하고, 권한을 갖춘 계정으로 결과를 확인한 뒤 공개합니다. 어떤 상황에서 적용하나요? 다음은 WordPress posts 엔드포인트에 사용할 JSON 본문을 만드는 로컬 예제입니다. 사이트에 연결하거나 글을 발행하지 않습니다. 인증 방식과 권한은 해당 사이트의 설정에 맞춰야 합니다. 검증 범위: 아래 코드는 외부 서비스에 요청하지 않는 로컬 예제입니다. 실제 서비스 연결은 별도로 검증해야 합니다. 최소 예제로 동작 확인하기 def make_draft(title, content): if not title.strip() or not content.strip(): raise ValueError("제목과 본문이 필요합니다") return {"title": title.strip(), "content": content.strip(), "status": "draft"} payload = make_draft(" 월간 보고서 작성법 ", "<p>검토할 초안입니다.</p>") assert payload["status"] == "draft" assert payload["title"] == "월간 보고서 작성법" print(payload) 결과는 어떻게 확인하나요? status가 draft인 본문이 출력됩니다. 실제 API 응답에서는 생성된 글 ID와 상태를 저장하고 관리자 화면에서 내용·링크·이미지를 확인하세요. HTTP 성공 코드만으로 공개 품질이 검증되지는 않습니다. 실제 업무에 적용할 때 확인할 점 Application Password 등의 자격 증명을 코드나 저장소에 넣지 마세요. 요청 후 응답이 끊겼다면 새 글을 무조건 다시 만들기보다 기존 생성 여부를...

Bing URL 알림 전 목록 검사: 제출과 색인은 다릅니다

검색엔진에 변경된 URL을 알리는 것과 실제로 색인되는 것은 다릅니다. 먼저 관리 중인 공개 URL만 골라 요청 목록을 검증하세요. 어떤 상황에서 적용하나요? Bing의 URL 제출 기능과 IndexNow는 문서·인증 방식이 다릅니다. 이 글의 예제는 어느 서비스에도 요청하지 않고 동일 호스트 URL의 중복과 묶음 크기만 검사합니다. 검증 범위: 아래 코드는 외부 서비스에 요청하지 않는 로컬 예제입니다. 실제 서비스 연결은 별도로 검증해야 합니다. 최소 예제로 동작 확인하기 from urllib.parse import urlsplit def prepare_batches(urls, host, size=2): if size <= 0: raise ValueError("묶음 크기는 양수여야 합니다") clean = [] for url in urls: p = urlsplit(url) if p.scheme != "https" or p.hostname != host or p.username or p.password: raise ValueError("관리 대상 주소가 아닙니다") if url not in clean: clean.append(url) return [clean[i:i+size] for i in range(0, len(clean), size)] batches = prepare_batches(["https://example.com/a", "https://example.com/a", "https://example.com/b", "https://example.com/c"], "example.com") assert [len(batch) for...

Google Indexing API 사용 범위: 일반 블로그 글은 어떻게 색인하나요?

Google Indexing API는 일반 블로그 글의 색인을 강제하는 도구가 아닙니다. Google 공식 문서가 허용하는 대상은 JobPosting 또는 VideoObject에 포함된 BroadcastEvent 페이지입니다. 일반 Blogger 글은 어떻게 알리나요? 사이트맵과 내부 링크로 새 글을 발견할 수 있게 하고 Search Console에서 URL 검사와 색인 상태를 확인하세요. API 호출을 반복한다고 일반 글의 색인이나 검색 순위가 보장되는 것은 아닙니다. 할당량 제한을 여러 계정으로 우회하는 방식도 사용하지 않아야 합니다. 색인되지 않을 때 확인 순서 비로그인 상태에서 글이 정상적으로 열리는지 확인합니다. robots.txt와 noindex 설정을 구분해 확인합니다. 대표 URL인 canonical이 다른 글을 가리키지 않는지 확인합니다. 사이트맵에 글이 포함되고 홈·관련 글에서 링크되는지 확인합니다. 콘텐츠가 중복되거나 답을 제공하지 않는 얇은 페이지인지 점검합니다. Search Console의 실제 색인 사유를 보고 수정합니다. HTTP 성공과 색인 완료의 차이 적격 페이지에서 API 요청이 성공해도 검색 결과 반영 자체를 보장하지는 않습니다. 응답은 알림 접수에 관한 것이며, 크롤링·색인·검색 노출은 구분해야 합니다. 애드센스 승인 역시 색인 API 성공 횟수와 별개입니다. Blogger 사이트맵 확인 예 이 사이트의 글 목록은 게시글 사이트맵 , 고정 페이지는 페이지 사이트맵 에서 확인할 수 있습니다. 사이트맵이 열리는 것과 모든 URL의 색인 완료는 다르므로 Search Console 보고서와 함께 해석하세요. 공식 기준: Google Indexing API 사용 범위 . 관련 가이드: API·운영 , 업무 자동화 . 작성: 로그 · 2026-10-17 정정: 일반 블로그 색인 자동화로 오해할 수 있던 안내를 공식 사용 범위에 맞게 수정했습니다.

Requests User-Agent 설정: 요청 준비와 접근 정책 구분

User-Agent는 요청 프로그램 정보를 전달하는 헤더이며, 바꾸는 것만으로 접근 권한이나 수집 허가가 생기지는 않습니다. 어떤 상황에서 적용하나요? 다음은 Requests에서 요청을 준비하고 헤더를 검사하는 로컬 예제입니다. 실제 전송은 하지 않습니다. 자신을 나타내는 식별자를 쓰고 대상 사이트의 API·이용약관·접근 안내를 우선 확인하세요. 검증 범위: 아래 코드는 외부 서비스에 요청하지 않는 로컬 예제입니다. 실제 서비스 연결은 별도로 검증해야 합니다. 최소 예제로 동작 확인하기 import requests request = requests.Request("GET", "https://example.com/", headers={ "User-Agent": "WorkAutomationLearning/1.0" }) prepared = request.prepare() assert prepared.headers["User-Agent"] == "WorkAutomationLearning/1.0" assert prepared.method == "GET" print(prepared.headers["User-Agent"]) 결과는 어떻게 확인하나요? 설정한 문자열이 출력됩니다. 이 결과는 헤더 준비를 검증할 뿐 실제 서버가 요청을 허용한다는 뜻은 아닙니다. 실제 전송에서는 시간 제한과 상태 코드를 확인해야 합니다. 실제 업무에 적용할 때 확인할 점 403을 받았다고 브라우저 헤더를 복사해 계속 요청하지 마세요. 인증이나 정책 문제를 확인하고 필요하면 관리자에게 허가를 받아야 합니다. 429 응답은 제공자의 재시도 지침을 따르고 요청 빈도를 낮추거나 중단합니다. 공식 자료와 다음 단계 관련 공식 문서 에서 사용하는 버전의 기능과 제한을 확인하세요. 학습 경로: 웹 스크래핑 가이드 · 요청 정책과 헤더 작성: ...

파이썬 CSV 저장: 한글 인코딩과 수식 입력 주의

CSV 저장에서는 열 순서·인코딩·줄바꿈을 정하고, 스프레드시트에서 수식으로 해석될 수 있는 외부 입력을 구분해야 합니다. 어떤 상황에서 적용하나요? 아래는 임시 폴더에 CSV를 쓰고 다시 읽어 헤더와 한글 보존을 확인합니다. 표준 라이브러리만 사용하며 실제 Excel을 실행하지 않습니다. utf-8-sig는 BOM이 포함된 UTF-8입니다. 검증 범위: 아래 코드는 외부 서비스에 요청하지 않는 로컬 예제입니다. 실제 서비스 연결은 별도로 검증해야 합니다. 최소 예제로 동작 확인하기 import csv from pathlib import Path from tempfile import TemporaryDirectory def spreadsheet_text(value): text = str(value) return "'" + text if text.lstrip().startswith(("=", "+", "-", "@")) else text with TemporaryDirectory() as folder: path = Path(folder) / "report.csv" with path.open("w", encoding="utf-8-sig", newline="") as file: writer = csv.DictWriter(file, fieldnames=["name", "note"]) writer.writeheader() writer.writerow({"name": "보고서", "note": spreadsheet_text("=1+1")}) with path.open(encoding="utf-8-sig...

Selenium 로그인 폼 연습: 로컬 페이지로 입력 단계 확인

로그인 자동화는 허용된 계정과 사이트 범위에서 수행하고, 입력 단계와 실제 인증 성공 판단을 분리해야 합니다. 어떤 상황에서 적용하나요? 다음은 외부 계정 대신 로컬 data URL의 연습용 폼을 사용합니다. demo는 임의의 연습 문자열이며 실제 비밀번호가 아닙니다. Chrome과 Selenium이 필요한 수동 실행 예제입니다. 검증 범위: 아래 코드는 문법을 점검한 GUI·브라우저 예제입니다. 이 사이트의 점검 환경에서는 실제 창 실행을 검증하지 않았으며 해당 실행 환경에서 수동 확인이 필요합니다. 최소 예제로 동작 확인하기 from urllib.parse import quote from selenium import webdriver from selenium.webdriver.common.by import By html = "<label>사용자<input id='user'></label><label>연습값<input id='pass' type='password'></label>" driver = webdriver.Chrome() try: driver.get("data:text/html;charset=utf-8," + quote(html)) driver.find_element(By.ID, "user").send_keys("demo-user") driver.find_element(By.ID, "pass").send_keys("demo-only") assert driver.find_element(By.ID, "user").get_attribute("value") == "demo-user" print("로컬 폼 입력 확인") fin...

Selenium 명시적 대기: 고정 sleep 대신 조건 확인

동적 페이지는 몇 초를 고정해서 기다리기보다 필요한 요소와 상태가 나타나는 조건을 명시해 기다립니다. 어떤 상황에서 적용하나요? 아래는 로컬 연습 페이지가 잠시 뒤 요소를 추가하면 WebDriverWait로 찾는 예제입니다. 외부 사이트에 접속하지 않지만 브라우저 실행 환경이 필요합니다. 검증 범위: 아래 코드는 문법을 점검한 GUI·브라우저 예제입니다. 이 사이트의 점검 환경에서는 실제 창 실행을 검증하지 않았으며 해당 실행 환경에서 수동 확인이 필요합니다. 최소 예제로 동작 확인하기 from urllib.parse import quote from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC html = """<script>setTimeout(() => { const p = document.createElement('p'); p.id='ready'; p.textContent='완료'; document.body.appendChild(p); }, 300);</script><body></body>""" driver = webdriver.Chrome() try: driver.get("data:text/html;charset=utf-8," + quote(html)) element = WebDriverWait(driver, 5).until( EC.visibility_of_element_located((By.ID, "ready"))) assert ...

파이썬 웹 스크래핑 기초: Requests와 BeautifulSoup 실행 예제

Requests는 HTTP 응답을 가져오고 BeautifulSoup은 받은 HTML에서 필요한 요소를 선택합니다. 두 도구는 브라우저에서 실행되는 자바스크립트를 자동으로 실행하지 않습니다. 인터넷 요청 없이 선택자부터 시험하기 처음에는 작은 HTML로 추출 규칙을 확인하는 편이 좋습니다. Python 3에서 python -m pip install requests beautifulsoup4 로 패키지를 설치하세요. 다음 예제는 외부 사이트를 요청하지 않습니다. from bs4 import BeautifulSoup html = '''<ul id="reports"> <li><a href="/report/1">월간 보고서</a></li> <li><a href="/report/2">주간 보고서</a></li> </ul>''' soup = BeautifulSoup(html, "html.parser") rows = [ {"title": a.get_text(strip=True), "path": a.get("href")} for a in soup.select("#reports li a[href]") ] assert len(rows) == 2 assert rows[0]["title"] == "월간 보고서" print(rows) #reports li a[href] 는 지정된 목록 안에서 href 속성이 있는 링크만 선택합니다. 선택 결과가 빈 목록이면 곧바로 파일을 덮어쓰기보다, 페이지 구조 변경 또는 잘못된 선택자인지 먼저 확인하세요. 허용된 페이지에 요청 연결하기 대상 사이트가 공식 API나 CSV를 제공하면 그것을 우...

Tkinter 버튼 command: 함수 전달과 입력 검증

버튼의 command에는 실행 결과가 아니라 호출할 함수를 전달하며, 콜백 안에서 입력을 읽고 오류를 표시합니다. 어떤 상황에서 적용하나요? 다음은 입력한 작업 이름을 검사해 상태 문구를 바꾸는 Tkinter 예제입니다. GUI가 있는 Python 환경이 필요합니다. 네트워크 요청이나 파일 변경은 하지 않습니다. 검증 범위: 아래 코드는 문법을 점검한 GUI·브라우저 예제입니다. 이 사이트의 점검 환경에서는 실제 창 실행을 검증하지 않았으며 해당 실행 환경에서 수동 확인이 필요합니다. 최소 예제로 동작 확인하기 import tkinter as tk from tkinter import ttk root = tk.Tk() root.title("작업 이름 확인") entry = ttk.Entry(root) entry.pack(padx=20, pady=10) status = tk.StringVar(value="작업 이름을 입력하세요") def check_input(): name = entry.get().strip() status.set(f"준비: {name}" if name else "빈 이름은 사용할 수 없습니다") ttk.Button(root, text="확인", command=check_input).pack(pady=10) ttk.Label(root, textvariable=status).pack(padx=20, pady=10) root.mainloop() 결과는 어떻게 확인하나요? 빈 값에서는 오류 안내가, 이름을 입력하면 준비 문구가 표시됩니다. command=check_input()으로 쓰면 창을 구성할 때 함수가 실행되므로 괄호 없이 전달하는 차이를 확인하세요. 실제 업무에 적용할 때 확인할 점 콜백에 오래 걸리는 작업을 직접 넣으면 이벤트 처리가 멈춥니다. 별도 작업 스레드와 큐를 사용하고 화면 변경은 메인 스레드에서 처리하세요. 입력 검...

Tkinter와 PyQt5 선택: 화면 요구와 배포 조건 비교

GUI 도구는 무조건 빠르다는 평가보다 필요한 위젯·화면 설계 방식·설치 환경·라이선스 조건으로 선택합니다. 어떤 상황에서 적용하나요? 작은 내부 입력창은 Tkinter부터 검토할 수 있고, Qt 기반 위젯과 Designer 작업 흐름이 필요한 경우 PyQt5를 검토할 수 있습니다. 다음은 요구사항을 빠뜨리지 않기 위한 점검표 코드이며 성능 측정 결과가 아닙니다. 검증 범위: 아래 코드는 외부 서비스에 요청하지 않는 로컬 예제입니다. 실제 서비스 연결은 별도로 검증해야 합니다. 최소 예제로 동작 확인하기 requirements = { "table_editing": True, "designer_workflow": True, "target_os": ["Windows"], "license_reviewed": False, } checks = ["대상 환경 실행", "설치 패키지", "접근성", "유지보수"] if requirements["designer_workflow"]: checks.append("Designer 파일과 시그널 연결") if not requirements["license_reviewed"]: checks.append("배포 라이선스 검토 필요") assert "배포 라이선스 검토 필요" in checks print(checks) 결과는 어떻게 확인하나요? 요구에 따라 확인해야 할 항목이 출력됩니다. 이 코드가 특정 프레임워크의 우수성을 결정하지는 않습니다. 실제 후보별로 같은 작은 화면을 만들어 입력·창 크기 변경·배포 환경을 비교하세요. 실제 업무에 적용할 때 확인할 점 Tkinter는 Python의 표준 인터페이스이지만 설치 환경에 Tcl/Tk가 ...

Tkinter grid 배치: weight와 sticky로 창 크기 대응

grid에서 창 크기에 따라 입력창을 늘리려면 해당 행·열의 weight와 위젯의 sticky를 함께 지정합니다. 어떤 상황에서 적용하나요? 아래는 이름 입력창이 가로 공간을 채우는 작은 화면입니다. 같은 부모 컨테이너에서는 pack과 grid를 섞지 않습니다. 서로 다른 Frame 안에서는 별도로 배치 관리자를 사용할 수 있습니다. 검증 범위: 아래 코드는 문법을 점검한 GUI·브라우저 예제입니다. 이 사이트의 점검 환경에서는 실제 창 실행을 검증하지 않았으며 해당 실행 환경에서 수동 확인이 필요합니다. 최소 예제로 동작 확인하기 import tkinter as tk from tkinter import ttk root = tk.Tk() root.title("보고서 설정") root.columnconfigure(1, weight=1) ttk.Label(root, text="보고서 이름").grid(row=0, column=0, padx=10, pady=10) entry = ttk.Entry(root) entry.grid(row=0, column=1, sticky="ew", padx=10, pady=10) ttk.Button(root, text="닫기", command=root.destroy).grid( row=1, column=1, sticky="e", padx=10, pady=10) root.minsize(320, 120) root.mainloop() 결과는 어떻게 확인하나요? 창을 넓히면 두 번째 열의 입력창이 함께 늘어나는지 확인하세요. sticky만 설정하고 열 weight가 0이면 남는 공간이 그 열에 배분되지 않을 수 있습니다. 실제 업무에 적용할 때 확인할 점 고정 픽셀 크기만으로 화면을 맞추면 글꼴·배율·번역 문구에 따라 잘릴 수 있습니다. 최소 크기와 키보드 탭 이동을 시험하고, 복잡한 화면은 기능별 Frame으로 나누세요. 작업 실행 중...

PyQt5 시그널과 슬롯: Designer 파일 전에 연결 구조 익히기

PyQt5에서는 위젯의 시그널을 처리 함수에 연결하고, Designer로 만든 화면도 같은 원리로 동작을 연결합니다. 어떤 상황에서 적용하나요? 다음은 Designer 파일 없이 연결 구조를 확인하는 최소 화면입니다. PyQt5 설치와 데스크톱 환경이 필요하며 여기서는 실제 GUI 실행 결과를 검증하지 않았습니다. Designer로 전환할 때는 objectName과 생성·로딩 방식을 일치시키세요. 검증 범위: 아래 코드는 문법을 점검한 GUI·브라우저 예제입니다. 이 사이트의 점검 환경에서는 실제 창 실행을 검증하지 않았으며 해당 실행 환경에서 수동 확인이 필요합니다. 최소 예제로 동작 확인하기 import sys from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLineEdit, QPushButton, QLabel app = QApplication(sys.argv) window = QWidget() window.setWindowTitle("보고서 입력") layout = QVBoxLayout(window) entry = QLineEdit() button = QPushButton("확인") status = QLabel("대기") def show_name(): name = entry.text().strip() status.setText(name if name else "이름을 입력하세요") button.clicked.connect(show_name) for widget in (entry, button, status): layout.addWidget(widget) window.show() sys.exit(app.exec_()) 결과는 어떻게 확인하나요? 텍스트를 입력한 뒤 확인 버튼을 눌러 레이블이 바뀌는지 시험하세요. Designer 사용 시 UI의 objectName을 통해 해당 위젯에 접근...

Tkinter 시작하기: 입력창과 상태 문구가 있는 최소 앱

Tkinter 첫 화면은 하나의 Tk 인스턴스와 mainloop를 두고, 위젯 상태를 이벤트 콜백에서 갱신하는 구조로 시작합니다. 어떤 상황에서 적용하나요? 다음은 파일명 입력을 받아 준비 문구만 표시하는 예제입니다. 파일을 열거나 쓰지 않으므로 화면 입력과 실제 파일 처리의 책임을 분리해 연습할 수 있습니다. 검증 범위: 아래 코드는 문법을 점검한 GUI·브라우저 예제입니다. 이 사이트의 점검 환경에서는 실제 창 실행을 검증하지 않았으며 해당 실행 환경에서 수동 확인이 필요합니다. 최소 예제로 동작 확인하기 import tkinter as tk from tkinter import ttk root = tk.Tk() root.title("업무 도구 시작") filename = tk.StringVar(value="report.csv") message = tk.StringVar(value="대기 중") frame = ttk.Frame(root, padding=16) frame.pack(fill="both", expand=True) ttk.Label(frame, text="처리할 파일 이름").pack(anchor="w") ttk.Entry(frame, textvariable=filename).pack(fill="x", pady=8) def prepare(): value = filename.get().strip() message.set(f"준비: {value}" if value else "파일 이름을 입력하세요") ttk.Button(frame, text="준비", command=prepare).pack(anchor="w") ttk.Label(frame, textvariable=message).pack(anchor="w", pady...