Ë
    m„jù-  ã                   óB  — 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                  j!                  dej                  j!                  dd	«      «      Zd
ZdZdZdZ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_zibo_gxqhbj.py â€” æ·„å�šé«˜æ–°åŒºçŽ¯ä¿�å±€Â·å»ºè®¾é¡¹ç›®çŽ¯å¢ƒå½±å“�è¯„ä»·
===============================================================
CMS: æ·„å�šæ”¿åŠ¡å…¬å¼€å¹³å�°ï¼Œ?open=fdzdgknr&nr_page=N&nr_per_page=10 åˆ†é¡µ
æ€»æ–‡ç« æ•°é€šè¿‡ JavaScript å�˜é‡� fdzdgknr_total èŽ·å�–

åˆ—è¡¨ï¼š<td class="zfxxgk-list-title"><a href="...">Title</a>
        <td class="zfxxgk-list-time">YYYY-MM-DD</td>
è¯¦æƒ…ï¼š<div class="details-content" id="details-content"> æ­£æ–‡
      <meta name="ArticleTitle"> / <meta name="PubDate">

ç”¨æ³•:
    python3 crawl_zibo_gxqhbj.py               # å…¨é‡�ï¼ˆè¿‘3å¹´ï¼‰
    python3 crawl_zibo_gxqhbj.py 1             # å¢žé‡�ï¼ˆä»…æœ€æ–°é¡µï¼‰
é    N)ÚBeautifulSoup)Úurljoin)ÚdatetimeÚ	timedelta)ÚThreadPoolExecutorÚas_completedÚ	SEARCH_DBÚGOV_DB_PATHz/root/search.dbzhttp://www.china-zibo.gov.cnz6/gongkai/site_gxqhbj/channel_6076a2721887a377796bb7cf/u!   æ·„å�šé«˜æ–°æŠ€æœ¯äº§ä¸šå¼€å�‘åŒºu   é«˜æ–°åŒºçŽ¯ä¿�å±€-çŽ¯è¯„ä¿¡æ�¯é
   z
User-AgentzoMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36é   éÈ   c                 ó    — t        d| › �«       y )Nz[zibo_gxqhbj] )Úprint)Úmsgs    ú&/root/gov_crawler/crawl_zibo_gxqhbj.pyÚlogr   1   s   € Ü	ˆN˜3˜%Ð
 Õ!ó    c            	      ó6  — t         › t        › dt        › dt        t	        j                  «       «      › �} t        d«      D ]“  }	 t        j                  | t        d¬«      }d|_	        |j                  }t        j                  d|«      }|rt        |j!                  d«      «      c S t        d|dz   › d�«       t	        j                  d
|d
z  z   «       Œ• y# t        $ r9}t        d|dz   › d	|› �«       t	        j                  d
|d
z  z   «       Y d}~ŒÔd}~ww xY w)z/Fetch first page to detect total article count.z%?open=fdzdgknr&nr_page=1&nr_per_page=ú&_t=é   é   ©ÚheadersÚtimeoutúutf-8zERROR fetching first page (try é   ú): é   Nz(fdzdgknr_total\s*=\s*parseInt\("(\d+)"\)z  total not found (try ú), retryingr   )ÚBASE_URLÚ	LIST_PATHÚPER_PAGEÚintÚtimeÚrangeÚrequestsÚgetÚHEADERSÚencodingÚtextÚ	Exceptionr   ÚsleepÚreÚsearchÚgroup)ÚurlÚattemptÚrespÚhtmlÚeÚms         r   Úfetch_total_countr6   5   s  € äˆJ”y�kÐ!FÄxÀjÐPTÔUXÔY]×YbÑYbÓYdÓUeÐTfÐ
g€CÜ˜“8ò $ˆð	Ü—<‘< ¬W¸bÔAˆDØ#ˆDŒMØ—9‘9ˆDô
 �I‰IÐAÀ4ÓHˆÙÜ�q—w‘w˜q“z“?Ò"ÜÐ% g¨a¡i [°Ð<Ô=Ü�
‰
�1�w ‘{‘?Õ#ð$ð øô ò 	ÜÐ1°'¸!±)°¸CÀ¸sÐCÔDÜ�J‰J�q˜7 Q™;‘Ô'Üûð	ús   Á/CÃ	DÃ/DÄDc                 óÎ  — t         › t        › d| › dt        › dt        t	        j                  «       «      › �}t        d«      D ]ƒ  }	 t        j                  |t        d¬«      }d|_	        |j                  }t        |d«      }|j                  d«      }|r n4t        d| › d|d
z   › d�«       t	        j                  d|dz  z   «       Œ… g S |j                  d«      }g }	t!        |«      D ]±  \  }
}|j#                  d«      }|r|j                  d«      sŒ+|d   }|j                  d«      xs |j%                  d¬«      xs d}|j'                  «       }|
t)        |«      k  r||
   j%                  d¬«      nd}t+        t         |«      }|	j-                  |||f«       Œ³ |	S # t        $ r=}t        d| › d	|d
z   › d|› �«       t	        j                  d|dz  z   «       Y d}~�Œ�d}~ww xY w)z$Return [(url, title, date_str), ...]z?open=fdzdgknr&nr_page=z&nr_per_page=r   r   r   r   r   z  ERROR page z (try r   r   r   Núhtml.parserztd.zfxxgk-list-titleú  Page z empty rows (try r   ztd.zfxxgk-list-timeÚaÚhrefÚtitleT)ÚstripÚ )r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r   r,   r   ÚselectÚ	enumerateÚfindÚget_textr=   Úlenr   Úappend)Úpager0   r1   r2   r3   r4   ÚsoupÚrowsÚdatesÚitemsÚiÚtdr:   r;   r<   Údate_strÚfull_urls                    r   Úfetch_list_pagerN   I   sØ  € äˆJ”y�kÐ!8¸¸¸mÌHÈ:ÐUYÔZ]Ô^b×^gÑ^gÓ^iÓZjÐYkÐ
l€CÜ˜“8ò ˆð	Ü—<‘< ¬W¸bÔAˆDØ#ˆDŒMØ—9‘9ˆDô
 ˜T =Ó1ˆØ�{‰{Ð1Ó2ˆÙÙÜˆg�d�VÐ,¨W°Q©Y¨K°{ÐCÔDÜ�
‰
�1�w ‘{‘?Õ#ðð  ˆ	à�K‰KÐ-Ó.€Eà€EÜ˜4“ò 	2‰ˆˆ2Ø�G‰G�C‹LˆÙ˜Ÿ™˜fœØØ�‰yˆØ—‘�g“Ò> !§*¡*°4 *Ó"8Ò>¸BˆØ—‘“ˆØ45¼¸E»
²N�5˜‘8×$Ñ$¨4Ð$Ô0ÈˆÜœ8 TÓ*ˆØ�‰�h  xÐ0Õ1ð	2ð €Løô7 ò 	Ü�- ˜v V¨G°A©I¨;°c¸!¸Ð=Ô>Ü�J‰J�q˜7 Q™;‘Ô'Ýûð	ús   Á/FÆ	G$Æ'2GÇG$c                 ó>  ‡— 	 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«      }|j                  dd„ ¬«      }
|
s|j                  dd¬«      }
|
r¤dD ](  }|
j                  |«      D ]  }|j                  «        Œ Œ* |
j                  t        j                   d«      ¬«      D ](  }|j#                  g d¢«      }|sŒ|j                  «        Œ* |
j                  dd„ ¬«      }|r|d   }
t%        |
«      }nd}|s,dD ]'  Š|j                  dˆfd„¬«      }
|
sŒt%        |
«      } n |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).r   r   r   z  ERROR ú: N©NNNr8   ÚmetaÚnameÚArticleTitle)ÚattrsÚcontentr>   ÚPubDatez(\d{4}-\d{2}-\d{2})r   Údivc                 óT   — | xr% dt        | t        «      r| ndj                  | «      v S ©Núdetails-contentú ©Ú
isinstanceÚstrÚjoin©Úcs    r   ú<lambda>zfetch_detail.<locals>.<lambda>ˆ   s-   € °AÒ4yÐ:KÔU_Ð`aÔcfÔUgÑPQÐmp×muÑmuÐvwÓmxÐ:y€ r   )Úclass_r[   )Úid)	z.sk-breadcrumbztable.details-infozh1.details-titlez.share-details-rowz.sharez.details-erweimaz.related-itemzli.details-info-fontsizezli.details-change-fontsizeu   æ‰“å�°)Ústring)r:   ÚliÚspanÚbuttonc                 óT   — | xr% dt        | t        «      r| ndj                  | «      v S rZ   r]   ra   s    r   rc   zfetch_detail.<locals>.<lambda>˜   sE   € À!ò  CHÐHYÔcmÐnoÔqtÔcuÑ^_Ð{~÷  |Dñ  |Dð  EFó  |Gð  IH€ r   éÿÿÿÿ)zzfxxgk-textÚnr_rightrV   Úarticlec                 óV   •— | xr% ‰t        | t        «      r| ndj                  | «      v S )Nr\   r]   )rb   Úclss    €r   rc   zfetch_detail.<locals>.<lambda>¢   s+   ø€ ¸AÒ<sÀ#ÌzÐZ[Ô]`ÔOaÉ!Ðgj×goÑgoÐpqÓgrÐBs€ r   z  WARNING: no content for )r&   r'   r(   r)   r*   r+   r   r   rA   r=   r-   Úmatchr/   r?   Ú	decomposeÚfind_allÚcompileÚfind_parentr_   )r0   r2   r3   r4   rF   Ú
meta_titler<   rL   Ú	meta_dater5   Úcontent_divÚselÚelÚnodeÚ
inner_listÚcontent_htmlro   s                   @r   Úfetch_detailr}   o   s@  ø€ ð Ü�|‰|˜C¬¸"Ô=ˆØˆŒØ�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ð —)‘)˜EÑ*y�)Óz€KÙØ—i‘i Ð*;�iÓ<ˆÙðNò 	ˆCð "×(Ñ(¨Ó-ò �Ø—‘•ñð	ð ×&Ñ&¬b¯j©j¸Ó.CÐ&ÓDò 	!ˆBØ—>‘>Ò"?Ó@ˆDÚØ—‘Õ ð	!ð
 !×)Ñ)¨%ñ  9HÐ)ó  Iˆ
ÙØ$ R™.ˆKÜ˜;Ó'‰àˆáàDò 	ˆCØŸ)™) EÓ2s˜)ÓtˆKÚÜ" ;Ó/�Ùð		ñ ÜÐ(¨¨Ð.Ô/Ø�X˜uÐ$Ð$à˜ 5Ð(Ð(øôm ò  Üˆh�s�e˜2˜a˜SÐ!Ô"Üûð ús   ƒ/G8 Ç8	HÈHÈHc                 ó2  — i }t        t        ¬«      5 }| D �ci c]  }|j                  t        |«      |“Œ }}t	        |«      D ]  }||   }	 |j                  «       ||<   Œ 	 d d d «       |S c c}w # t        $ r}d||<   Y d }~ŒAd }~ww xY w# 1 sw Y   |S xY w)N)Úmax_workersrQ   )r   ÚMAX_WORKERSÚsubmitr}   r   Úresultr+   )ÚurlsÚresultsÚexr0   Úfut_mapÚfutr4   s          r   Úfetch_detail_batchrˆ   ®   s¤   € Ø€GÜ	¬Ô	4ð 2¸Ø@DÖE¸�2—9‘9œ\¨3Ó/°Ñ4ÐEˆÐEÜ Ó(ò 	2ˆCØ˜#‘,ˆCð2Ø"Ÿz™z›|�˜’ñ	2÷2ð €Nùò Føô
 ò 2Ø1�˜–ûð2ú÷2ð €NúsE   “B˜A,¶BÁA1ÁBÁ,BÁ1	B	Á:BÁ?BÂB	Â	BÂBc           
      óT  — ddl }| sy|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)z3items: list of (url, title, date_str, content_html)r   NzœINSERT OR REPLACE INTO gov_raw
                   (site_name, page_url, title, publish_date, content, category)
                   VALUES (?, ?, ?, ?, ?, ?)r   z  DB error for rP   )Úsqlite3ÚconnectÚDB_PATHÚcursorÚexecuteÚ	SITE_NAMEÚSOURCEr+   r   ÚcommitÚclose)
rI   rŠ   Úconnrb   Úinsertedr0   r<   rL   r|   r4   s
             r   Ú
save_to_dbr•   »   s·   € ãÙØØ�?‰?œ7Ó#€DØ�‰‹€AØ€HØ.3ò 
.Ñ*ˆˆU�H˜lð		.Ø�I‰Ið0ô ˜C ¨°,ÄÐGô	ð ˜‰M‰Hð
.ð 	‡K�K„MØ‡J�J„LØ€Oøô	 ò 	.Ü�/ #  b¨¨Ð,×-Ñ-ûð	.ús   º%BÂ	B'ÂB"Â"B'c                 óœ  — ddl }| s
t        «       S |j                  t        «      }	 dj	                  dt        | «      z  «      }|j                  d|› d�| «      j                  «       }|D �ch c]  }|d   ’Œ	 c}|j                  «        S c c}w # t        $ r t        «       cY |j                  «        S w xY w# |j                  «        w xY w)u2   è¿”å›žå·²å…¥åº“çš„ URL é›†å�ˆ (å¢žé‡�å�œæ­¢æ�¡ä»¶)r   Nú,ú?z0SELECT page_url FROM gov_raw WHERE page_url IN (ú))
rŠ   Úsetr‹   rŒ   r`   rC   rŽ   Úfetchallr’   r+   )rƒ   rŠ   r“   ÚphrG   Úrs         r   Úcheck_existingrž   Ó   s­   € ãÙÜ‹uˆØ�?‰?œ7Ó#€Dð	Ø�X‰X�cœC ›I‘oÓ&ˆØ�|‰|Ø>¸r¸dÀ!ÐDÀdó
ç
‰(‹*ð 	ð #Ö#˜��!“Ò#ð 	�
‰
�ùò	 $øÜò Ü‹u‰à�
‰
�ðûð 	�
‰
�ús6   §AB Á,BÁ8B ÂB ÂB6Â#B9 Â5B6Â6B9 Â9Cc                  óÎ  — t        t        j                  «      dkD  xr t        j                  d   dk(  } t        j                  «       t        d¬«      z
  j                  d«      }t        d|› �«       t        «       }|dk(  rt        d«       y |t        z   dz
  t        z  }t        d	|› d
|› dt        › d�«       g }| r|}nt        |t        «      }t        d|dz   «      D �]  }t        |«      }|st        d|› d�«        nð|D ��	�
cg c]  \  }}	}
|
sŒ
|
|k\  sŒ||	|
f‘Œ }}	}}
|j                  |«       | rxt        |D ��cg c]  \  }}}|‘Œ
 c}}«      }|D ��	�
cg c]  \  }}	}
||vsŒ||	|
f‘Œ }}	}}
|st        d|› d�«        nit        d|› dt        |«      › dt        |«      › �«       ŒÐ|r|st        d|› d|› d�«        n*|dz  dk(  sŒñt        d|› d|› dt        |«      › d�«       �Œ |st        d«       y t        dt        |«      › �«       g }t         dz  }t        dt        |«      |«      D ]�  }||||z    }|D ��cg c]  \  }}}|‘Œ
 }}}t        d|dz   › d|t        |«      z   › dt        |«      › d�«       t#        |«      }|D ]A  \  }}}|j%                  |d«      \  }}}|xs |}|xs |}|j'                  ||||xs df«       ŒC ŒŸ t)        |«      }t        d d!› �«       t        d"t        |«      › d#|› d$�«       |r9t+        |D �cg c]  }|d%   sŒ	|d%   ‘Œ c}«      }t        d&|d   › d'|d(   › �«       	 dd l} | j/                  t0        «      }!|!j3                  d)t4        f«       |!j7                  «        |!j9                  «        t        d*«       y c c}
}	}w c c}}w c c}
}	}w c c}}w c c}w # t:        $ r}"t        d+|"› �«       Y d }"~"y d }"~"ww xY w),Nr   Ú1iG  )Údaysz%Y-%m-%dz3-year cutoff: r   z+ERROR: could not detect total article countzTotal: z articles, z pages (z/page)zPage z: no data, stoppingz: all already in DB, stoppingr9   rP   z new, cumulative z: all before cutoff (z), stoppingr   ú/z articles so farzNo articles after date filterzTotal filtered: é   z  Details [ú-z]...rQ   r>   ú
z2==================================================zDone. Total: z articles (saved: r™   r   zDate range: z ~ rk   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 index rebuiltzFTS rebuild note: )rC   ÚsysÚargvr   Únowr   Ústrftimer   r6   r"   ÚminÚ	MAX_PAGESr%   rN   Úextendrž   r€   rˆ   r'   rD   r•   ÚsortedrŠ   r‹   rŒ   rŽ   r�   r‘   r’   r+   )#ÚincrementalÚthree_years_agoÚtotal_countÚtotal_pagesÚall_articlesÚ	max_pagesrE   rI   ÚuÚtÚdÚfilteredÚ_ÚexistingÚnew_onesr„   Ú
batch_sizeÚbatch_startÚbatchÚ
batch_urlsÚ
detail_mapr0   r<   rL   r|   Údetail_dateÚdetail_titleÚfinal_titleÚ
final_dateÚsavedr�   rH   rŠ   r“   r4   s#                                      r   ÚmainrÅ   å   s*  € Ü”c—h‘h“- !Ñ#Ò:¬¯©°©°sÑ(:€KÜ—|‘|“~¬	°wÔ(?Ñ?×IÑIÈ*ÓU€OÜˆ/˜/Ð*Ð+Ô,ô $Ó%€KØ�aÒÜÐ9Ô:ØØ¤Ñ)¨AÑ-´(Ñ:€KÜˆ'�+�˜k¨+¨°h¼x¸jÈÐOÔPà€LÙØ‰	ä˜¤YÓ/ˆ	ä�a˜ Q™Ó'ó SˆÜ Ó%ˆÙÜ�%˜�vÐ0Ð1Ô2Ùð .3×QÐQ¡' ! Q¨²a¸AÀÓ<P�Q˜˜1’IÐQˆÒQØ×Ñ˜HÔ%áä%¸×&A©W¨Q°°1¢qÓ&AÓBˆHØ19×OÐO¡g a¨¨A¸QÀhÒ=N˜˜A˜qš	ÐOˆHÒOÙÜ�e˜D˜6Ð!>Ð?Ô@ÙÜ�'˜$˜˜r¤# h£- Ð0AÄ#ÀlÓBSÐATÐUÔVØñ ™Ü�%˜�vÐ2°?Ð2CÀ;ÐOÔPÙà�"‰9˜‹>Ü�'˜$˜˜q  ¨2¬c°,Ó.?Ð-@Ð@PÐQÖRð5Sñ8 ÜÐ+Ô,ØäÐ
œ3˜|Ó,Ð-Ð.Ô/ð €GÜ˜q‘€JÜ˜Q¤ LÓ 1°:Ó>ò 	OˆØ˜[¨°zÑ)AÐBˆØ',×-™G˜A˜q !’aÐ-ˆ
Ñ-Üˆk˜+ a™-˜¨¨+´c¸%³jÑ*@Ð)AÀÄ3À|ÓCTÐBUÐUYÐZÔ[Ü'¨
Ó3ˆ
Ø$)ò 	OÑ ˆC�˜Ø6@·n±nÀSÐJ\Ó6]Ñ3ˆL˜+ |Ø&Ò/¨%ˆKØ$Ò0¨ˆJØ�N‰N˜C ¨j¸,Ò:LÈ"ÐMÕNñ		Oð	Oô �wÓ€Eäˆ"ˆXˆJˆÔÜˆ-œ˜G›�~Ð%7¸°w¸aÐ@ÔAÙÜ gÖ6 °°1³˜˜!›Ò6Ó7ˆÜˆl˜5 ™8˜* C¨¨b©	 {Ð3Ô4ð&ÛØ�‰œwÓ'ˆØ�‰ð ô
 ˆYô	ð 	�‰ŒØ�
‰
ŒÜÐÕ ùô} Rùó
 'BùÜOùó4 .ùò 7øô  ò &ÜÐ   Ð$×%Ñ%ûð&úsO   ÄN$
ÄN$
ÄN$
ÅN+ÅN1
Å+N1
ÉN8Ì
N>Ì"N>ÍAO Ï	O$ÏOÏO$Ú__main__)#Ú__doc__Úosr-   r¦   r$   r&   Úbs4r   Úurllib.parser   r   r   Úconcurrent.futuresr   r   Úenvironr'   rŒ   r    r!   r�   r�   r"   r(   r€   r«   r   r6   rN   r}   rˆ   r•   rž   rÅ   Ú__name__© r   r   ú<module>rÏ      sÅ   ðñó  
Û 	Û 
Û Û Ý Ý  ß (ß ?ð �*‰*�.‰.˜ b§j¡j§n¡n°]ÐDUÓ&VÓ
W€ð *€ØD€	Ø/€	Ø	*€Ø€ð ð 3ð€ð €Ø€	ò"òò(#òL<)ò~
òò0ò$Z&ðz ˆzÒÙ…Fð r   