From 6655e0cc2934c281d0c5875637bff08bd742ee17 Mon Sep 17 00:00:00 2001 From: HuangHai <10402852@qq.com> Date: Sun, 18 Jan 2026 18:59:17 +0800 Subject: [PATCH] 'commit' --- Apps/AiTeJiYiChong/Crawler.py | 6 +- Apps/AiTeJiYiChong/Kit.py | 7 ++ .../__pycache__/Crawler.cpython-310.pyc | Bin 13411 -> 13447 bytes .../__pycache__/Kit.cpython-310.pyc | Bin 12709 -> 12917 bytes Apps/TeLaiDian/Crawler.py | 10 +- Apps/TeLaiDian/Kit.py | 7 ++ .../__pycache__/Crawler.cpython-310.pyc | Bin 17900 -> 17979 bytes .../TelaiDian/__pycache__/Kit.cpython-310.pyc | Bin 7633 -> 7843 bytes Apps/YeLiTe/Config/Setting.py | 2 +- .../__pycache__/Setting.cpython-310.pyc | Bin 762 -> 762 bytes Apps/YeLiTe/Crawler.py | 118 +++++++++++------- Apps/YeLiTe/Kit.py | 7 ++ Apps/YeLiTe/ReadImageKit.py | 22 ++++ Apps/YeLiTe/Service.py | 70 ++++++++++- .../__pycache__/Crawler.cpython-310.pyc | Bin 10441 -> 10682 bytes Apps/YeLiTe/__pycache__/Kit.cpython-310.pyc | Bin 9876 -> 10103 bytes .../__pycache__/ReadImageKit.cpython-310.pyc | Bin 6904 -> 7840 bytes .../__pycache__/Service.cpython-310.pyc | Bin 6521 -> 7252 bytes Config/Config.py | 8 +- Config/__pycache__/Config.cpython-310.pyc | Bin 1366 -> 1365 bytes ...{T6_ClearHistory.py => T5_ClearHistory.py} | 6 +- Tools/T5_KillRabbitAd.py | 5 - Tools/{T7_Export.py => T6_Export.py} | 0 ...tInputIME.py => T7_InstallFastInputIME.py} | 0 ...tBlueRect.py => T8_DebugRabbitBlueRect.py} | 0 .../T6_ClearHistory.cpython-310.pyc | Bin 0 -> 6110 bytes 26 files changed, 199 insertions(+), 69 deletions(-) rename Tools/{T6_ClearHistory.py => T5_ClearHistory.py} (98%) delete mode 100644 Tools/T5_KillRabbitAd.py rename Tools/{T7_Export.py => T6_Export.py} (100%) rename Tools/{T8_InstallFastInputIME.py => T7_InstallFastInputIME.py} (100%) rename Tools/{T9_DebugRabbitBlueRect.py => T8_DebugRabbitBlueRect.py} (100%) create mode 100644 Tools/__pycache__/T6_ClearHistory.cpython-310.pyc diff --git a/Apps/AiTeJiYiChong/Crawler.py b/Apps/AiTeJiYiChong/Crawler.py index ec12984..68abe1d 100644 --- a/Apps/AiTeJiYiChong/Crawler.py +++ b/Apps/AiTeJiYiChong/Crawler.py @@ -15,7 +15,7 @@ if project_root not in sys.path: import uiautomator2 as u2 from Apps.AiTeJiYiChong import Kit -from Apps.AiTeJiYiChong.Kit import take_screenshot, setup_logger +from Apps.AiTeJiYiChong.Kit import take_screenshot, setup_logger, get_name_md5 from Apps.AiTeJiYiChong.ReadImageKit import ReadImageKit from Apps.AiTeJiYiChong.FirstPageKit import run_ocr_rect from Util.RedisKit import RedisKit @@ -177,7 +177,7 @@ async def get_station_list(d, service, max_stations_count=MAX_STATIONS_COUNT): should_back_to_list = True - detail_uuid = f"detail_{station_name}_{image_uuid}" + detail_uuid = f"detail_{get_name_md5(station_name)}_{image_uuid}" detail_path = take_screenshot(d, detail_uuid, save_dir=TEMP_IMAGE_DIR) logger.info(f"已启动后台分析详情页: {station_name}") @@ -268,7 +268,7 @@ async def get_station_list(d, service, max_stations_count=MAX_STATIONS_COUNT): logger.info("正在从顶部开始向下逐页截图...") max_scroll_down_pages = 10 for p_idx in range(1, max_scroll_down_pages + 1): - p_shot = take_screenshot(d, f"price_scroll_{p_idx}_{station_name}", save_dir=TEMP_IMAGE_DIR) + p_shot = take_screenshot(d, f"price_scroll_{p_idx}_{get_name_md5(station_name)}", save_dir=TEMP_IMAGE_DIR) before_dn_md5 = Kit.get_image_content_md5(p_shot) d.swipe_ext("up", scale=0.8) diff --git a/Apps/AiTeJiYiChong/Kit.py b/Apps/AiTeJiYiChong/Kit.py index 9b5e32d..5bba216 100644 --- a/Apps/AiTeJiYiChong/Kit.py +++ b/Apps/AiTeJiYiChong/Kit.py @@ -35,6 +35,13 @@ def get_file_md5(file_path): hash_md5.update(chunk) return hash_md5.hexdigest() +def get_name_md5(name): + if not name: + return "unknown" + if not isinstance(name, str): + name = str(name) + return hashlib.md5(name.encode("utf-8")).hexdigest() + def get_image_content_md5(file_path, top_ratio=0.1, bottom_ratio=0.1): """ diff --git a/Apps/AiTeJiYiChong/__pycache__/Crawler.cpython-310.pyc b/Apps/AiTeJiYiChong/__pycache__/Crawler.cpython-310.pyc index 2c10ea2931ad8be02a514eac63e5c96d22b0eb3e..b4d835b055707360b62ebdb69642f9c6ba351899 100644 GIT binary patch delta 2653 zcmY*bU2Gf25xzbCO8k=|SrYX_$`WOZqJAh+vMoEdtk{-g#Yt+{iEF0G`OG~@Cy{r| zawSX75^gOA?u!AX+rGqbLOsN;jo1jlhZb%6(f~n#qA3FRp|})5fEMUW(TAdbD9{$& zSxSj22(z=_%+Ait&dl-8i?__M9SSun;_s7>3+CX3cf#EWzmvLuy4aR$Lkd=~x6oef z$aP5GSBMrnbDfg+7rKhwxo*if6ncuWTukzfg?OT)7fUpBOIo*0HzUbLwbEE{yCq!sLi1%o)j1%qmqUNp2Ko~%7V_f*u%uepzeIz*g~ zYuQ+TppY2)1g2AB|I}pAQGR z8WJ?T6sZo-ef&Ft`1KaKYhwGi(56bhV#?C~>LBbYDV73+CRqv}*-!=l6P8*U+F2_@ z)--KrDVmb9kMR+fT2+Mf0q93}aYAzl`?saP!q4t-LeJ0t9_Sf(LOWS%1L0oby-J=4 z97PpD)u=MBR)!ed`4vwG_oV#PRaNn^Erb+0yfnfR%!j9Mt7jD4_`FgXX2VrCJ}x40 z5kD^lljs(IH<(3}{PSQwdJAVN$pxj7mNw3S4LnyFr=xr>l=6(>v-m~+Qn-u%G_>#f z77bUMSytWy*=k~w(&{6L3mz$Kf*n{^#ZAAK_Rg`)9R=^Z>jD{4EFpPwUP{hy-*k|U zVwD}lYP+(bo>X3cwQ`91nS#H|4vCW!^>@0X+;!6iejwa}#`s+L6bkXpa1ZL^kHb;) zJN{WX-qTOhKT=o+OK*s~Do2^W+Qp7akCf^-cSp{hDoHP8me@3F5?;DVMf&o(^yP4+ z&uV1H*`So%l9D$-a#68jZiTjNy4UaVcOz5Rf6jzW{2It;yxNOj*+TVPi`?n7v6^8W zTS)k z%5&^Fk(u_&33j4-U`q*$!%xNGR=fZJzueRw_zP>rNI32x5q_g7iMsiRO;eW+b||gF zfT~tzE2l*fA7UrjDK^Va!I(TrE6tW7{&4s-upk9Yl9~RePcP3lu*>VAMK+tEPqR zt6JH-W{^&>0)CM!KN9OgL4GmT>wN}*7LJD6n@I!kCxM&-(#}7K^+me`>v;82$*{2F zF585X{UDv}0*eKn8g? zn#)dWQC|bVE)+B|qp2Hi>5 z+Ox~7NT#Kg^aZ2rcuJay*Boz2lOKlAwsmYt%c1{7K(@ItM}f#P}yv zTiapQMV(k!?B%jvf6V70;5aw?KNDY+OyVsR09$>Or2BdPIGqw@?WFtWWSzeS z^7}v@0QngZaMlS>o9YEEZ?9OCJOua=kPm@;ABc>m{sw$@{I7{$3efRuT2VJGO-rgT zT}Wn$37`*trI^+Nxy;XH1}BRW)321FB8dgNV2RjEA{>p_HkIjjU<|ELyQou}WXMPS zapo8gWjn*?4IQ6>mwUma;)5H>4n$#GIH6alSr|QUV6zMo7&|%sVzxUfGZ;EyTl40^ zXni3;DZP>H=MS?ZN97y$3aCC%WZqU_yAzW9Wu-YTvSRHDdpq{XL|U}Q@rnNb0n=ac AxBvhE delta 2701 zcmZ8jU2Gf25xzbCN+c!HqJF3!QvVjoNTNi^lI&Qn;r}>I;aIMdOWo6ndy-Bf@2I^~ zB&Ej&DAhI(Nh4^oA>(QWcdU!#XR1({P{-*m$|8~e5+$mi zqB|mLp>Mj6h1yx@j%!`rxhs$!`e%0zCFrc@uQOeM2Te<{G((qlrJzc|TwYal74wzT zKvb-mGP5K-Ot(hj^qhAB4bdHM5Bh}u(7TH+(r({((eLSjkD>?ki2vo5zm(eSpe?R@ z_7HI+Vb7)Cs~-3lMbYk{{=nQ&zdd9R+8t$aAC-n}f2GSF-bYBVn%0^t1Dp<8Lv%Ti zcs;^bVf*kt+7rpgwy-u_ISi{(+D-#vjo4{?tSmDA9Xq|2eDo}(^b=OQowib3_A7kM zPQNNJ=?9=6dxB${DeSLHKg7>I;+USFx`RE<_pMGlT}HT<jVPkDGd~#<}mS+;;f33-&;Q&i3B;1DCu6{_xAJPMI=doOIj6BTrQN zt?@SmyMy7(s&t&6^>H4(P|47E^QAL+o)NE^eZmg2jND|0d%ebUIa=!18||;yBV1DE zl5c|Ks-VZ+g4MF;-Z`MZXr5E5HuH&Jsqfs2uk51>0&YCdV#Nx}al-D{XVKjjODApD z+N6CFFIicfd&~7m%bH?)|B3H_!3)a~ZG3JAcqhBb1NuU^D?7a}Fs*+xtteixPgU6Z zaS!;}nVka5J@>{#JBksD*+T;KRyc_|=KR45}+ES)W#W7VFa;Ye$2_RC25 z+z94L+s`a9osY!O9DONr6FJq-BA=m|aW;raH$gCu|3`)yb{9FW71c^22boU|Z6bQY z+YLqoRUBOq(E$ChZ5TQ9VcYR^E5jX+N{B&{E(aCK5dcJWn|bq@DtT4QsrBKno^NkJ z%}#JrQ{v5bSPC!?yW z-S^S4qoe`$3v6jRHnwC_drc)V@B(p>Nszfri#YDhO$|F9pi{&HvH;zP_j)719-_Ue z_6YFE5`?wK+|r6F3DbWjQeL=QiA;NXcUg@O zdXq?^f9(Bw08Wn#0GXkqeM1br-1qQxDN-b?#Il(qs;Zl-hGk08g0c;Ok?ZRrWGj}VhDS3*r zhPNeeQHEfoP~AP&Wv~k6R@L0P%vRhj{a62L<`tHcIHG#mnCq*K$hve2-Kz9*23j+Qsiqm%w ze`l08m`ENQ)%Bmyt0{xoH|Xh+^^rZszUIkfj%G4sg7Ha2QjeW}sXRp=j692`X*9Wm zF3}$(lc%Ar7m_W6H%1p5F}ZeTShW-_FE10LAZrCyy;?NO;1u$3T#CL!R$-~p|0EM$ z-qbPHt%H}^0EIqH`p5;~p);facf)IIN{tGfF?5GXPBN+EtuM-;&jY>=TpY+2eK++r zv{n5y^~ zAin|RCXgQifh?qeWmrmH&KaA!MQ#E7K9Ki-Tm!<>P z-kY3faYwR!G?J2uNJHN;l6a%}Yjl4Zw5HuWd6t*4xw%CJ$vQv?44+-Ue_ diff --git a/Apps/AiTeJiYiChong/__pycache__/Kit.cpython-310.pyc b/Apps/AiTeJiYiChong/__pycache__/Kit.cpython-310.pyc index a280111c4dc2fd8202e42ae0a6822c207b0581b0..83cabaad7c5258a44ee700f0822c217f9465e8b5 100644 GIT binary patch delta 2941 zcmZ`*U2Gf25$2Ld@S7}Hqs&~3M2~zg@M3U{t7$&0m3wKTeo#lv;|VMPkmbCp)WAuG5d15pZw+J@vCbI+Ic;+w4Dyo z6ir_zOWm}KW`NT}x6y~-on@V6LbuayknK=(56uF-lMd4y?FA}FM`%CY1ynEVrC+#4 zmNIlN-AxC8(?>_?9y$nAKP69v3}XXbm^X;b9a~sjT$pPOkmDqIn@G(u>+E)jr-d6n zOETiO;lE|lpbH{W=1B1_@nPhpT~e=_UbR%GUzAa++H{r!;r2j-Yg223Kw1P~^FcZa z|KsrYiU3zao`(MTK>6fa*h~53O6VGSF64)AMXrQyX*9e}*2%5tdI-FZ%*!}T#bm_uIqwC-ye|}*3CS39ESECA8(B#N6+jRLe9B~n`6Y}P z;}`*shqcj&MiN9P-Gm#hH?>(ZwrMjY}3JM;S6L?BjQF!7nu`xI!^Z%fV~Jy zO=qjN=a<}NBl=&bL@qHzq&S?&9#Fxz+3)hrWmfVm&Y0s>UEjhh5~7XpB7&m z>2BRj?pguZu&ms zGHg|4xLj>trAd$Z%?28-Fn&i2WKWQrt!nmNvW68?_24E_=MjQh0A-}w*V0xARIWKg zb=62^q$Uxt%)E+V0~ilU-L6+k4b!jkW#rZou&KBc3ROegMY4h5BQz0K5H2FDB3wea zjPNYN6@=#yt|GM8v1~h3El(^Uq|fEl`;#EK1LXDAq1SFTl)ORTY6jOmGUc~{0X=h>W6BJzmB{ys5VSgf=GzjmQLOS zf*Yc>_tnB@Z5v@3_NL&!FBq}q%{!ak^cVThKkLN*^XdCI=VsoAriqhOZ+l;Wqt7)5lF=DL9HKJKwAX{dE9GqW>~d^;Tqu2ivjfIIJe)a8;{1!2xt5sAkHF67=O5N(v~GIKQ&RjOpC_y0qx=+kO{5Fi;!kkw zJ%pbk{0v|z!B$PnFJV@B3%S@qGR#(`I8}HgCzG~U@>s)!zJVO+9;?*hQs7B(voH+v z{i<*gaJo24PKpVO-qa tB!C{$NnVFbTJTGfB*}!~(iYKEdLp6gJM>I4os1{8B_{NPiAZ|Se*iHEx~l*H delta 2733 zcmZuzYit}>751HdjmNudJMn8Br)lE#W9+OQV;X|;a36A-hQ>)1r%k7nVKVowcjDch z?U~ucF{P#=5~>QV(%Xkrsj5mEN_e!ThW?>{_=SX!kbqzF0~JvP`A5Z%f`kwP&bbqB zT#H@pH|L&n?s?pE&zb!Pzv1TnT+V32&);uVyuUnnEkDFQzBc*H+CJXFvsan5ljnH; zYMa%=J9!sAdqqc?@ov5YWqpd?$$OCQ=fk|84f$4OH@^!x zgM5_V&G#a;i?g$B=GX?gUNBiyxc~Ix;^|ZN+53*q+wy(JCuvter7U*Y)n3!*~4aKHS?d2 zJ~Gu$Fd&=y9%jl{^ocQIL`m+14(unAi8z$l2x*TZ9Fw>7;WSaMCZEa-$g%b}(?ybw z$ltaPuHA#=!f~@5T23N8XjHvWtb|~a-ULFF4*jxM6>yk1M+lB0n8`RSnt+qEPS83PRE223L8A4lR}UJFD^zWxG>E`k6)-NJ?fNo1A%EHR2(x6a zyEd}zNPFC>=Pt)ZRH;;*P=xZ$?o%vS|FrvP0=G@}mL}*#A&Ky>R5L7>4q^Z3qVD?K zt1khSz$|PQ^;^AA!1aWbYGIQH+QmZEF@WCQ=)l*Lp zHBLZx6P_ga8iKha(!JV}-EhJRe4V%#2&lin#YSxdPNX2H5O@R^36=?}1T}&>fltsN zc!~fBwiH&rUnsCY$=?*d#9mt02H!B!D!-zh?)QYZOYaF{OpB??~kyaizQ}7mPXt096D^UX6%LEm8TNxrC6Yvhg zcd%OULpf&-Ninu>x@81zwsc!Q)rRMB!)F+C+YpvpemHi0SPf57!mydM^*qT0H)C?Q zZ=#rfMw>p6!xIxHRRwX0<&8HIt%?U9A+bW(fmop708WB% z!$`h1arc0gurF0tQ&SfMzYbHV0wF-H3?Qo zvPy8LEe^^{lOM5hIlF&6eVIh}N@xGUwFijYg%BmlF}?_!wTAgPTtk*+_|34aTxbv{zwziw<_<&DzJ{P)N@&Lz(#QIu}@UOf!pM`ZEG1V178DQOvE#c@NM zjuXC5-0KLDCRQxDYwC;W;>=V(Vr6Os@r9|&i0SDQ?0$KA`rv6R6OZMUP2vjdBpd1` zB;f|pKOp!8!G{ENi=ti^@ZX2)01xak__cVhx2^wi`W##QH)@y~>?3Ugq!)=+ovPt~ z1-3~pnnUmn5~BRd^Tfr8`JtBBaz?tKfI}Sx&QzG diff --git a/Apps/TeLaiDian/Crawler.py b/Apps/TeLaiDian/Crawler.py index 028f37e..8bf0fd5 100644 --- a/Apps/TeLaiDian/Crawler.py +++ b/Apps/TeLaiDian/Crawler.py @@ -7,7 +7,7 @@ import json import cv2 from Apps.TeLaiDian.Kit import ( take_screenshot, get_image_content_md5, clean_station_name, - setup_logger, read_image, save_image, detect_warm_popup_xczs_cv + setup_logger, read_image, save_image, detect_warm_popup_xczs_cv, get_name_md5 ) from Apps.TeLaiDian.ReadImageKit import ReadImageKit from Apps.TeLaiDian.FirstPageKit import run_ocr_rect @@ -208,6 +208,8 @@ class TeLaiDianCrawler(BaseCrawler): remaining = max_to_crawl - current_idx logger.info(f"--- [进度: {current_idx}/{max_to_crawl}, 剩余: {remaining}] 处理场站: {name} (坐标: {point}, 距离: {distance}) ---") + file_tag = get_name_md5(name) + # 组装基础场站信息,便于详情页逻辑使用 station_info = { "name": name, @@ -223,7 +225,7 @@ class TeLaiDianCrawler(BaseCrawler): await asyncio.sleep(WAIT_DETAIL_PAGE_LOAD) # 截图验证是否进入详情页 - detail_check_path = take_screenshot(d, f"tld_detail_check_{int(time.time())}.jpg") + detail_check_path = take_screenshot(d, f"tld_detail_check_{file_tag}_{int(time.time())}.jpg") logger.info(f"详情页快照已保存: {detail_check_path}") # 简单验证:如果标题包含 "我的卡券"、"优惠券"、"新人福利" 等,说明点错了 @@ -300,7 +302,7 @@ class TeLaiDianCrawler(BaseCrawler): """ 在详情页提取价格和状态信息 """ - first_screen_path = take_screenshot(d, f"tld_detail_basic_{int(time.time())}.jpg") + first_screen_path = take_screenshot(d, f"tld_detail_basic_{get_name_md5(station_name)}_{int(time.time())}.jpg") station_name = station_info.get("name") address = station_info.get("address") distance = station_info.get("distance") @@ -456,7 +458,7 @@ class TeLaiDianCrawler(BaseCrawler): max_scroll_down_pages = 8 for p_idx in range(1, max_scroll_down_pages + 1): # 截图当前页 - p_shot = take_screenshot(d, f"tld_detail_price_{int(time.time())}_{p_idx}.jpg") + p_shot = take_screenshot(d, f"tld_detail_price_{get_name_md5(station_name)}_{int(time.time())}_{p_idx}.jpg") # 检查是否还能向下滚动 before_dn_md5 = get_image_content_md5(p_shot) diff --git a/Apps/TeLaiDian/Kit.py b/Apps/TeLaiDian/Kit.py index 6391334..48b91c8 100644 --- a/Apps/TeLaiDian/Kit.py +++ b/Apps/TeLaiDian/Kit.py @@ -48,6 +48,13 @@ def get_file_md5(file_path): for chunk in iter(lambda: f.read(4096), b""): hash_md5.update(chunk) return hash_md5.hexdigest() + +def get_name_md5(name): + if not name: + return "unknown" + if not isinstance(name, str): + name = str(name) + return hashlib.md5(name.encode("utf-8")).hexdigest() def get_image_content_md5(file_path, top_ratio=0.1, bottom_ratio=0.1): """ diff --git a/Apps/TelaiDian/__pycache__/Crawler.cpython-310.pyc b/Apps/TelaiDian/__pycache__/Crawler.cpython-310.pyc index e2fbda16b09624390ab0e86f4e64f6496f0bd535..db48c2533c8c980097220f500cf953637d797fba 100644 GIT binary patch delta 5386 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 Vd_LAf)`^NeEsm(uT28EA{SR@TLT~^8 diff --git a/Apps/TelaiDian/__pycache__/Kit.cpython-310.pyc b/Apps/TelaiDian/__pycache__/Kit.cpython-310.pyc index b58806f3e55da4d1abcec4562edd634e31a2452c..c2197897574f254eb4589cf319e16fb0d77b9149 100644 GIT binary patch delta 1449 zcmZXU&2Jk;6u@_O{jpwuHg;ntaT2#ln{G=|L!hK;k|L2NG*J^I!U4C!b$2$#$=Yk) zZjw4p36P2lLZTfB4hTquK%zoI!9DcQ8xlg|1nL3psZuFw{sk`Zo)fAHcD28G^FC(Z z%)FUj&wMo&wWCo@!sqLIR^{Q%Xg9la^ThZ@j{CU(1}kVhz=JoWLYS*Ogl&W$;$a>^ zOO!`>3^g$x=Lu}%{4j6hNwg$*j;HuRln!u-w_9!1WFg5Up5__!OYsigiS0q&#k1J9 z^FH3gd(k`1*=v&Czl+K2JUB12f;g@K%QQb%zF@3NjQUS)44}yqQ6aa@#KwkbPNm#s^i?7HO2Tgtk$<>T@;+h$w-Z3+LT%zDA)+EUG4t^MU+b{7Um z^nj;ToJ!4cOEtsv6vqYV#epFwNmG&+Fl&a*P3T9J&LBXR;1j4Qd6BZ|7Hg%dS*-FG zo=1&C3+!V)rZJVJ7z{QYf0P~ncT~v>y7rZZYdU+QhTsSd6LRf(5lU{w_QdT#H!jD| zfm7^^_&deL)DdFF=wZi=JRc+*iLG&tn%Ni21eTIRG1S zPHCl5E9WZJQrXPGSv1W~>LG}cV;teBPTi`w=2aIa#7?OF&?H%=2(KV?U&{+xi74bX zEgpw@*hLZ4df8laKwFb1UPZ@U1u?tpqd?j-Xr*$JB+6$kSX{A&7VG6*>cKcdSAYWd zAs$8YlQbL8XV~?Ir&wkUCa50*)4;7NTP6%sKL}>sDj6osQ7>Rrz(CVeX^V@|#W*Eg zP_L96vskH?3*vrsh)oM6*2l_XAU4A;HJw<5v9sdc_}I~>f-y|@LpwGQCS(b;T{!WF z@x$zv2qbiNS>zKJSV_Fsoe`fT;?Zx=!I2Rf1Ecvv;upqFig(&RX7@xqc{fb+g69Z^ z_$`@F)Bp4^yg?dD6h;WAMMo+ho+hzXaAh%{I>x>g*Hgo+(cDRW#?rK&%d~=j-2L#+ z@3tR(@X_P%@4%uk+VdMr6lf8ugc?E*wn}CH*QB)xZxevfN+j~XM9|~~m(0eh4IEr@ zTqdj#-Xg3Lt`eT4E85aW*iT|4JD41=X_4#f6Gx7DPw(e1Zn_LJKxjORj4|K|r>jJrJK}r#1wIa)d4eT?H-R37?(U zWvuGVURA$O7CL&KzqVYhH{c~wP$|JCY1QK1*)8r>d58=d0^L0@NEjuwHjQcwE)gzE zIE6y|b+=*-ohvzwIRj=YE?gm-L1+-J5d_x7(PxgKsN#K~%0x|8Wi6s6RZR=3ZE8%5 OXeS~ER0ZGeSm!@YI!5^b delta 1250 zcmZXS%WoTH5WqcaJG)-nYbTEFq_NYak0_g$OpBrhl*mCQD2-}_T2#q}Y&QPZ#=(xw zc$4595)KiU3Pk&f6B4DM-YW5Mk$OPl4}b%R6DuSRl!)9o^a^4ojd+Otq~E+}zsGzs z|NXPkW;Ck%=zCD9*QRbovvB{`gjEJ+p%g5yXst{a63g% zlsE)vrJx54q5;}l%AdI0eXQ>)h0Bz2oae?g+I%U`1tkxZzVOvF~RkzCyF0<8Bu3?!%c`{B; zD#wkD7@x7Et=nxrO4XBhjTtD&?~JpsCLbFsaJ`$4MSw2rN_>9oU&T~r1~JXu!i+3~ z-w6xyv-lafDSwEYa6|qPzXGqwmxc#2M%8hxW*IGXY~kP?%55tI9dNa~-}?=~gj`9y z2Vcsc5)Z?CM4V=<$~*nJbe>c*j91yid&Z|27vy1oF8t5ytjp2lID9NGCoh8A-AjG| zX};PmzRX7tZyw&i`|I29{PyVsbYw1_+plnsD&sXqjbN(B<8tzA_HHohj0Pi5FeCrl z2zfpAb*Hn_M1f6CY%$(olo`lqGydML{5gFdzLvp(i?H3D8<_XgOz#X$(`DZqnp1a! zTW)3glKf@pqi~7q@{ERjH?tD 0: + total_piles = total_sum + free_piles = free_sum + piles_detail = piles + try: - total_piles = None - free_piles = None - if isinstance(piles, list): - total_sum = 0 - free_sum = 0 - for p in piles: - if not isinstance(p, dict): - continue - t = p.get("total") - f = p.get("idle") - try: - if t is not None: - total_sum += int(t) - except Exception: - pass - try: - if f is not None: - free_sum += int(f) - except Exception: - pass - if total_sum > 0: - total_piles = total_sum - free_piles = free_sum - await self.service.save_station_profile_and_status( - station_name=name, - address=None, - total_piles=total_piles, - free_piles=free_piles, - piles_detail=None, - parking_info=None, - distance=distance - ) + basic_info = await self.read_image_kit.analyze_detail_basic_info(detail_shot) + if isinstance(basic_info, dict): + addr = basic_info.get("address") + if addr: + address_detail = addr + park = basic_info.get("parking_info") + if park: + parking_info = park except Exception as e: - logger.warning(f"兜底写入场站基础信息失败: {name}, {e}") - + logger.warning(f"详情页基础信息识别失败: {e}") # --- 新增:点击“阶段性电价”按钮以获取完整电价列表 --- # 使用 OCR 探测价格入口 dqdf_pos = detect_price_info_container_cv(detail_shot) @@ -230,7 +234,7 @@ class YeLiTeCrawler(BaseCrawler): logger.info("正在从顶部开始向下逐页截图...") max_scroll_down_pages = 10 for p_idx in range(1, max_scroll_down_pages + 1): - p_shot = take_screenshot(d, f"detail_price_{clean_station_name(name)}_{int(time.time())}_{p_idx}") + p_shot = take_screenshot(d, f"detail_price_{file_tag}_{int(time.time())}_{p_idx}") before_dn_md5 = get_image_content_md5(p_shot) d.swipe(scroll_x, scroll_bottom_y, scroll_x, scroll_top_y, 0.2) @@ -256,7 +260,18 @@ class YeLiTeCrawler(BaseCrawler): # -------------------------------------------------- # 启动后台任务处理详情页 - task = asyncio.create_task(self.analyze_detail_background(name, detail_shots, distance=distance)) + task = asyncio.create_task( + self.analyze_detail_background( + name, + detail_shots, + address=address_detail, + distance=distance, + total_piles=total_piles, + free_piles=free_piles, + piles_detail=piles_detail, + parking_info=parking_info, + ) + ) background_tasks.append(task) processed_count += 1 @@ -305,7 +320,17 @@ class YeLiTeCrawler(BaseCrawler): return processed_count - async def analyze_detail_background(self, station_name, image_paths, address=None, distance=None): + async def analyze_detail_background( + self, + station_name, + image_paths, + address=None, + distance=None, + total_piles=None, + free_piles=None, + piles_detail=None, + parking_info=None, + ): """ 后台异步分析详情页 (支持多张截图合并) """ @@ -341,7 +366,16 @@ class YeLiTeCrawler(BaseCrawler): unique_prices.sort(key=lambda x: x.get('start', '00:00')) if unique_prices: - await self.service.process_price_detail_data(station_name, unique_prices, address=address, distance=distance) + await self.service.process_price_detail_data( + station_name, + unique_prices, + address=address, + distance=distance, + total_piles=total_piles, + free_piles=free_piles, + piles_detail=piles_detail, + parking_info=parking_info, + ) logger.info(f"场站 {station_name} 价格分析完成并入库 (记录数: {len(unique_prices)}, 地址: {address}, 距离: {distance})") else: logger.warning(f"场站 {station_name} 未识别到价格信息") diff --git a/Apps/YeLiTe/Kit.py b/Apps/YeLiTe/Kit.py index 2a7509f..e915574 100644 --- a/Apps/YeLiTe/Kit.py +++ b/Apps/YeLiTe/Kit.py @@ -51,6 +51,13 @@ def get_file_md5(file_path): hash_md5.update(chunk) return hash_md5.hexdigest() +def get_name_md5(name): + if not name: + return "unknown" + if not isinstance(name, str): + name = str(name) + return hashlib.md5(name.encode("utf-8")).hexdigest() + def get_image_content_md5(file_path, top_ratio=0.1, bottom_ratio=0.1): """ 计算图片核心内容的 MD5 值(排除状态栏和导航栏) diff --git a/Apps/YeLiTe/ReadImageKit.py b/Apps/YeLiTe/ReadImageKit.py index 01c9fc6..4fd8889 100644 --- a/Apps/YeLiTe/ReadImageKit.py +++ b/Apps/YeLiTe/ReadImageKit.py @@ -98,6 +98,28 @@ class ReadImageKit: logger.error(f"Failed VLM Response: {res_text}") return [] + async def analyze_detail_basic_info(self, image_path): + prompt = """ + 分析这张充电站详情页首屏截图,提取以下信息并返回 JSON: + { + "name": "场站名称", + "address": "完整地址", + "parking_info": "停车收费信息" + } + name 为页面标题中的场站名称,address 为定位图标附近的完整地址,parking_info 为页面中与停车收费相关的文字。如果某项无法识别,请将该字段设为 null。 + 只返回纯 JSON 对象,不要包含额外说明文字。 + """ + try: + res_text = await self.vlm.analyze_image(image_path, prompt) + json_str = self.vlm.extract_json(res_text) + data = json.loads(json_str) + if isinstance(data, dict): + return data + return {} + except Exception as e: + logger.error(f"分析详情页基础信息失败: {e}") + return {} + @classmethod async def detect_ad_popup(cls, image_path, device_info=None): """ diff --git a/Apps/YeLiTe/Service.py b/Apps/YeLiTe/Service.py index d5a53e4..7af6fbd 100644 --- a/Apps/YeLiTe/Service.py +++ b/Apps/YeLiTe/Service.py @@ -16,6 +16,7 @@ from Model.StationProfile import StationProfile from Model.StationStatus import StationStatus from Model.StationPriceSchedule import StationPriceSchedule from Apps.YeLiTe.Config.Setting import PRICE_FLATTEN_TO_24H +import re logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") logger = logging.getLogger(__name__) @@ -89,7 +90,17 @@ class YeLiTeService: except Exception as e: logger.error(f"更新任务结束日志失败: {e}") - async def process_price_detail_data(self, station_name, hourly_schedule, address=None, distance=None) -> bool: + async def process_price_detail_data( + self, + station_name, + hourly_schedule, + address=None, + distance=None, + total_piles=None, + free_piles=None, + piles_detail=None, + parking_info=None, + ) -> bool: if not station_name or not hourly_schedule: return False @@ -98,6 +109,54 @@ class YeLiTeService: schedule_to_save = hourly_schedule + standardized_piles = [] + total = total_piles or 0 + free = free_piles or 0 + + if isinstance(piles_detail, list): + for idx, p in enumerate(piles_detail): + try: + t = int(p.get("total", 0)) + f = int(p.get("idle", p.get("free", 0))) + total += t + free += f + standardized_piles.append( + { + "pile_no": f"G{idx+1}", + "type": p.get("type", "未知"), + "power": "", + "status_text": f"空闲{f}/总{t}", + "remark": "列表页忙闲", + } + ) + except Exception: + continue + elif isinstance(piles_detail, str): + piles_str = piles_detail + nums = re.findall(r"\d+", piles_str) + if len(nums) >= 2: + try: + f_val = int(nums[-2]) + t_val = int(nums[-1]) + free += f_val + total += t_val + standardized_piles.append( + { + "pile_no": "G1", + "type": "未知", + "power": "", + "status_text": piles_str, + "remark": "列表页忙闲(字符串)", + } + ) + except Exception: + pass + + if standardized_piles: + total_piles = total + free_piles = free + piles_detail = standardized_piles + use_flatten = (PRICE_FLATTEN_TO_24H_GLOBAL or PRICE_FLATTEN_TO_24H) and isinstance(hourly_schedule, list) if use_flatten: @@ -181,11 +240,12 @@ class YeLiTeService: session=session, id=status_id, station_hash=station_hash, - total_piles=None, - free_piles=None, - piles_detail_json=None, - current_price=current_price_info.get("price"), + total_piles=total_piles, + free_piles=free_piles, + piles_detail_json=piles_detail, + parking_info=parking_info, distance=distance, + current_price=current_price_info.get("price"), valid_start_time=now, ) diff --git a/Apps/YeLiTe/__pycache__/Crawler.cpython-310.pyc b/Apps/YeLiTe/__pycache__/Crawler.cpython-310.pyc index 31f462da516c3ea7dcb284d36ebd8e8e411a10b8..dfebc28618726eab4aa86b9851bd50fe6dd30c32 100644 GIT binary patch delta 4440 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 delta 4219 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 diff --git a/Apps/YeLiTe/__pycache__/Kit.cpython-310.pyc b/Apps/YeLiTe/__pycache__/Kit.cpython-310.pyc index c9c9e402c95936db67ab7decbdc569b893e44158..b6afcbbab7530aaf77833ef21b5747e28f0fb292 100644 GIT binary patch delta 2003 zcmZ8iUrbY181L!d+tN~?6r?S*$&WzLj7xwT!?096%DSDTr~~R zYOsW9nAX6vhQ2}TXaqd9w39|@1F$;UK^y57U=i9xV-QsjmN-p-B}yH%x!6!@%rz1R zZJ|lYPDRL+V|1E_R@t_Ps|)pSY|vczPjXLflr`NUwOJJSIEDvOh@(My#h zw=;B{oe_!JgecV1LW9oNG<#aW{Db(s=F6@rj5>>8k5zri>?IDEVel_V z@}f|?J8W0LQ!s3>6yMgWWS0ol^$glgJ&H!RZWK)EDr!bH#oobK6b9RafSqQ05%vM( z+%rsF%K4^?3yf)0ipzBruEL*nX>v;VB5B~+NFP}f(~%XjSpGc{Brx88>i1_}o1=#{ zV$LdrW`qpFh&UQ;CBF$Pnk5%S+E*_gM(+&7z?D@hIaH9i zg$6tIu(;WfCVz{E4UJ^E{IuaaXA~PpH|DblfM3@fk!gx6B{iKDR?84+`_ zHu6l|jO`^?#nadk@}W48*&=%4;ZPiuV>#ic0m81AN8<;bWV`sJ`3C6`v6gXAi{5g6 z_0`0$L!^Xls&tCOU6C%;Sh6cikIHb4Ue)4D^OgOxIo#6w2(~gx$n0a-7q7O`)&I*u zDs$S>qRFTwy;w$L(kIR)eISF`WLNYgrZ|N#f?#X(hWIAgNm|6u$$oOH97)Z&Kp?Aa zdp&F`#E2(tnLXn`q)(l;@Vc=HdsQ@NX5dyzKfJ!ifI}t40;-+Uiqie|_|SwDiT150 zWQb`c^PD!K8Wd*1E?{9ih4job-QdzcWU`XVIV1=j=v^&m%pmonaVFy&sFoZ~~; zI74AeH;4BhyMwN~xK^eruj;AFNc`w%LP#NefM5&BmQ*J$yAcim9IhzU7UO9&E+Sk+ zSVp)CkPDySda?VkYAsFV*{IIhHFTkD*e!$ypu9{1b1LxXppbx5aRx$4#9ld-K)@$1 HWg7ki`G)Bh delta 1820 zcmZ9MO>7%Q6vsXOT6^P-W5=;m+fAJBY|}VtQA1j2leTHnlGGI>t&|b1*?88@Hn!Iq zZ<4xDMO2k2l~Ab$xbStXK;lqY;sm{LK|%r!oR)JB5ki6!6$jwGbw5OG>9_CAdpq;y z&42c<+z02|O+}Gi@OyuI-MBM(uRTq^zc-d81NW%9GsuEWzD20Q+F0n8i?%a`wZk*a zhFAxSK%|2WvrZNRE5Zg?7mI@xWeL^|S)DMlk0oIw##}5_?yAIToVZw;?T2WB^{`%e zcC!)I$NC{_A0x{yb#xc2$rXspC1moe5di*pg+gH7vc(2fFI{xae?K=tx4+J^wPN55wA8S$gsLoSKmVWLw_rL7+~H5tl8 zRm_8}yZ8Zs+Rn$sT4*ecQ`yqC#;ZoP#E*$jLX(FNVnW!Kjfz&%^EJ&{r;4RlYGuvR z^Hr^))1bA^_4>M5X3o-7{1duC*2G)NI9Y0bsVsR8<8rEd*9Q-tL*UZ8sE6Id=$=OF zBebxb`4yfMe@D_{E)p5Q0WJZ)AT}vDRto_P><4@+u0=i{e+}Jb1Sa#9XO`nWOa2MR zFNwM6R2cisad+J5u6Q@9k#X@`bYjlw=sZMhuTd?Uwx_ID)eK+2+zG@a0^7`;@?QXp zdP`huP-(5a$+^y`xYEg>+23{ckwx(cNQD%eCO5=v>;@?|AI3ri&i03{1~zoq&w4| z5S2t9c_i*85@e%!Kk=2j%jvZvja7W_0%A%S$^ISeknO8(R%#8J#G8_B-IVNUvsyGt z*=60bP%>qFrGls;oEER{8U#nY9G-)8Thi9*cun~k@$+CJLIZW(TGF@l zvh6*Wo4-KCCa-9grE{t*TTo=>Nh%G& ze9wcj#@N${*dE#sTljEjW|m6pPiDp~*umn{**F8Ax{K?3uCk5OZr1W;vsBXgw1^Ea z?A*nowgIY}kD`rGiSxODq4Up%+_`x*$?+E0UJJgG{2dJ4Mn8~uK2rI7>vVz`=tej< zp@x>DDMwu+=pI3!7-n1QTtdHyxQf_7)B!Yn(K5=}Gg`fIp}-dni*I5G#lvqR?t=b? ZllX-R5d6#TfLm4qosQ?0WucA4{{zbUs6YS! diff --git a/Apps/YeLiTe/__pycache__/ReadImageKit.cpython-310.pyc b/Apps/YeLiTe/__pycache__/ReadImageKit.cpython-310.pyc index affba2c1f6a7daf1357be65fbc0996dd90704279..a6d9eb0fa056dd79e68815d1b3cdecc9bc8b36c1 100644 GIT binary patch delta 1139 zcmZ9KO-vI(6vt<_?Y3QL;{miqjY~BK{ER`P!T22$m52v4L@#9RR;`vowo8oA+EzX! z5o~o8<)hFxPz}TuQq;DB9K3n*+^e1K77t$aLYyh2R%f!mef#!5Z~n7ye;o;*Fm@OW z48UV8>aaJ}Ef_fn8>LRTbr-MU={|5nW25;>UdQYEU@yF(DSnLl4!>y1`u#hHmJlBGg5| zgA2f;D&{D+Dgr%fQ59CZ)i~0K8n;HIdnuvTt!V`pBqKN;ryF<%f5d#9M20jm&@WMy7-X%auH3;qmb`^T_-2pvpa9M*`2pKiZ%Tc z%5qG8@j+QkuiLVe3VTWsalqzM8FH*pR1QBbL|^Ap@A6}P<(}{a`O5!7$A5aoASSrWgEAh|R4(sf4IPk*Kp-^CU{rl%LiDC;_lt?QJ z5nLdb8dhR{G}MoRbA@OKO^+yvMfvs9((a`qT|4nFhz1Ab$zZYbUebCrmB~kZ8(p4W zP!?wz*?LAGzpY><*g?P&)Dl=QvTELL6@@+IxrSgbM!i<3An|^J0|X|5gBV!PiJZ_t zo-0c*oF}i$oRf1r=(e@-Hj%SC+HP_#yS3PI8-DHDhC%t%kYcJ}C1miV@if9sc7y9g3af*2x!P^woeo|&NzxajWpl03h(jIF aL7hr>nc6I^n(Z(vU9GtWFG{mD&3^znNUit) delta 259 zcmZ2r`@@tkpO=@50SLmLXJ)3WY~)L1WHg#wz$h(~%9_HJ!j{6`!r06h#g@X6!r8(Q z#h$_%%%I6Vc|BvexQ>feOiFQheo=NzVx~)CNn(s+K|yiMW*#O(cGf7SlA@@|PMixi z_wfE>W;CAME!fOxIJr~pM>dqvWpa?59{^v?L(KpH diff --git a/Apps/YeLiTe/__pycache__/Service.cpython-310.pyc b/Apps/YeLiTe/__pycache__/Service.cpython-310.pyc index 9031e1428b6d41194cebfa82ac2d9f235865ac29..ad301635959202a1bd95b842e1bcd312c34819f4 100644 GIT binary patch delta 3228 zcmZuzYm6IL6~6b*j6EJd*7m-U zak5o_8O@n{&+C5ooO2%^@BG7_Og)`82t2=iy=GfeuVjYl-(K1Jt7%R+tqqt17M&Y} zZ-^(jahXwK(UoCqLz|i-2MJH|)Fr}G%gh`Nvh-v6t-xTXwPr<+APAUb#FFyshxK zsWqE6-}P#|Cle;CmSc&EXO(SU44zRJ$4q5`KN!X=XQs|AGjY~B&+V$^dL<@$U~XbK z*r9d@|5g)p;$}=cO6g>9GB!y!1uw>~YFj~LZ!j1?K&OJ|;=5w|(c*#N)%c&cn{m-} z9NVdu)G+Q<+<6#L5A!~tyk%EkVs6?M}l36PxbAfTGBwU z*VvHT0i7^m2~ij21-A;^s_eg;*^A_%;60;A4+kuHu$2JDz2^aFq~ZGweC~HtLcUHV6`EvjoYP}Ok`*FpoB9cl zuCO-o4axjumG~*CHTpU8(=yf=f`7(SWZYAinW%Z1j4#tKlhco#Vt$vOUE1TtWOgOa z70%jhnYR4gU4|O5HDsf}&&#yTJw(81M&{w4k*O7($7C0e_mgYn`z+Ged7{m@!ILt7 z4a!UAK%(+A&%CC!DJ3V!xs59E5*Owu!S^Ke7m4$51keD0t?M%GcYDc|6z`JVZRYoQ zY1y+(d3IhC*O$fsTo2C;5CGI0wewNC4?y)spwhB00*TJ^~(N9YX#z=4%4A81p~BA7$K8N81(EQdLpXW~N%iJDhL>qFk_15*yo z6Y&WMaaO~S>0IP`u#NfNAcy=BIUcCkZEh@x|h~ zcRK$?2p_b@WC7w~_~UXM06iihEXRQJO%L{vsO+Zv2>>!N09H)|zbwaA zdZBbDw-VcW7p6|Hv!Tq`Cy*^o3rr_?1Eci)D=K5C( zZE^?(d4lY^`~Tic{zi!701UPXGzRB}`8oR8m>lkw*{uZ0~C8(4nRtiA)fHS#8B?_5GK<`5NCYNcHs1F?2gq_?H`q?r7 zlW5#V+Y`j;>Xak&o+_Orjvl!ijokfHCjHV~FjD}g7=f7rFq(|XxYVU8OR#>SG63B8 zWn&%O#+9*PcV=^oxl@a<^g7Fpl69y|?CpSaD3AMFA?4$ILQ+Wiq*Q@!lv^S3F-$z) zbc~cXA9-9**oi{Tt9zB2soK0|h3c%ZtdJgDjYO(vvxNK}eb{?A>|u zt<|eHny`hD?YA%fve^ZVTQ6VzYx_s5?VsKH^>;y7(#&|nu32TLF1`q2Q)|>0Eny}* zJ9OEz&UdOB1rhkru%g<3Hv#gTTX)1!;Js;x`<23E6s$7N%nc0;R;O*|B37AOUd66O9>P=u<_0Gg zoSw7wQ0F!PbpTU(rYVHwB)oEjQ5+54>pIq&5JiL%9V5|6GzQ&Jt$`IBRZepuI%mZ= za+Rv(g|SMb0h8?4DC{_!U&`Le<)Z z^1Wz^XVA+DB*&3F3j{)g0lXV6@m1tQ4q8Ou%+2gQ+p?lx2a-!OdY2IcZ~DmA%tYqDsE(NbC|PdErirIb;nvPV@Es{ypcOZ&EWmq zw$^FTcZXs9u#0+9r3TZf%2c2_w6m1aEGLs3I?_k*JDru|{X~}ICeC5sMRF2}hotv@(uZBV-{G$0P65#gBrl#UYKZ!rHRF{VvBf0F9v6izJH;P+uOsqwY!^uU}<&U V6rF@R!MtaqqQmloS^!?2{RcG1HyQu{ delta 2314 zcmZuy-H#kc5$~Rvov;1={ydvFXD(|e7w0%^> zy1Kr)rmLp7mB5_mduUHf2i%#nQFz?B$i|O+mS|s)mVWQZ_`GSRqwqgC1`Q( zJraEz$SMo^z02QRDt$}E?*4Z*E@7Eh#3dy ziQtIwnZ5w3^#}--%$f9Iv@MN5JHx)m(G&kRf{btiVJY~R`89ebh(u3~BEWd~>;WPM?}zZZCqVxe6_iJWnP^Oj17WL!6iG7Ka5DBKOOZ>cu!z}ajO!9#z z;_HN80-1D#z?zKBiEDiaLrsdfpAspN0G%I;6q5?XPm44&?kLQ>D~VB>MT=y2nPjnF z$ifimB?8J(aQML3?W~Z^S%rAfH-1ftpP}S>+KY|jEH2DDge64g4!NuBP)b(FCBi`C zMrLz%I$xvLkdqY#oP_S@M2`Pn8T650G<>cP)$e&D5qu|@gE!tgagy6JIdhnxoA-y@6D zc|?Bx6Tb+DmW6Ffppxt6MNyPQ1n7dGLKZ4ZZfjE`iZy_mWsnvpnq|<`Kqs{w+0{|I zCBI@5zX~;>VNJYE`SVN@6@|!Tox*CtD+_Ilu9Fdp`p^aX>FWkKs+7swbnq-1uaJI{ z5*)a?MEd%~U1j3#tkC@GgJ5b9Omz}WO+*-c9V4O&r3Mus6bLQ7ZS00t9M>M60H%rs zzf4xnQ1`|)$Q+JK@IDgt_B75uWl?_y@;$>cf4-`fQ+-_T;d}x7PmyaDf^eJ-dGCv6ue;(mf@ZZ#rqGynN3E^yTE1g|E2V~vg zkFbFeMm@)C^_l~_XSt!d#x3gsou06o%<@`xui15-ei&~LIk);=a~grpZ0I`uw#Cl{ zpQkUJ+QT2m-6s8D(o$4hVyot}xRufa{ZQ^$9^a4ah&$-n9)A)Q9%(qihnXivHDo3c zjv!#a<7t3Ux#|pgDEF*>s4%Mr; zJ&V7Lu3kkri-3VPQV*p~&uO}?A6mIabm&^mwO-5fU?S_}N z{RA5&-QZ&B8`7W2y|+pg3g`cRc|rP=1b;0bHKgU`y1EQcP_E2BHwmnaCX+(_I#QGB zn@8#ygyRU`1qhWZj??2kTssIW2%EuAE4BF|kZuV;Cy+EPBPV1%tIN7<##3ptn|qwc zL0I3*_reqgpHz+);7qyGwc1{jJB}Bst--+Rv*2*`SNp^0m6mI_pL6 delta 174 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 literal 0 HcmV?d00001