
    h"                        d dl mZ d dlZd dlZd dlmZmZ d dlmZmZm	Z	m
Z
 d dlZd dlmZ d dlmZmZ d dlmZ  e            ZdZd	Zd
diZdedefdZdddedededededz  f
dZdede	e
eeef                  fdZdede
e	e         ef         fdZde	e         de	e         fdZdede	e         fdZdeded ede	e         fd!Zd"ede fd#Z!d$ede fd%Z"deeeez  f         fd&Z#e$d'k    r e% e#                       dS dS )(    )escapeN)datetimetimezone)DictListOptionalTuple)BeautifulSoup)
get_clientlogger)broadcast_htmlz5https://www.moef.go.kr/nw/notice/hr.do?menuNo=4050300z,https://www.moef.go.kr/nw/notice/hrDetail.doz
User-AgentzCMozilla/5.0 (compatible; govbot/1.0; +https://work.jjickjjicks.com)targetreturnc                    dd l }t          |                                          }	 t                              d                              || dddd t          j        t          j	                  
                                d                                           n.# t          $ r!}t          j        d|            Y d }~nd }~ww xY w|S )Nr   crawler_runrunning)idr   statuspagesrowsfail_reason
started_atz[crawler_run insert] )uuidstruuid4supabasetableinsertr   nowr   utc	isoformatexecute	Exceptionr   warning)r   r   run_ides       )/var/www/html/bot/app/crawler/moef_n8n.py
_run_startr(      s    KKKF4}%%,,",x|44>>@@.
 .
 	 	 79999 4 4 42q22333333334Ms   A5B 
C'CC)r   r%   r   r   r   r   c                   |t          j        t          j                                                  ||d}|||d<   	 t
                              d                              |                              d|           	                                 d S # t          $ r"}t          j        d|            Y d }~d S d }~ww xY w)N)r   finished_atr   r   r   r   r   z[crawler_run finish] )r   r   r   r    r!   r   r   updateeqr"   r#   r   r$   )r%   r   r   r   r   payloadr&   s          r'   _run_finishr.   +   s    |HL11;;==	 G !,4}%%,,W5588vFFNNPPPPP 4 4 42q223333333334s   AB 
B?B::B?href_jsc                     t          j        d| pd          }|sdS |                    d          |                    d          |                    d          fS )za
    javascript:fn_egov_select('4050300','MOSFBBS_...','POST_ID') -> (menuNo, bbsId, postId)
    z=fn_egov_select\('(\d+)','([A-Za-z0-9_]+)','([A-Za-z0-9_]+)'\) N         )researchgroup)r/   ms     r'   _extract_js_paramsr9   <   sU     		RT[Ta_abbA t771::qwwqzz1771::--    
title_textc                 $   | sdS t          j        d|                                           }|rN|                    d                                          |                    d                                          fS d|                                 fS )uL   
    '[태그] 제목' -> ('태그','제목'), 아니면 (None, 원제)
    )Nr1   z^\[(.+?)\]\s*(.+)$r2   r3   N)r5   matchstripr7   )r;   r8   s     r'   _split_tag_from_titler?   E   s      x
&
(8(8(:(:;;A 6wwqzz!!1771::#3#3#5#555!!####r:   	containerc                     | sdS |                      d          }|rD|                    dd          pd                                }|                    d          }|pdS dS )u~   
    목록 DOM에서 'state*' 클래스를 갖는 태그(예: <span class="state1">인사발령</span>)를 우선 추출
    Nz@span[class*="state"], em[class*="state"], strong[class*="state"] Tr>   r1   z[]())
select_oneget_textr>   )r@   elts      r'   _extract_tag_from_staterH   P   sq      t			`	a	aB	 [[D[))/R6688GGFOOyD4r:   htmlc                 &   t          j        d|           }|st          j        d|           }|sdS |                    d                              dd          }	 t	          j        |d          }|                    d          S # t          $ r |                    d          }d t          |          D             }	 t	          j        d
                    |          d          }|                    d          cY S # t          $ r Y Y dS w xY ww xY w)	uj   
    상세 페이지에서 '등록일' 또는 날짜 패턴(YYYY.MM.DD / YYYY-MM-DD) -> 'YYYY-MM-DD'
    u3   등록일[^0-9]*(\d{4}[.\-](\d{1,2})[.\-](\d{1,2}))z#(\d{4}[.\-](\d{1,2})[.\-](\d{1,2}))Nr2   .-z%Y-%m-%dc                 N    g | ]"\  }}|d k    r|                     d          n|#S )r   r3   )zfill).0ips      r'   
<listcomp>z0_parse_date_from_detail_html.<locals>.<listcomp>l   s2    III1q1uu!IIIr:   )r5   r6   r7   replacer   strptimestrftimer#   split	enumeratejoin)rI   r8   rawdtpartss        r'   _parse_date_from_detail_htmlr\   ]   s(    		H$OOA DI<dCC t
''!**

S#
&
&C
sJ//{{:&&&   		#II	%8H8HIII	"388E??J??B;;z***** 	 	 	444	s0   )B 8D><C=:D=
DDDDmenuNobbsIdpostIdc                     ||| d}t          j        t          |t          d          }|                                 t          |j                  S )N)searchBbsId1searchNttId1r]      )paramsheaderstimeout)requestsget
DETAIL_URLHEADERSraise_for_statusr\   text)r]   r^   r_   rd   rs        r'   _detail_posted_atrn   s   sS     F
 	ZLLLA'///r:   row_idc                     t                               d                              d                              d|                               d                                          }t          |j                  S )Nmoef_idr   r2   )r   r   selectr,   limitr"   booldata)ro   ress     r'   _exists_in_supabaserw   }   sY    
..
#
#
*
*4
0
0
3
3D&
A
A
G
G
J
J
R
R
T
TC>>r:   rowc                 0    g dg dg dg dg}|D ]} fd|D             }	 t                               d                              |                                            dS # t          $ r$}t          j        d| d	|            Y d
}~|d
}~ww xY wdS )u<   
    tag/posted_at 유무와 무관하게 유연 삽입
    )r   r^   r_   titletag	posted_at)r   r^   r_   rz   r|   )r   r^   r_   rz   r{   r   r^   r_   rz   c                 *    i | ]}|v ||         S  r   )rO   krx   s     r'   
<dictcomp>z _safe_insert.<locals>.<dictcomp>   s$    666aQ#XX3q6XXXr:   rq   Tzinsert retry with fields z	 failed: NF)r   r   r   r"   r#   r   r$   )rx   fields_priorityfieldsru   r&   s   `    r'   _safe_insertr      s    
 	?>>777111***	O " M M66666666	MNN9%%,,T22::<<<44 	M 	M 	MNKvKKKKLLLLLLLL	M5s   ?A%%
B/BBc            
         d} t          |           }d}d}d}	 t          j        t          t          d          }|                                 |dz  }t          |j        d          }|                    d          }|D ]}|                    dd	          }	t          |	          }
|
s+|
\  }}}| d
| }t          |          rHd	}|                    d          }|r.|                    d          }|r|                    dd          }|s|                    dd          pd}|                    d          pE|                    d          p0|                    d          p|                    d          p|j        }t!          |          }t#          |          \  }}|s|}n|}	 t%          |||          }n3# t&          $ r&}t)          j        d| d|            d }Y d }~nd }~ww xY w||||p|d}|r||d<   |r||d<   t-          |          }|st)          j        d|            |dz  }t.           d| d| d| }|r7dt1          |           dt1          |                    d d	                     d!n&d"t1          |                    d d	                     d!}d#| d$| d%}	 t3          |          }|t5          |t6                    rt7          |          n|rdndz  }n1# t&          $ r$}t)          j        d&| d|            Y d }~nd }~ww xY wt9          j        d'           t=          |d(||)           t)          j        d*| d+|            |||d(d,S # t&          $ rU}t=          |d-||tA          |          .           t)          j!        d/|            tA          |          |d-d0cY d }~S d }~ww xY w)1Nrq   r   rc   )re   rf   r2   zhtml.parserz$a[href*="javascript:fn_egov_select"]hrefr1   rL   h3arB   TrC   u   기재부 인사발령litrarticledivzfetch posted_at failed for z: r}   r{   r|   zinsert failed for z?searchBbsId1=z&searchNttId1=z&menuNo=z[(z) rz   ][u!   기재부 인사발령입니다.
z

<a href="u   ">[자세히 보기]</a>ztelegram send failed for g      ?passed)r   r   r   zMOEF run: inserted=z, sent=)insertedsentr%   r   aborted)r   r   r   r   zMOEF run aborted: )errorr%   r   )"r(   rg   rh   LIST_URLrj   rk   r
   rl   rr   r9   rw   find_previousfindrE   find_parentparentrH   r?   rn   r#   r   r$   r   ri   r   r   
isinstanceinttimesleepr.   infor   	exception)r   r%   r   r   r   rm   soupanchorsr   r/   rd   r]   r^   r_   ro   r;   r   linkr@   r{   tag2clean_titler|   r&   rx   okheadmessagesent_ress                                r'   run_oncer      s   FFEHD`HL7B???	
QV]33++DEE P	 P	AeeFB''G'00F $*!FE6((((F"6**  J&&B @wws|| @!%s$!?!?J UZZ4Z88T<T
 d## ==&&==++ =='' 8  *)44C !6j A AD+ ) )
!-feVDD		 ! ! !JVJJqJJKKK 						!
  $2
	 C  ! E
 -#,K c""B <F<<===MH !]]]]V]]U[]]DILtEsEEvcgggb.A.A'B'BEEEERtV\]`]d]delmo]p]pVqVqRtRtRtD;; ; ; ; ; 
J)'22Hc)B)B^HhI]\]^ J J JH6HHQHHIIIIIIIIJ JsOOOOF85xHHHHA(AA4AABBB$dfPXYYY H H HF9EVYZ[V\V\]]]]1a11222Q6YGGGGGGGGHsu   FM, -F?>M, ?
G/	G*%M, *G//CM, 4<K10M, 1
L;LM, LAM, ,
O6A
O OO__main__)&rI   r   r5   r   r   r   typingr   r   r   r	   rg   bs4r
   app.services.supabase_servicer   r   app.services.telegram_senderr   r   r   ri   rj   r   r(   r   r.   r9   r?   rH   r\   rn   rt   rw   r   r   __name__printr   r:   r'   <module>r      s         				  ' ' ' ' ' ' ' ' . . . . . . . . . . . .        < < < < < < < < 7 7 7 7 7 7:<<B;
 Ws s    " _c 4 4 4 4 4C 4s 4QTW[Q[ 4 4 4 4". .sC}1E(F . . . .	$c 	$eHSM34F.G 	$ 	$ 	$ 	$x'> 8C=    s x}    ,0c 0# 0s 0x} 0 0 0 0     d t    ,gH$sC#I~& gH gH gH gHR z	E((** r:   