DB_JOB/_스크립트/_gongju_split_jangae.py
hehihoho3 df16c98366 백업: DB수집 전체 스냅샷 (공공기관2 정리 전)
공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 18:15:40 +09:00

155 lines
8.1 KiB
Python

# -*- coding: utf-8 -*-
"""공주시 305행(장애인 단일행, 순번311, sub06_01_02_01.do)을
크롤링한 탭 트리(1단계10→잎30)로 분해.
- 305행을 30행(305~334)으로 확장, 306~414행은 +29 시프트(335~443)
- 순번(B) 305~443 연속 재번호(311..), 305 이전(검수본·삭제갭) 불변
- 병합셀 재조정(>=306행 +29) + 장애인 F/G 병합 신규
- K열 하이퍼링크 유지/재설정
사용: --write 로 적용(미지정 시 계획만 출력)
"""
import sys, shutil
from copy import copy
import openpyxl
XLSX = r'D:\01.프로젝트\DB수집\작업파일\광역_사이트맵\충청남도\2.공주시\충청남도_공주시.xlsx'
SPLIT_ROW = 305 # 장애인 행
N = 30 # 새 행 수
SHIFT = N - 1 # 29
DATA_LAST = 414 # 현재 마지막 데이터행
B_START = 311 # 305행 순번
BASE = 'https://www.gongju.go.kr'
# (G, H, url, L, M) H=None 이면 단일(leaf)
ROWS = [
('장애인인권헌장', None, '/kr/sub06_01_02_01.do', '페이지', 1),
('장애인등록안내', '장애인이란', '/kr/sub06_01_02_03_01.do', '페이지', 1),
('장애인등록안내', '장애인등록/심사제도', '/kr/sub06_01_02_03_02.do', '페이지', 1),
('장애인등록안내', '장애인등록현황', '/kr/sub06_01_02_03_03.do', '페이지', 1),
('장애인등록안내', '장애인관련법률', '/kr/sub06_01_02_03_04.do', '페이지', 1),
('장애인복지카드안내', None, '/kr/sub06_01_02_04_01.do', '페이지', 1),
('장애인생활안정지원', '장애수당지급', '/kr/sub06_01_02_05_01.do', '페이지', 1),
('장애인생활안정지원', '장애인의료비지원', '/kr/sub06_01_02_05_02.do', '페이지', 1),
('장애인생활안정지원', '자립자금대여', '/kr/sub06_01_02_05_03.do', '페이지', 1),
('장애인생활안정지원', '재활보조기구 무료교부', '/kr/sub06_01_02_05_04.do', '페이지', 1),
('장애인생활안정지원', '장애아동수당', '/kr/sub06_01_02_05_05.do', '페이지', 1),
('장애인생활안정지원', '장애인일자리', '/kr/sub06_01_02_05_06.do', '페이지', 1),
('자동차관련시책', '장애인자동차표지 발급', '/kr/sub06_01_02_06_01.do', '페이지', 1),
('자동차관련시책', '고속도로통행료 할인', '/kr/sub06_01_02_06_02.do', '페이지', 1),
('자동차관련시책', '자동차특별소비세 면제', '/kr/sub06_01_02_06_03.do', '페이지', 1),
('세금감면시책', '소득세공제', '/kr/sub06_01_02_07_01.do', '페이지', 1),
('세금감면시책', '상속세공제', '/kr/sub06_01_02_07_02.do', '페이지', 1),
('각종요금할인', '전화요금할인', '/kr/sub06_01_02_08_01.do', '페이지', 1),
('각종요금할인', 'TV수신료면제', '/kr/sub06_01_02_08_02.do', '페이지', 1),
('각종요금할인', '이동통신 요금할인', '/kr/sub06_01_02_08_03.do', '페이지', 1),
('각종요금할인', '교통요금 할인', '/kr/sub06_01_02_08_04.do', '페이지', 1),
('각종요금할인', '공공시설 이용요금 감면', '/kr/sub06_01_02_08_05.do', '페이지', 1),
('각종요금할인', '장애인 전기요금 감면', '/kr/sub06_01_02_08_06.do', '페이지', 1),
('각종요금할인', '초고속인터넷 요금할인', '/kr/sub06_01_02_08_07.do', '페이지', 1),
('장애인전화상담', '장애인전화상담소', '/kr/sub06_01_02_09_01.do', '페이지', 1),
('장애인전화상담', '이용안내', '/kr/sub06_01_02_09_02.do', '페이지', 1),
('장애인 전동휠체어 급속충전기 설치장소', None, '/kr/sub06_01_02_10.do', '페이지', 1),
('한눈에 보는 장애인복지 서비스', '시설소개', '/kr/sub06_01_02_11_01.do', '페이지', 1),
('한눈에 보는 장애인복지 서비스', '사업홍보', 'https://www.gongju.go.kr/bbs/BBSMSTR_000000001671/list.do?mno=sub06_01_02_11_02', '게시판', 96),
('한눈에 보는 장애인복지 서비스', '채용정보', 'https://www.gongju.go.kr/bbs/BBSMSTR_000000001672/list.do?mno=sub06_01_02_11_03', '게시판', 11),
]
assert len(ROWS) == N
def full(u):
return u if u.startswith('http') else BASE + u
def main():
write = '--write' in sys.argv
wb = openpyxl.load_workbook(XLSX)
ws = wb.active
if write:
# 0) 모든 병합 먼저 해제(시프트 시 MergedCell 쓰기불가 방지)
old_merges = [str(mr) for mr in list(ws.merged_cells.ranges)]
for mr in old_merges:
ws.unmerge_cells(mr)
# 1) 시프트: source 414..306 -> dest +29 (아래에서 위로)
for sr in range(DATA_LAST, SPLIT_ROW, -1): # 414..306
dr = sr + SHIFT
for c in range(1, 28):
src = ws.cell(sr, c)
dst = ws.cell(dr, c)
dst.value = src.value
if src.has_style:
dst._style = copy(src._style)
# hyperlink 이동
if src.hyperlink is not None:
dst.hyperlink = copy(src.hyperlink)
dst.hyperlink.ref = dst.coordinate
src.hyperlink = None
else:
dst.hyperlink = None
# 2) 305~334 영역 클리어 + 스타일 템플릿(원래 305행) 적용
# 원래 305행 스타일은 시프트 안했으므로 그대로 305에 남아있음(템플릿)
tmpl = {c: copy(ws.cell(SPLIT_ROW, c)._style) for c in range(1, 28) if ws.cell(SPLIT_ROW, c).has_style}
for r in range(SPLIT_ROW, SPLIT_ROW + N):
for c in range(1, 28):
cell = ws.cell(r, c)
cell.value = None
cell.hyperlink = None
if c in tmpl:
cell._style = copy(tmpl[c])
# 3) 30행 데이터 기입 (G는 그룹 최상단에만)
prev_g = None
for i, (g, h, u, L, M) in enumerate(ROWS):
r = SPLIT_ROW + i
if g != prev_g:
ws.cell(r, 7).value = g # G 소 (그룹 최상단)
prev_g = g
if h:
ws.cell(r, 8).value = h # H 세부
fu = full(u)
kc = ws.cell(r, 11)
kc.value = fu
kc.hyperlink = fu
ws.cell(r, 12).value = L # L
ws.cell(r, 13).value = M # M
ws.cell(r, 14).value = '어문' # N
ws.cell(r, 15).value = '미부착' # O
# F=장애인 (병합 최상단)
ws.cell(SPLIT_ROW, 6).value = '장애인'
# 4) 순번(B) 305~443 연속 재번호
for r in range(SPLIT_ROW, DATA_LAST + SHIFT + 1):
ws.cell(r, 2).value = B_START + (r - SPLIT_ROW)
# 5) 병합셀 재조정 (0단계서 해제한 old_merges를 시프트해 재생성)
from openpyxl.utils.cell import range_boundaries
def shift(rr):
return rr + SHIFT if rr >= SPLIT_ROW + 1 else rr
for rng in old_merges:
c1, r1, c2, r2 = range_boundaries(rng)
nr1, nr2 = shift(r1), shift(r2)
ws.merge_cells(start_row=nr1, start_column=c1, end_row=nr2, end_column=c2)
# 신규 병합: F305:F334
ws.merge_cells(start_row=305, start_column=6, end_row=334, end_column=6)
# G 병합(다중 H 그룹)
gmerges = [(306, 309), (311, 316), (317, 319), (320, 321), (322, 328), (329, 330), (332, 334)]
for a, b in gmerges:
ws.merge_cells(start_row=a, start_column=7, end_row=b, end_column=7)
bak = XLSX.replace('.xlsx', '_backup_장애인분해전.xlsx')
shutil.copy(XLSX, bak)
wb.save(XLSX)
print('저장 완료. 백업:', bak)
else:
print('=== 계획(DRY) ===')
print('305행(장애인) → 30행 확장, 306~414 → +29 시프트')
print('순번 305~443 = 311..%d' % (B_START + (DATA_LAST + SHIFT - SPLIT_ROW)))
print('F305:F334 병합, G병합 7개')
for i, (g, h, u, L, M) in enumerate(ROWS):
print(' r%d G=%s H=%s L=%s M=%s' % (SPLIT_ROW + i, g, h or '', L, M))
if __name__ == '__main__':
main()