공공기관2 작업 중. _temp 몽타주(재생성가능)는 제외. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
155 lines
8.1 KiB
Python
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()
|