새기능 #5805
완료됨새기능 #5801: 신유형개방 권리확인 사이트 수집
[신유형개방 권리확인] 경기북부경찰청 보도자료 수집 (799건)
0%
설명
개요¶
경기북부경찰청 알림마당 > 알림판 > 보도자료 게시판 799건(2016-04-11 ~ 2026-07-20)을 전건 수집해 1. 권리확인 시트에 기재했다.
- 산출물:
2026 신유형개방 권리확인 및 처리 리스트(경기북부경찰청)_보도자료.xlsx
분석¶
1) 목록 URL 추적¶
조사표에 적힌 URL이 https://www.ggbpolice.go.kr/PageLink.do 로 파라미터가 없는 메인 페이지였다. 메뉴 이동이 goSubMenuPage_3dep('040000','040100','040200') 같은 JS 함수로만 이루어져 링크가 노출되지 않았다.
페이지 소스에 메뉴 메타가 hidden input으로 박혀 있는 것을 찾아 실제 게시판 경로를 추출했다.
<input type="hidden" name="tmp_menuNm"
value='040200|040100|보도자료|||/cop/bbs/selectBoardList.do?bbsId=News_main|MENUT01||' />
→ 목록 …/cop/bbs/selectBoardList.do?bbsId=News_main&pageIndex=N
2) 상세 URL 규칙¶
목록의 제목 링크가 fn_inqire_notice('74803','News_main') 형태라 href가 없다. 첫 번째 인자가 nttId 임을 확인하고 eGovFrame 표준 규칙으로 상세 URL을 직접 조립해 응답을 검증했다.
→ …/cop/bbs/selectBoardArticle.do?bbsId=News_main&nttId=74803 (200 및 제목 일치 확인)
3) 제목¶
목록 <a> 텍스트에 전체 제목이 그대로 노출되어 있어 상세페이지 799회 요청을 생략했다. (목록 80회 요청으로 종료)
핵심 코드¶
import re, html, urllib.request, ssl
CTX = ssl.create_default_context()
CTX.check_hostname = False
CTX.verify_mode = ssl.CERT_NONE
UA = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}
GGB_LIST = 'https://www.ggbpolice.go.kr/cop/bbs/selectBoardList.do?bbsId=News_main&pageIndex={}'
GGB_VIEW = 'https://www.ggbpolice.go.kr/cop/bbs/selectBoardArticle.do?bbsId=News_main&nttId={}'
ROW_RE = re.compile(r'<tr>(.*?)</tr>', re.S)
def clean(s):
s = re.sub(r'<[^>]+>', '', s)
s = html.unescape(s).replace('\xa0', ' ')
return re.sub(r'\s+', ' ', s).strip()
def crawl_ggb():
items, page, seen = [], 1, set()
while True:
h = get(GGB_LIST.format(page))
found = 0
for row in ROW_RE.findall(h):
m = re.search(r"fn_inqire_notice\('(\d+)','News_main'\)", row)
if not m:
continue
ntt = m.group(1)
if ntt in seen: # 상단 고정공지 중복 방지
continue
seen.add(ntt)
found += 1
title = clean(re.search(r'fn_inqire_notice.*?>(.*?)</a>', row, re.S).group(1))
dates = re.findall(r'(\d{4}-\d{2}-\d{2})', row)
items.append({'title': title,
'url' : GGB_VIEW.format(ntt),
'date' : dates[0] if dates else ''})
print(' page %d -> %d (total %d)' % (page, found, len(items)))
if found == 0: # 빈 페이지 = 종료 조건
break
page += 1
return items
엑셀 기재 (등록일 8자리 숫자 + 하이퍼링크)
import openpyxl
from copy import copy
from openpyxl.styles import Font
from openpyxl.styles.colors import Color
BODY_FONT = Font(name='맑은 고딕', sz=10)
LINK_FONT = Font(name='맑은 고딕', sz=11, u='single', color=Color(theme=10))
for i, it in enumerate(items, 1):
r = 4 + i - 1
d = it['date'].replace('-', '') # '2026-07-20' -> '20260720'
vals = [i, '경기북부경찰청', '알림마당 > 알림판 > 보도자료', '보도자료',
it['title'], it['url'], None, int(d)]
for c, v in enumerate(vals, 1):
cell = ws.cell(row=r, column=c)
cell.value = v
cell._style = copy(style_tmpl[c - 1]) # 템플릿 4행 서식 승계
cell.font = copy(BODY_FONT)
ws.cell(r, 5).number_format = '@' # 제목: 텍스트
ws.cell(r, 8).number_format = '0' # 등록일: 8자리 숫자
link = ws.cell(r, 6) # F열 하이퍼링크
link.number_format = '@'
link.hyperlink = it['url']
link.font = copy(LINK_FONT)
사용 패키지¶
| 패키지 | 버전 | 용도 |
|---|---|---|
| Python | 3.13.0 | 실행 환경 |
| openpyxl | 3.1.5 | 템플릿 복사·기재·서식·하이퍼링크 |
표준 라이브러리: urllib.request / ssl / re / html / json / time / os
검수¶
- 조사표(260701 기준) 표기 수량 793건 ↔ 수집 799건 → 그간 신규 등록분 6건으로 설명됨
- 상세 URL 중복 0건 / 등록일 누락 0건
- 무작위 표본을 실제 요청해 응답 HTML에 제목 포함 여부 대조 → 불일치 0건
특이사항¶
- 조사표 기준 이 게시판은 공공누리 1유형(부착위치: 첨부파일) 로 표기되어 있으나, 목록·상세 페이지에는 마크가 노출되지 않아 G열(저작물유형)은 공란으로 둔 상태. 필요 시 일괄 입력 가능.
- 페이징 종료 조건을 「마지막 페이지 번호」가 아니라 「파싱 결과 0건」으로 잡아, 게시물이 늘어나도 수정 없이 재실행 가능.
표시할 데이터가 없습니다.