Ë
    ­�jË*  ã                   ó"  — 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ZddlmZmZ ddl	m
Z
 dZdZdZdZdZ ej                   «        ed	¬
«      z
  j#                  d«      ZdZdZdZdZdZd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zdd„Z e!dk(  r e«        yy)uÃ  å®£æ±‰åŽ¿äººæ°‘æ”¿åºœ - çŽ¯è¯„å…¬ç¤ºæ �ç›®çˆ¬è™« (xxgk-list-qthbxx.html)
ç«™ç‚¹: https://www.xuanhan.gov.cn (å››å·�è¾¾å·ž)
æ �ç›®: /xxgk-list-qthbxx.html (çŽ¯è¯„å…¬ç¤º, 888æ�¡/30é¡µ)
åˆ—è¡¨: POST /api-ajax_list-{page}.html (é¡µé�¢å†… fetch, jQuery æ•°ç»„åº�åˆ—åŒ– ajax_type[]=...; requests ç›´è¿žè¿”'æ— æ•ˆæ“�ä½œ'é¡» playwright session)
è¯¦æƒ…: GET /xxgk-show-{id}.html â†’ div#content æ­£æ–‡ + æ­£æ–‡å†… /uploadfile/ é™„ä»¶ç›¸å¯¹è·¯å¾„ç»�å¯¹åŒ–
WAF: æ—  (ä½† API æ ¡éªŒ session â†’ ç”¨ playwright é¡µé�¢å†… fetch)
å…¥åº“: è‡ªåŠ¨æ£€æµ‹ /root/search.db å­˜åœ¨åˆ™ INSERT OR IGNORE ç›´æ�’ gov_raw (FTS è§¦å�‘å™¨è‡ªåŠ¨å�Œæ­¥ gov_search)
è¿�è¡Œ: python3 crawl_xuanhan_hpgs.py [--pages=N] [--no-db] [--sync-only]
é    N)ÚdatetimeÚ	timedelta)Úsync_playwrightu   å®£æ±‰åŽ¿-çŽ¯è¯„å…¬ç¤ºzhttps://www.xuanhan.gov.cnz0https://www.xuanhan.gov.cn/xxgk-list-qthbxx.htmlé   iG  )Údaysz%Y-%m-%dzoMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36z/tmp/xuanhan_hpgs.jsonlz/root/search.dbu   çŽ¯è¯„å…¬ç¤ºzäajax_type[]=45_xxgk&ajax_type[]=2498&ajax_type[]=45&ajax_type[]=xxgk&ajax_type[]=Y-m-d&ajax_type[]=36&ajax_type[]=30&ajax_type[]=is_top%20DESC&ajax_type[]=inputtime%20DESC&ajax_type[]=displayorder%20DESC&ajax_type[]=null&is_ds=1c                  óÎ   — t         j                  dd D ]O  } | j                  d«      rt        | j	                  d«      d   «      c S | j                  «       sŒDt        | «      c S  y)u   æ”¯æŒ� --pages=N å’Œçº¯æ•°å­—é   Nz--pages=ú=r   )ÚsysÚargvÚ
startswithÚintÚsplitÚisdigit)Úas    ú'/root/gov_crawler/crawl_xuanhan_hpgs.pyÚparse_pages_argr       sU   € ä�X‰X�a�bˆ\ò ˆØ�<‰<˜
Ô#Ü�q—w‘w˜s“| A‘Ó'Ò'Ø�9‰9�;Ü�q“6ŠMð	ð
 ó    c                 óœ   — t        j                  dd| xs d«      j                  «       } | j                  dd«      j                  dd«      } | S )Nu   ^[â€¢Â·Â·.\s]+Ú u   â€‹u   ï»¿)ÚreÚsubÚstripÚreplace©Úts    r   Úclean_titler   )   sD   € Ü
�‰Ð  " a¢g¨2Ó.×4Ñ4Ó6€AØ	�	‰	�(˜BÓ×'Ñ'¨°"Ó5€AØ€Hr   c                 ó  — ddl m}  || d«      }|j                  d„ «      D ]  }|j                  «        Œ |j                  ddg«      D ]  }|j	                  «        Œ 	 |j                  d«      D �cg c]  }|j                  d«      sŒ|‘Œ }}|sn|d   j	                  «        ŒG|j                  d«      D ]?  }|j                  d«      sŒ|j                  d	«      rd	|j                  d	«      ini |_        ŒA t        |«      S c c}w )
u@   æ­£æ–‡æ¸…æ´—: span/font unwrap + åµŒå¥—pæ‰�å¹³åŒ– + ä¿�ç•™è¡¨æ ¼r   )ÚBeautifulSoupzhtml.parserc                 ó:   — | j                   xr d| j                   v S )Nú:)Únamer   s    r   ú<lambda>zclean_content.<locals>.<lambda>2   s   €  q§v¡vÒ'?°#¸¿¹°-€ r   ÚspanÚfontÚpÚstyleÚalign)	Úbs4r   Úfind_allÚ	decomposeÚunwrapÚfindÚgetÚattrsÚstr)Úhtmlr   ÚsoupÚtagr&   Únesteds         r   Úclean_contentr5   .   sø   € å!Ù˜˜}Ó-€DØ�}‰}Ñ?Ó@ò ˆØ�‰�ðà�}‰}˜f fÐ-Ó.ò ˆØ�
‰
�ðð Ø!Ÿ]™]¨3Ó/Ö?˜°1·6±6¸#µ;’!Ð?ˆÐ?ÙØØˆq‰	×ÑÔð	 ð
 �]‰]˜3Óò JˆØ�5‰5��>Ø34·5±5¸´>�w §¡ g£Ñ/ÀrˆA�GðJô ˆt‹9Ðùò @s   Á3DÂ
Dc                 óš  — g }t        j                  d| t         j                  t         j                  z  «      D �]N  }|j	                  d«      j                  «       }|r|j                  d«      rŒ7t        j                  d|t         j                  «      sŒ]t        j                  d|j	                  d«      «      }|r|j	                  d«      }nHt        j                  d|j	                  d«      «      }|r|j	                  d«      j                  «       nd}|j                  d	«      r
t        |z   }n,|j                  d
«      s|j                  d	d«      d   d	z   |z   }|j                  |xs |j                  d	«      d   |dœ«       �ŒQ t        «       }g }	|D ]/  }
|
d   |vsŒ|j                  |
d   «       |	j                  |
«       Œ1 |	S )uA   æ­£æ–‡å†…é™„ä»¶: <a href="/uploadfile/..."> + sudyfile-attr titlez"<a[^>]+href="([^"]+)"[^>]*>.*?</a>r	   Ú
javascriptz#\.(pdf|docx?|xlsx?|zip|rar|7z|doc)$ztitle['\\]*:['\\]*([^'\\}]+)r   z>([^<]{1,100})</a>r   ú/Úhttpéÿÿÿÿ)r"   Úurlr;   )r   ÚfinditerÚIÚSÚgroupr   r   ÚsearchÚBASEÚrsplitÚappendr   ÚsetÚadd)Ú	html_fragÚ
detail_urlÚattsÚmÚhrefÚm2r"   Úm3ÚseenÚuniqr   s              r   Úextract_attachmentsrO   B   s}  € à€DÜ�[‰[Ð>À	Ì2Ï4É4ÔRT×RVÑRVÉ;ÓWó LˆØ�w‰w�q‹z×ÑÓ!ˆÙ�t—‘ |Ô4ØÜ�9‰9Ð;¸TÄ2Ç4Á4ÕHä—‘Ð:¸A¿G¹GÀA»JÓGˆBÙØ—x‘x “{‘ä—Y‘YÐ4°a·g±g¸a³jÓA�Ù.0�r—x‘x “{×(Ñ(Ô*°b�Ø�‰˜sÔ#Ü˜d‘{‘Ø—_‘_ VÔ,Ø!×(Ñ(¨¨aÓ0°Ñ3°cÑ9¸DÑ@�Ø�K‰K Ò!<¨¯©°C«¸Ñ)<ÀTÑJÖKð!Lô" ‹5€DØ€DØò ˆØˆU‰8˜4ÒØ�H‰H�Q�u‘XÔØ�K‰K˜�Nðð €Kr   c           
      ó”  — t        d«      D ]o  }	 | j                  d|z  t        «      }t        j                  |«      }|j                  d«      dk(  r't        d|› d�d¬«       t        j                  d	«       Œm|c S  y# t        $ r?}t        d|› d
t        |«      dd › d�d¬«       t        j                  d	«       Y d}~Œ¶d}~ww xY w)u8   é¡µé�¢å†… fetch åˆ—è¡¨ API (jQuery æ•°ç»„åº�åˆ—åŒ– body)é   al  async (b) => {
                const r = await fetch('/api-ajax_list-' + '%d' + '.html', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'X-Requested-With': 'XMLHttpRequest'},
                    body: b
                });
                return await r.text();
            }Ústatusr   õ     é¡µu    æ— æ•ˆæ“�ä½œ é‡�è¯•...T©Úflushé   u	    å¤±è´¥: NéP   u
    é‡�è¯•...)ÚrangeÚevaluateÚ	AJAX_BODYÚjsonÚloadsr.   ÚprintÚtimeÚsleepÚ	Exceptionr0   )ÚpageÚpnÚ_ÚbodyÚdÚes         r   Ú
fetch_listrg   ^   sÊ   € ä�1‹Xò ˆð	Ø—=‘=ð "ð ñ"ô !ó"ˆDô —
‘
˜4Ó ˆAØ�u‰u�X‹ !Ò#Ü˜˜b˜TÐ!8Ð9ÀÕFÜ—
‘
˜1”ØØŠHðð& øô ò 	Ü�E˜"˜˜Y¤s¨1£v¨c¨r { m°:Ð>ÀdÕKÜ�J‰J�q�M‰Mûð	ús   �A(A?Á9A?Á?	CÂ5CÃCc                 ó¸   — |j                  dd«      }t        d«      D ]  }	 | j                  d|«      c S  y# t        $ r t	        j
                  d«       Y Œ:w xY w)u>   é¡µé�¢å†… fetch è¯¦æƒ…é¡µ (httpâ†’https é˜²æ··å�ˆå†…å®¹æ‹¦æˆª)zhttp://zhttps://rQ   zAasync (u) => { const r = await fetch(u); return await r.text(); }N)r   rX   rY   r`   r^   r_   )ra   rG   Ú	fetch_urlrc   s       r   Úfetch_detailrj   u   s`   € à×"Ñ" 9¨jÓ9€IÜ�1‹Xò ˆð	Ø—=‘=Ð!hÐjsÓtÒtðð
 øô ò 	Ü�J‰J�qŽMð	ús   ¢8¸AÁAc                 ó´  — | syt         j                  j                  t        «      st	        dt        › d�d¬«       yt        j                  t        d¬«      }|j                  d«       d	x}}|j                  «       }| D ]�  }	 |j                  d
t        |d   |d   |d   |d   |d   |d   xs dd d t        d|d   |j                  dd«      |j                  dd«      f«       |j                  d	kD  r|dz  }n|dz  }|j                  «        Œ‘ |j                  «        ||fS # t
        j                  $ r}t	        d|› �d¬«       |dz  }Y d }~ŒSd }~ww xY w)N)r   r   u     æœªå�‘çŽ° u   , è·³è¿‡å…¥åº“ (ä»…å†™ JSONL)TrT   i"  )ÚtimeoutzPRAGMA busy_timeout=290000r   zçINSERT OR IGNORE INTO gov_raw
                   (site_name, source_url, page_url, title, publish_date, content, summary, category, script_name, attachments, group_name, industry)
                   VALUES (?,?,?,?,?,?,?,?,?,?,?,?)r;   ÚtitleÚpub_dateÚcontentr   iô  zcrawl_xuanhan_hpgs.pyÚattachmentsÚ
group_nameõ   å››å·�ÚindustryÚotherr	   z
  DB err: )ÚosÚpathÚexistsÚDB_PATHr]   Úsqlite3ÚconnectÚexecuteÚcursorÚ	SITE_NAMEÚCATEGORYr.   ÚrowcountÚErrorÚcommitÚclose)ÚresultsÚconnÚaddedÚskippedÚcurÚrrf   s          r   Ú
push_to_dbr‰      s[  € ÙØÜ�7‰7�>‰>œ'Ô"Ü�œW˜IÐ%BÐCÈ4ÕPØÜ�?‰?œ7¨CÔ0€DØ‡L�LÐ-Ô.ØÐ€EˆGØ
�+‰+‹-€CØò ˆð	Ø�K‰Kð7ô ˜A˜e™H a¨¡h°°'±
¸A¸j¹MÈ1ÈYÉ<Ø�I‘,Ò$ " d sÐ+¬XÐ7NÐPQÐR_ÑP`Ø—‘�| XÓ.°·±°jÀ'Ó0JðLô	ð �|‰|˜aÒØ˜‘
‘à˜1‘�ð 	�‰�ð#ð$ 	‡J�J„LØ�'ˆ>Ðøô �}‰}ò 	Ü�J˜q˜cÐ"¨$Õ/Ø�q‰L�Gûð	ús   ÂA<D%Ä%EÄ8EÅEc                  óÒ  ‡— t        «       } dt        j                  v }dt        j                  v rt        dd¬«       y t        dt        › d| xs d› d	t
        › �d¬«       g }d
d
d
d
d
dœ}t        «       5 }|j                  j                  dddg¬«      }|j                  t        ddddœd¬«      }|j                  «       }	 |j                  t        dd¬«       |j                  d«       | r| nt         }d}	t#        d|dz   «      D �]O  }
t%        ||
«      }|st        d|
› d�d¬«       Œ$|j'                  dg «      }|j'                  dd
«      }|s �nt        d|
› d|› dt)        |«      › d |› d!�	d¬«       |D �]´  }|d"xx   dz  cc<   t+        |j'                  d#d$«      «      }|j'                  d%«      xs d$d d& }|j'                  d'd$«      Š|r|t
        k  r|d(xx   dz  cc<   d}	 �nEt-        |‰«      }|s!t        d)|d d* › �d¬«       |d+xx   dz  cc<   Œ¢t/        j0                  d,|t.        j2                  «      }|r|j5                  d«      nd$}|rt7        |«      nd$}t/        j8                  d-d$|«      j;                  «       }t)        |«      d&k  r&d.|vr"t        d/|d d* › �d¬«       |d0xx   dz  cc<   �ŒDd.|v rt/        j8                  d1ˆfd2„|«      }t=        |‰«      }t        |||‰‰d3d4|rt?        j@                  |d¬5«      nd$d6œ	}|jC                  |«       |d7xx   dz  cc<   �Œ· |	rt        d8d¬«        ntE        jF                  d9«       �ŒR |jI                  «        d d d «       tK        ||«       |s"tM        |«      \  }}t        d:|› d;|› d<�d¬«       t        d=|d"   › d>|d7   › d?|d(   › d@|d0   › dA|d+   › d<�d¬«       y # t        $ r Y �Œ w xY w# 1 sw Y   ŒvxY w)BNz--no-dbz--sync-onlyu2   sync-only: æŠ“å�–+å…¥åº“ä¸€ä½“, æ— éœ€å�•ç‹¬å�Œæ­¥TrT   u   ç«™ç‚¹: u    æœ€å¤§é¡µ: u   å…¨é‡�z	 CUTOFF: r   )Ú	total_apiÚkeptÚcutoffÚemptyÚdetail_failz--no-sandboxz--disable-dev-shm-usage)ÚheadlessÚargszzh-CNiV  i„  )ÚwidthÚheight)Ú
user_agentÚlocaleÚviewportÚignore_https_errorsiÈ¯  Údomcontentloaded)rl   Ú
wait_untili¸  Fr	   rS   u    åˆ—è¡¨å¤±è´¥ÚdataÚtotalr8   ú u    æ�¡ (total ú)r‹   rm   r   Ú	inputtimeé
   r;   r�   u       è¯¦æƒ…å¤±è´¥: r   r�   z/<div[^>]*id="content"[^>]*>(.*?)</div>\s*</div>z<[^>]+>z<imgu       ç©ºæ­£æ–‡è·³è¿‡: rŽ   z(<img[^>]+src=")([^"]+)(")c                 ór  •— | j                  d«      | j                  d«      j                  d«      r| j                  d«      na| j                  d«      j                  d«      rt        | j                  d«      z   n)‰j                  dd«      d   dz   | j                  d«      z   z   | j                  d«      z   S )Nr	   rQ   r9   r8   r   rV   )r?   r   rA   rB   )ÚmmrG   s    €r   r#   zmain.<locals>.<lambda>Û   s  ø€  2§8¡8¨A£;ÀÇÁÈ!Ã×AWÑAWÐX^ÔA_°"·(±(¸1´+Ð|~÷  }Eñ  }Eð  FGó  }H÷  }Sñ  }Sð  TWô  }XÔfjÐmo×muÑmuÐvwÓmxÒfxð  ^h÷  ^oñ  ^oð  psð  uvó  ^wð  xyñ  ^zð  }@ñ  ^@ð  CE÷  CKñ  CKð  LMó  CNñ  ^Nñ  $Pð  SU÷  S[ñ  S[ð  \]ó  S^ñ  $^€ r   rr   rt   ©Úensure_ascii)	Ú	site_namerm   rn   ro   Ú
source_urlr;   rq   rs   rp   rŒ   u       æ—¥æœŸ < CUTOFF å�œæ­¢gš™™™™™é?u   === å…¥åº“: æ–°å¢žu    è·³è¿‡z ===u   === å®Œæˆ�: APIu    ä¿�ç•™u
    CUTOFFæˆªu    ç©ºu    è¯¦æƒ…fail)'r   r   r   r]   r}   ÚCUTOFFr   ÚchromiumÚlaunchÚnew_contextÚUAÚnew_pageÚgotoÚLIST_1r`   Úwait_for_timeoutÚTOTAL_PAGESrX   rg   r.   Úlenr   rj   r   r@   r>   r?   r5   r   r   rO   r[   ÚdumpsrC   r^   r_   r‚   Úsave_resultsr‰   )Ú	max_pagesÚno_dbrƒ   Ústatsr&   ÚbrowserÚctxra   Útotal_pagesÚ
cutoff_hitrb   rš   Úrowsr›   Úitemrm   rn   Údetail_htmlrI   Úcontent_htmlro   ÚtextrH   Úrecr…   r†   rG   s                             @r   ÚmainrÀ   ž   s]  ø€ ÜÓ!€IØœŸ™Ð!€EØœŸ™Ñ ÜÐBÈ$ÕOØÜ	ˆH”Y�K˜|¨IÒ,A¸Ð+BÀ)ÌFÈ8Ð
TÐ\`Õaà€GØ Q°!¸aÐPQÑR€EÜ	Ó	ð H˜aØ—*‘*×#Ñ#ØØ Ð";Ð<ð $ó >ˆð ×!Ñ!¬R¸ÐTXÐdgÑJhð  CÐ!ó  DˆØ�|‰|‹~ˆð	Ø�I‰I”f eÐ8JˆIÔKð 	×Ñ˜dÔ#á#,‘i´+ˆØˆ
Ü˜˜;¨™?Ó+ó 8	ˆBÜ˜d BÓ'ˆDÙÜ˜˜b˜T Ð/°tÕ<ØØ—8‘8˜F BÓ'ˆDØ—H‘H˜W aÓ(ˆEÙÚÜ�E˜"˜˜Q˜{˜m¨1¬S°«Y¨K°|ÀEÀ7È!ÐLÐTXÕYØó *#�Ø�kÓ" aÑ'Ó"Ü# D§H¡H¨W°bÓ$9Ó:�Ø ŸH™H [Ó1Ò7°R¸¸"Ð=�Ø!ŸX™X e¨RÓ0�
Ù ¬6Ò 1Ø˜(“O qÑ(“OØ!%�JÚÜ*¨4°Ó<�Ù"ÜÐ.¨u°S°b¨z¨lÐ;À4ÕHØ˜-Ó(¨AÑ-Ó(Øä—I‘IÐPÐR]Ô_a×_cÑ_cÓd�Ù-.˜qŸw™w qœz°B�Ù9Eœ-¨Ô5È2�Ü—v‘v˜j¨"¨gÓ6×<Ñ<Ó>�Ü�t“9˜r’> f°GÑ&;ÜÐ1°%¸¸°*°Ð>ÀdÕKØ˜'“N aÑ'“NÙà˜WÑ$Ü Ÿf™fØ5ó ^Øó!�Gô +¨<¸ÓD�ä!*Ø"Ø (Ø&Ø",Ø%Ø"*Ø 'ÙKO¤4§:¡:¨dÀÕ#GÐUWñ
�ð —‘˜sÔ#Ø�f“ Ñ"•ðU*#ñV ÜÐ2¸4Õ@ÙÜ�J‰J�sŽOðq8	ðt 	�‰Œ÷QHôT �˜%Ô ÙÜ# GÓ,‰ˆˆwÜÐ" 5 '¨°°	¸Ð>ÀdÕKÜ	ˆO˜E +Ñ.Ð/¨w°u¸V±}°oÀZÐPUÐV^ÑP_ÐO`Ð`dÐejÐkrÑesÐdtÐtð  AFð  GTñ  AUð  @Vð  VZð  [ð  cgö  høôM ò 	Úð	ú÷Hð Hús2   Á4AOÃOÃJOÏ	OÏOÏOÏOÏO&c                 óô   — t        t        dd¬«      5 }| D ]+  }|j                  t        j                  |d¬«      dz   «       Œ- 	 d d d «       t        dt        | «      › dt        › �d	¬
«       y # 1 sw Y   Œ*xY w)NÚwzutf-8)ÚencodingFr¢   ú
u   å·²å†™ u    æ�¡åˆ° TrT   )ÚopenÚOUTÚwriter[   r±   r]   r°   )rƒ   rµ   Úfrˆ   s       r   r²   r²   ø   sm   € Ü	Œc�3 Ô	)ð >¨QØò 	>ˆAØ�G‰G”D—J‘J˜q¨uÔ5¸Ñ<Õ=ñ	>÷>ô 
ˆG”C˜“L�> ¬#¨Ð
/°tÖ<÷>ð >ús   “1A.Á.A7Ú__main__)N)"Ú__doc__r[   ru   r   r   r^   ry   r   r   Úplaywright.sync_apir   r}   rA   r­   Ú	PAGE_SIZEr¯   ÚnowÚstrftimer¦   rª   rÆ   rx   r~   rZ   r   r   r5   rO   rg   rj   r‰   rÀ   r²   Ú__name__© r   r   ú<module>rÑ      s¶   ðñ÷ (× '× 'ß (Ý /à$€	Ø#€Ø	;€Ø€	Ø€Ø
ˆ(�,‰,‹.™9¨%Ô0Ñ
0×	:Ñ	:¸:Ó	F€Øv€Ø€Ø
€Ø€ðI€	ò
òò
ò(ò8ò.òò>Xhót=ð ˆzÒÙ…Fð r   