Ë
    ¸¬ujE   ã                   ó  — 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 ddlm	Z	 ddl
m
Z
mZ ddlmZmZ  ej                  dd«      Zd	Zd
ZdZe› d�ZdddœZddiZdZdZd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Z e!dk(  r e «        yy)u?  
crawl_chengwu.py â€” æˆ�æ­¦åŽ¿äººæ°‘æ”¿åºœÂ·çŽ¯å¢ƒå½±å“�è¯„ä»·å…¬ä¼—å�‚ä¸Ž
======================================================
CMS: ELS æœ�åŠ¡ç³»ç»Ÿï¼ŒAPI é©±åŠ¨

åˆ—è¡¨ï¼šPOST /els-service/article/{pageNo}/{pageSize}
      JSON body: {"catas": ["1535192418234798080"]}
åˆ†é¡µï¼š10æ�¡/é¡µ
è¯¦æƒ…ï¼š/10086/{dwid}/{xxid}.html
      æ ‡é¢˜ <meta name="ArticleTitle">
      æ—¥æœŸ <meta name="PubDate">
      æ­£æ–‡ embedded in <script>var memo = "..."</script>

ç”¨æ³•:
    python3 crawl_chengwu.py               # å…¨é‡�
    python3 crawl_chengwu.py 1             # å¢žé‡�
é    N)ÚBeautifulSoup)Úurljoin)ÚdatetimeÚ	timedelta)ÚThreadPoolExecutorÚas_completedÚ	SEARCH_DBz/root/search.dbu   æˆ�æ­¦åŽ¿äººæ°‘æ”¿åºœu   çŽ¯å¢ƒå½±å“�è¯„ä»·å…¬ä¼—å�‚ä¸Žzhttp://www.chengwu.gov.cnz/els-service/articlezoMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36zapplication/json;charset=utf-8)ú
User-AgentzContent-Typer
   é   é
   c                 ó    — t        d| › �«       y )Nz
[chengwu] )Úprint)Úmsgs    ú"/root/gov_crawler/crawl_chengwu.pyÚlogr   5   s   € Ü	ˆJ�s�eÐ
Õó    c                 ó  — t         › d| › dt        › �}ddgi}	 t        j                  |t        |d¬«      }|j                  «       }|j                  di «      j                  dg «      }g }|D ]m  }|j                  dd«      }	|j                  dd«      }
|j                  dd«      j                  «       }|j                  dd«      }|j                  |	|
||f«       Œo |S # t        $ r}t        d| › d	|› �«       g cY d
}~S d
}~ww xY w)zLFetch one list page from API. Returns list of (xxid, dwid, title, date_str).ú/ÚcatasÚ1535192418234798080é   )ÚheadersÚjsonÚtimeoutÚdataÚcontentsz  ERROR list page ú: NÚxxidÚ ÚdwidÚsubjectÚfwdate)ÚAPI_URLÚ	PAGE_SIZEÚrequestsÚpostÚHEADERSr   ÚgetÚ	Exceptionr   ÚstripÚappend)Úpage_noÚurlÚpayloadÚrespr   r   ÚeÚitemsÚcr   r    ÚtitleÚdate_strs                r   Úfetch_list_pager5   9   s  € äˆI�Q�w�i˜q¤ Ð
,€CØÐ.Ð/Ð0€GðÜ�}‰}˜S¬'¸ÈÔLˆØ�y‰y‹{ˆØ—8‘8˜F BÓ'×+Ñ+¨J¸Ó;ˆð
 €EØò 4ˆØ�u‰u�V˜RÓ ˆØ�u‰u�V˜RÓ ˆØ—‘�i Ó$×*Ñ*Ó,ˆØ—5‘5˜ 2Ó&ˆØ�‰�d˜D %¨Ð2Õ3ð4ð €Løô ò ÜÐ   	¨¨A¨3Ð/Ô0Ø�	ûðús   ™AC Ã	DÃ'C?Ã9DÃ?Dc                 ó\  — | j                  d«      }|dk  ry| |d }|j                  d«      dz   }|}|t        |«      k  r||   dk(  r|dz  }nb||   dk(  rU||dz   |d	z    j                  «       }|r3|j	                  d
«      s"|j	                  d«      s|j	                  d«      rn|dz  }n|dz  }|t        |«      k  rŒ||| }	 |j                  «       j                  d«      }|j                  dd«      }|j                  dd«      }|j                  dd«      }|S # t        $ r |}Y ŒEw xY w)z4Extract and decode var memo = '...' from script tag.z
var memo =r   r   Nú"é   ú\é   é   ú;ú
úÚunicode_escapez\/r   z\nz\tú	)	ÚfindÚindexÚlenr*   Ú
startswithÚencodeÚdecoder)   Úreplace)ÚhtmlÚidxÚchunkÚquote_startÚendÚrestÚmemo_rawÚmemo_decodeds           r   Úextract_memo_contentrP   Q   sN  € à
�)‰)�LÓ
!€CØ
ˆQ‚wØà��ˆJ€EØ—+‘+˜cÓ" QÑ&€Kà
€CØ
”�E“
Ò
Ø�‰:˜ÒØ�1‰H‰CØ�3‰Z˜3ÒØ˜˜Q™˜s 1™uÐ%×+Ñ+Ó-ˆDÙ˜4Ÿ?™?¨3Ô/°4·?±?À4Ô3HÈDÏOÉOÐ\`ÔLaØØ�1‰H‰Cà�1‰HˆCð ”�E“
Ó
ð �[ Ð%€Hð Ø—‘Ó(×/Ñ/Ð0@ÓAˆð
  ×'Ñ'¨¨sÓ3€LØ×'Ñ'¨¨tÓ4€LØ×'Ñ'¨¨tÓ4€LàÐøô ò  ØŠð ús   ÃD ÄD+Ä*D+c                 ór  — t         › d|› d| › d�}	 t        j                  |t        d¬«      }d|_        |j
                  }t        |d«      }|j                  dddi¬«      }|r$|j                  d«      r|d   j                  «       nd}d}	|j                  dddi¬«      }
|
rK|
j                  d«      r:t        j                  d|
d   j                  «       «      }|r|j                  d«      }	t        |«      }|st        d|› �«       d	|	|fS ||	|fS # t        $ r}t        d|› d|› �«       Y d	}~y
d	}~ww xY w)z=Return (content_html, date_str, title) or (None, None, None).ú/10086/r   ú.htmlr   )r   r   zutf-8z  ERROR r   N©NNNzhtml.parserÚmetaÚnameÚArticleTitle)ÚattrsÚcontentr   ÚPubDatez(\d{4}-\d{2}-\d{2})r8   z  WARNING: no content for )ÚBASE_URLr%   r(   ÚHEADERS_HTMLÚencodingÚtextr)   r   r   rA   r*   ÚreÚmatchÚgrouprP   )r   r    r-   r/   rH   r0   ÚsoupÚ
meta_titler3   r4   Ú	meta_dateÚmÚcontent_htmls                r   Úfetch_detailrg   v   sI  € äˆJ�g˜d˜V 1 T F¨%Ð
0€Cð Ü�|‰|˜C¬¸rÔBˆØˆŒØ�y‰yˆô
 ˜˜}Ó-€Dð —‘˜6¨&°.Ð)A�ÓB€JÙ-7¸J¿N¹NÈ9Ô<UˆJ�yÑ!×'Ñ'Ô)Ð[]€Eð €HØ—	‘	˜&¨°Ð(;�	Ó<€IÙ�Y—]‘] 9Ô-Ü�H‰HÐ+¨Y°yÑ-A×-GÑ-GÓ-IÓJˆÙØ—w‘w˜q“zˆHô (¨Ó-€LáÜÐ(¨¨Ð.Ô/Ø�X˜uÐ$Ð$à˜ 5Ð(Ð(øô3 ò  Üˆh�s�e˜2˜a˜SÐ!Ô"Üûð ús   ‘/D Ä	D6ÄD1Ä1D6c                 óN  — i }t        t        ¬«      5 }| D ���ci c]!  \  }}}}|j                  t        ||«      ||f“Œ# }}}}t	        |«      D ]   }||   \  }}	 |j                  «       |||f<   Œ" 	 ddd«       |S c c}}}w # t        $ r
 d|||f<   Y ŒGw xY w# 1 sw Y   |S xY w)z,items: list of (xxid, dwid, title, date_str))Úmax_workersrT   N)r   ÚMAX_WORKERSÚsubmitrg   r   Úresultr)   )r1   ÚresultsÚexr   r    Ú_Úfut_mapÚfuts           r   Úfetch_detail_batchrr   š   sÑ   € à€GÜ	¬Ô	4ð 
;¸ð %*÷
ð 
á ��d˜A˜qð �I‰I”l D¨$Ó/°$¸°Ñ=ð
ˆò 
ô   Ó(ò 	;ˆCØ  ™‰JˆD�$ð;Ø(+¯
©
«�˜˜t˜Ò%ñ	;÷
;ð €Nùô
øô ò ;Ø(:�˜˜t˜Ó%ð;ú÷
;ð €Nús@   “Bš&A=
Á BÁBÁ0BÁ=BÂBÂBÂBÂBÂB$c           
      óT  — | sydd l }|j                  t        «      }|j                  «       }d}| D ]-  \  }}}}	 |j	                  dt
        ||||t        f«       |dz  }Œ/ |j                  «        |j                  «        |S # t        $ r}	t        d|› d|	› �«       Y d }	~	Œqd }	~	ww xY w)Nr   zœINSERT OR REPLACE INTO gov_raw
                   (site_name, page_url, title, publish_date, content, category)
                   VALUES (?, ?, ?, ?, ?, ?)r8   z  DB error for r   )Úsqlite3ÚconnectÚDB_PATHÚcursorÚexecuteÚ	SITE_NAMEÚCOLUMN_NAMEr)   r   ÚcommitÚclose)
Úrowsrt   Úconnr2   Úinsertedr-   r3   r4   rf   r0   s
             r   Ú
save_to_dbr€   «   s·   € ÙØÛØ�?‰?œ7Ó#€DØ�‰‹€AØ€HØ.2ò 
.Ñ*ˆˆU�H˜lð		.Ø�I‰Ið0ô ˜C ¨°,ÄÐLô	ð ˜‰M‰Hð
.ð 	‡K�K„MØ‡J�J„LØ€Oøô	 ò 	.Ü�/ #  b¨¨Ð,×-Ñ-ûð	.ús   º%BÂ	B'ÂB"Â"B'c                  óî   — 	 dd l } | j                  t        «      }|j                  dt        f«       |j                  «        |j                  «        y # t        $ r}t        d|› �«       Y d }~y d }~ww xY w)Nr   a  INSERT OR REPLACE INTO gov_search(rowid, title, site_name, summary)
               SELECT rowid, title, site_name,
                      CASE WHEN length(content) > 200 THEN substr(content, 1, 200) ELSE content END
               FROM gov_raw WHERE category = ?z
FTS note: )	rt   ru   rv   rx   rz   r{   r|   r)   r   )rt   r~   r0   s      r   Úrebuild_ftsr‚   Â   sf   € ðÛØ�‰œwÓ'ˆØ�‰ð2ô ˆNô	
ð 	�‰ŒØ�
‰
�øÜò Üˆj˜˜Ð×Ñûðús   ‚AA Á	A4ÁA/Á/A4c                  ó*  — t        t        j                  «      dkD  xr t        j                  d   dk(  } t        j                  «       t        d¬«      z
  j                  d«      }t        d|› �«       g }d}	 t        |«      }|s|dk(  rt        d«       y n�t        d|› d	t        |«      › d
�«       |D ����cg c]  \  }}}}|sŒ||k\  sŒ||||f‘Œ }	}}}}|j                  |	«       | rt        d«       n/|	r't        |	«      t        |«      k  rt        d|› d�«       n|dz  }Œ¯t        dt        |«      › �«       |st        d«       y g }
t        dz  }t        dt        |«      |«      D ]š  }||||z    }t        d|dz   › d|t        |«      z   › dt        |«      › d�«       t        |«      }|D ]S  \  }}}}|j                  ||fd«      \  }}}|xs |}|xs |}t        › d|› d|› d�}|
j                  ||||xs df«       ŒU Œœ t!        |
«      }t        d|› dt        |
«      › �«       |
rAt#        |
D �cg c]  }|d   sŒ	|d   ‘Œ c}«      }t        d|r|d   nd› d|r|d   nd› �«       t%        «        t        d«       y c c}}}}w c c}w ) Nr8   Ú1iG  )Údaysz%Y-%m-%dz3-year cutoff: zNo articles foundzPage r   z	 articleszIncremental: page 1 onlyz': some articles before cutoff, stoppingzTotal articles to process: zNo articles within 3 yearsé   r   z  Details [ú-r   z]...rT   rR   rS   r   zSaved: r:   zDate range: zN/Az ~ éÿÿÿÿzDone!)rC   ÚsysÚargvr   Únowr   Ústrftimer   r5   Úextendrj   Úrangerr   r(   r[   r+   r€   Úsortedr‚   )ÚincrementalÚthree_years_agoÚ	all_itemsÚpager1   r   r    r3   ÚdÚfilteredrm   Ú
batch_sizeÚbatch_startÚbatchÚ
detail_mapr4   rf   Údetail_dateÚdetail_titleÚfinal_titleÚ
final_dater-   ÚsavedÚrÚdatess                            r   Úmainr¡   Ó   sÍ  € Ü”c—h‘h“- !Ñ#Ò:¬¯©°©°sÑ(:€KÜ—|‘|“~¬	°wÔ(?Ñ?×IÑIÈ*ÓU€OÜˆ/˜/Ð*Ð+Ô,ð €IØ€Dà
Ü Ó%ˆÙØ�qŠyÜÐ'Ô(ØØäˆe�D�6˜œC ›J˜< yÐ1Ô2àGL×kÑkÑ/C¨t°T¸5À!ÒPQÐVWÐ[jÓVj�T˜4 ¨Ò*ÐkˆÓkØ×Ñ˜Ô"áÜÐ*Ô+Øáœ˜H›¬¨E«
Ò2Ü�%˜�vÐDÐEÔFØà�‰	ˆð+ ô. Ð
%¤c¨)£nÐ%5Ð6Ô7áÜÐ(Ô)Øð €GÜ˜q‘€JÜ˜Q¤ I£°
Ó;ò 
OˆØ˜+ k°JÑ&>Ð?ˆÜˆk˜+ a™-˜¨¨+´c¸%³jÑ*@Ð)AÀÄ3ÀyÃ>ÐBRÐRVÐWÔXÜ'¨Ó.ˆ
à+0ò 	OÑ'ˆD�$˜˜xØ6@·n±nÀdÈDÀ\ÐSeÓ6fÑ3ˆL˜+ |Ø&Ò/¨%ˆKØ$Ò0¨ˆJÜ�J˜g d V¨1¨T¨F°%Ð8ˆCØ�N‰N˜C ¨j¸,Ò:LÈ"ÐMÕNñ	Oð
Oô �wÓ€EÜˆ'�%�˜œ#˜g›,˜Ð(Ô)áÜ gÖ6 °°1³˜˜!›Ò6Ó7ˆÜˆl¡u˜5 š8°%Ð8¸É¸EÀ"ºIÐTYÐ;ZÐ[Ô\ä„MÜˆ…LùõW lùòN 7s   Â9J
ÃJ
ÃJ
È:
JÉJÚ__main__)"Ú__doc__Úosr_   r‰   r   r%   Úbs4r   Úurllib.parser   r   r   Úconcurrent.futuresr   r   Úgetenvrv   ry   rz   r[   r#   r'   r\   rj   r$   r   r5   rP   rg   rr   r€   r‚   r¡   Ú__name__© r   r   ú<module>r«      sÃ   ðñó$ 
Û 	Û 
Û Û Ý Ý  ß (ß ?à
ˆ"�)‰)�KÐ!2Ó
3€Ø#€	Ø.€Ø&€ØˆJÐ*Ð
+€ð3ð 5ñ	€ð ð 3ð€ð €Ø€	òòò0"òJ!)òHò"ò.ò">ðB ˆzÒÙ…Fð r   