Ë
    ¸¬uj©!  ã                   ó`  — d Z ddlZddlZddlZddlZddlZddlmZmZ ddlm	Z	 ej                  j                  dej                  j                  ej                  j                  e«      «      «       ddlmZ ddlmZ dZddlZ eej,                  «      dkD  r2ej,                  d   j/                  «       r eej,                  d   «      ndZe� ed	 ee«      z   «       d
„ ZdZdZ ej>                  «        ed¬«      z
  jA                  d«      Z!d„ Z"dd„Z#d„ Z$d„ Z%d„ Z&e'dk(  r e&«        yy)uÖ   
å½­å·žå¸‚äººæ°‘æ”¿åºœ - çŽ¯å¢ƒå½±å“�è¯„ä»·å®¡æ‰¹ çˆ¬è™«
CMS: EJS (AJAX pagination via ejspagination_go)
URL: https://www.pengzhou.gov.cn/pzs/c143008/list.shtml
WAF: JS Challenge (requires Playwright with stealth)
é    N)ÚdatetimeÚ	timedelta)Úurljoin)ÚBeautifulSoup)Úsync_playwrightz/root/search.dbé   z[AutoPg] max_pages=c                  óZ   — dd l } | j                  t        «      }|j                  d«       |S )Nr   zPRAGMA journal_mode=WAL)Úsqlite3ÚconnectÚDB_PATHÚexecute)r
   Úconns     ú&/root/gov_crawler/crawl_pengzhou_hp.pyÚget_connectionr       s%   € ÛØ�?‰?œ7Ó#€DØ‡L�LÐ*Ô+Ø€Kó    u%   å½­å·žå¸‚ç”Ÿæ€�çŽ¯å¢ƒå±€-çŽ¯è¯„å®¡æ‰¹z2https://www.pengzhou.gov.cn/pzs/c143008/list.shtmliG  )Údaysz%Y-%m-%dc                  óÊ   — t        «       j                  «       } | j                  j                  dddg¬«      }|j	                  ddddd	œ¬
«      }|j                  d«       | ||fS )z+Create a Playwright browser with WAF bypassTz---disable-blink-features=AutomationControlledz--no-sandbox)ÚheadlessÚargszoMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36zzh-CNi€  i8  )ÚwidthÚheight)Ú
user_agentÚlocaleÚviewportz<delete Object.getPrototypeOf(navigator).__proto__.webdriver;)r   ÚstartÚchromiumÚlaunchÚnew_contextÚadd_init_script)ÚpÚbrowserÚctxs      r   Úcreate_browserr#   +   s|   € äÓ×ÑÓ!€AØ�j‰j×ÑØØ=¸~ÐNð  ó €Gð ×
Ñ
ð EØØ¨4Ñ0ð ó €Cð
 ×ÑÐVÔWØˆg�sˆ?Ðr   c                 ó‚  — g }t        «       \  }}}|j                  «       }	 |j                  t        dd¬«       t	        j
                  d«       t        dt        | t        xs | «      dz   «      D �]ý  }t        d|› d�«       t	        j
                  d«       |j                  «       }t        |d	«      }|j                  d
d„ ¬«      }	|	st        d|› d�«        �n•d}
|	j                  d«      D ]£  }|j                  d«      }|r|j                  d«      sŒ(|d   j                  «       }|j!                  d¬«      }t#        j$                  d|«      }|r|j'                  d«      nd}|r|t)        |«      d n|}|j+                  |||dœ«       |
dz  }
Œ¥ t        d|› d|
› dt)        |«      › d�«       |D �cg c]  }|d   t,        k\  sŒ|‘Œ }}t)        |«      t)        |«      z
  }|dkD  rt        d|› d�«       |} ns|| k  s�Œ•	 |j/                  d |dz   › d!�«      }|j1                  «       dkD  r0|j2                  j5                  «        t	        j
                  d"«       nt        d#«        n�Œ  |j9                  «        |j;                  «        |D �cg c]  }|d   t,        k\  sŒ|‘Œ }}t        d&t)        |«      › �«       |S c c}w # t6        $ r}t        d$|› d|› �«       Y d}~ Œzd}~ww xY w# t6        $ r}t        d%|› �«       Y d}~Œžd}~ww xY w# |j9                  «        |j;                  «        w xY wc c}w )'z?Crawl list pages via AJAX pagination, return list of item dictsÚnetworkidleé0u  ©Ú
wait_untilÚtimeouté   r   z[List] Fetching page z...g      ø?úhtml.parserÚulc                 ó   — | xr
 d| v xr d| v S )NÚlistzejs-list© ©Úcs    r   ú<lambda>z"crawl_list_pages.<locals>.<lambda>L   s   € °!Ò2W¸À!¸Ò2WÈ
ÐVWÈ€ r   ©Úclass_z[List] Page z: no list found, stoppingr   ÚliÚaÚhrefT)Ústripz(\d{4}-\d{2}-\d{2})Ú N)ÚtitleÚurlÚdate_strú: z items (total: ú)r<   é   z[List] z& items outside 3-year window, stoppingza.pagination-num:has-text('z')é   z[List] No more pages, stoppingz[List] Click error on page z[List] Error: z#[List] Total items within 3 years: )r#   Únew_pageÚgotoÚBASE_URLÚtimeÚsleepÚrangeÚminÚ_MAX_PGÚprintÚcontentr   ÚfindÚfind_allÚgetr8   Úget_textÚreÚmatchÚgroupÚlenÚappendÚTHREE_YEARS_AGOÚlocatorÚcountÚfirstÚclickÚ	ExceptionÚcloseÚstop)Ú	max_pagesÚ	all_itemsr    r!   r"   ÚpageÚpage_numrJ   Úsoupr,   Úitems_on_pager5   r6   r7   ÚtextÚ
date_matchr<   r:   ÚitÚitems_within_3yÚitems_outsideÚnext_btnÚes                          r   Úcrawl_list_pagesri   ;   s'  € à€Iä$Ó&�O€A€w�Ø�<‰<‹>€DðBØ�	‰	”( }¸eˆ	ÔDÜ�
‰
�1Œä˜a¤ Y´Ò0D¸9Ó!EÈÑ!IÓJó 8	ˆHÜÐ)¨(¨°3Ð7Ô8ä�J‰J�sŒOØ—l‘l“nˆGÜ  ¨-Ó8ˆDØ—‘˜4Ñ(W�ÓXˆBáÜ˜ X JÐ.GÐHÔIÚàˆMØ—k‘k $Ó'ò #�Ø—G‘G˜C“L�Ù §¡ f¤Øà˜‘y—‘Ó(�Ø—{‘{¨�{Ó.�ô  ŸX™XÐ&<¸dÓC�
Ù2<˜:×+Ñ+¨AÔ.À"�á08˜œS ›]˜^Ñ,¸d�à× Ñ Ø"ØØ (ñ"ô ð
  Ñ"‘ð'#ô* �L  
¨"¨]¨O¸?Ì3ÈyË>ÐJZÐZ[Ð\Ô]ð -6Ö[ b¸¸J¹Ì?Ó9ZšrÐ[ˆOÐ[Ü 	›N¬S°Ó-AÑAˆMØ˜qÒ Ü˜ ˜Ð.TÐUÔVØ+�	Ùð ˜)Ô#ð
Ø#Ÿ|™|Ð.IÈ(ÐUVÉ,ÈÐWYÐ,ZÓ[�HØ—~‘~Ó'¨!Ò+Ø Ÿ™×,Ñ,Ô.ÜŸ
™
 1�äÐ >Ô@Ùñ &ðe8	ðz 	�‰ŒØ	�‰Œð (ÖM˜¨2¨j©>¼_Ó+L’ÐM€IÐMÜ	Ð/´°I³Ð/?Ð
@ÔAØÐùò= \øô" !ò ÜÐ7¸°zÀÀAÀ3ÐGÔHÝûðûô ò $Ü�˜q˜cÐ"×#Ñ#ûð$ûð 	�‰ŒØ	�‰�üò Nsy   ¢FK3 Æ7KÇ	KÇ6K3 ÈA&KÉ,K3 ÊL<Ê'L<ËK3 Ë	K0ËK+Ë%K3 Ë+K0Ë0K3 Ë3	LË<LÌ
L ÌLÌL Ì"L9c                 ó  — | d   }	 |j                  |dd¬«       t        j                  d«       |j                  «       }t	        |d«      }| d   }|j                  dd	d
i¬«      }|r$|j                  d«      r|d   j                  «       }| d   }|j                  dd	di¬«      }|r'|j                  d«      r|d   j                  «       dd }|j                  dd¬«      xs |j                  dd¬«      }	d}
|	rt        |	«      }
n!|j                  dd„ ¬«      }|rt        |«      }
|j                  }d}|
r"t	        |
d«      }|j                  dd¬«      dd }t        |||||
|dœS # t        $ r}t        d|› d|› �«       Y d}~yd}~ww xY w)z(Fetch a detail page and extract content.r;   r%   r&   r'   r   r+   r:   ÚmetaÚnameÚArticleTitle)ÚattrsrJ   r<   ÚPubDateNé
   ÚdivÚarticle__content)Úidr3   r9   c                 ó$   — | xr dt        | «      v S )Nzwrapper-detail)Ústrr0   s    r   r2   zcrawl_detail.<locals>.<lambda>©   s   € ¸Ò8XÐ>NÔRUÐVWÓRXÐ>X€ r   ú T)Ú	separatorr8   i,  )Ú	site_namer:   Úpage_urlÚpublish_dateÚ
source_urlrJ   Úsummaryz[Detail] Error r=   )rB   rD   rE   rJ   r   rK   rM   r8   ru   r;   rN   Ú	SITE_NAMErY   rI   )Úitemr^   r;   rJ   r`   r:   Úmtr<   ÚpdÚcontent_divÚ	body_htmlÚwrapperr{   Úsummary_textÚtxt_souprh   s                   r   Úcrawl_detailr†   Œ   s±  € à
ˆu‰+€Cð2Ø�	‰	�# -¸ˆ	Ô?Ü�
‰
�1Œà—,‘,“.ˆÜ˜W mÓ4ˆð �W‘ˆØ�Y‰Y�v f¨nÐ%=ˆYÓ>ˆÙ�"—&‘&˜Ô#Ø�y‘M×'Ñ'Ó)ˆEð ˜
Ñ#ˆØ�Y‰Y�v f¨iÐ%8ˆYÓ9ˆÙ�"—&‘&˜Ô#Ø˜)‘}×*Ñ*Ó,¨S¨bÐ1ˆHð —i‘i Ð*<�iÓ=ÒlÀÇÁÈ5ÐYkÀÓAlˆØˆ	ÙÜ˜KÓ(‰Ià—i‘i Ñ.X�iÓYˆGÙÜ ›L�	ð —X‘Xˆ
ð ˆÙÜ$ Y°Ó>ˆHØ#×,Ñ,°sÀ$Ð,ÓGÈÈÐMˆLô #ØØ"Ø$Ø$Ø Ø#ñ
ð 	
øô ò Ü� ˜u B q cÐ*Ô+Üûðús   ‡E E( Å(	FÅ1FÆFc                 óš  — t        «       }|j                  «       }d}| D ]R  }	 |j                  d|d   |d   |d   |d   |d   |d   |j                  d	d
«      f«       |j                  dkD  r|dz  }ŒT |j                  «        |j                  «        |S # t
        $ r+}t        d|j                  dd«      › d|› �«       Y d}~Œ¦d}~ww xY w)zSave records to gov_raw tabler   z±
                INSERT OR IGNORE INTO gov_raw (site_name, title, page_url, publish_date, source_url, content, summary)
                VALUES (?, ?, ?, ?, ?, ?, ?)
            rx   r:   ry   rz   r{   rJ   r|   r9   r   z[DB] Error inserting ú?r=   N)	r   Úcursorr   rM   ÚrowcountrY   rI   ÚcommitrZ   )Úrecordsr   r‰   ÚinsertedÚrecrh   s         r   Ú
save_to_dbr�   Å   së   € äÓ€DØ�[‰[‹]€Fà€HØò Hˆð	HØ�N‰Nð ð �KÑ  # g¡,Ø�J‘  ^Ñ!4Ø�LÑ! 3 y¡>Ø—‘˜	 2Ó&ð	ôð �‰ Ò"Ø˜A‘�øðHð  	‡K�K„MØ‡J�J„LØ€Oøô ò 	HÜÐ)¨#¯'©'°'¸3Ó*?Ð)@ÀÀ1À#ÐF×GÑGûð	Hús   £ABÂ	C
Â!CÃC
c            	      óÜ  — t        d«       t        dt        › �«       t        d«       t        d¬«      } t        dt        | «      › �«       | st        d«       y t        dt        | «      › d	�«       t	        «       \  }}}|j                  «       }g }d
}t        | «      D ]T  \  }}t        ||«      }	|	r<|j                  |	«       |dz   dz  d
k(  sŒ1t        d|dz   › dt        | «      › d�«       ŒP|dz  }ŒV |j                  «        |j                  «        t        dt        |«      › d|› d�«       t        d«       t        |«      }
t        d|
› dt        |«      › d�«       t        d«       y )Nu4   === å½­å·žå¸‚ç”Ÿæ€�çŽ¯å¢ƒå±€-çŽ¯è¯„å®¡æ‰¹ çˆ¬è™« ===u   3å¹´æˆªæ­¢æ—¥æœŸ: z!
--- Step 1: Crawl list pages ---é	   )r\   zTotal items from list: zNo items found, exitingz
--- Step 2: Crawl z detail pages ---r   r   rp   z	[Detail] ú/z donez
Detail crawl complete: z
 success, z errorsz
--- Step 3: Save to DB ---z	Inserted z new records (total fetched: r>   z
=== Done ===)rI   rT   ri   rR   r#   rA   Ú	enumerater†   rS   rZ   r[   r�   )Úitemsr    r!   r"   r^   rŒ   ÚerrorsÚir~   rŽ   r�   s              r   Úmainr—   à   se  € Ü	Ð@ÔBÜ	ÐœÐ/Ð
0Ô1ô 
Ð
.Ô/Ü qÔ)€EÜ	Ð#¤C¨£J <Ð
0Ô1áÜÐ'Ô(Øô 
Ð ¤ U£ Ð,=Ð
>Ô?ä$Ó&�O€A€w�Ø�<‰<‹>€Dà€GØ€FÜ˜UÓ#ò ‰ˆˆ4Ü˜4 Ó&ˆÙØ�N‰N˜3ÔØ�A‘˜‰|˜qÓ Ü˜	 ! A¡#  a¬¨E«
 |°5Ð9Õ:à�a‰K‰Fðð ‡M�M„OØ‡F�F„Hä	Ð%¤c¨'£l ^°:¸f¸XÀWÐ
MÔNô 
Ð
(Ô)Ü˜'Ó"€HÜ	ˆI�h�ZÐ<¼SÀ»\¸NÈ!Ð
LÔMä	Ð
Õr   Ú__main__)r‘   )(Ú__doc__ÚsysÚosrO   ÚjsonrD   r   r   Úurllib.parser   ÚpathÚinsertÚdirnameÚabspathÚ__file__Úbs4r   Úplaywright.sync_apir   r   Ú_SYSrR   ÚargvÚisdigitÚintrH   rI   ru   r   r}   rC   ÚnowÚstrftimerT   r#   ri   r†   r�   r—   Ú__name__r/   r   r   ú<module>r¬      s  ðñó Û 	Û 	Û Û ß (Ý  ð ‡�‡���2—7‘7—?‘? 2§7¡7§?¡?°8Ó#<Ó=Ô >å Ý /ð €Û Ù" 4§9¡9›~°Ò1°d·i±iÀ±l×6JÑ6JÔ6L‰#ˆd�i‰i˜‰lÔ
ÐRV€Ø
ÐÙ	Ð
¡# g£,Ñ
.Ô/òð 4€	Ø?€Ø�8—<‘<“>¡I°5Ô$9Ñ9×CÑCÀJÓO€òó Nòb6òrò6(ðV ˆzÒÙ…Fð r   