11import os
22import random
33import time
4+ import functools
45
56from loguru import logger
67from playwright .sync_api import sync_playwright
78from tabulate import tabulate
89
910
11+ def retry_decorator (retries = 3 ):
12+ def decorator (func ):
13+ @functools .wraps (func )
14+ def wrapper (* args , ** kwargs ):
15+ for attempt in range (retries ):
16+ try :
17+ return func (* args , ** kwargs )
18+ except Exception as e :
19+ if attempt == retries - 1 : # 最后一次尝试
20+ logger .error (f"函数 { func .__name__ } 最终执行失败: { str (e )} " )
21+ logger .warning (f"函数 { func .__name__ } 第 { attempt + 1 } /{ retries } 次尝试失败: { str (e )} " )
22+ time .sleep (1 )
23+ return None
24+
25+ return wrapper
26+
27+ return decorator
28+
29+
1030os .environ .pop ("DISPLAY" , None )
1131os .environ .pop ("DYLD_LIBRARY_PATH" , None )
1232
@@ -25,7 +45,7 @@ def __init__(self) -> None:
2545 self .page .goto (HOME_URL )
2646
2747 def login (self ):
28- logger .info ("Login " )
48+ logger .info ("开始登录 " )
2949 self .page .click (".login-button .d-button-label" )
3050 time .sleep (2 )
3151 self .page .fill ("#login-account-name" , USERNAME )
@@ -36,36 +56,39 @@ def login(self):
3656 time .sleep (10 )
3757 user_ele = self .page .query_selector ("#current-user" )
3858 if not user_ele :
39- logger .error ("Login failed " )
59+ logger .error ("登录失败 " )
4060 return False
4161 else :
42- logger .info ("Login success " )
62+ logger .info ("登录成功 " )
4363 return True
4464
4565 def click_topic (self ):
4666 topic_list = self .page .query_selector_all ("#list-area .title" )
47- logger .info (f"Click { len (topic_list )} topics " )
67+ logger .info (f"发现 { len (topic_list )} 个主题帖 " )
4868 for topic in topic_list :
49- logger .info ("Click topic: " + topic .get_attribute ("href" ))
50- page = self .context .new_page ()
51- page .goto (HOME_URL + topic .get_attribute ("href" ))
52- if random .random () < 0.3 : # 0.3 * 30 = 9
53- self .click_like (page )
54- self .browse_post (page )
55- page .close ()
69+ self .click_one_topic (topic .get_attribute ("href" ))
70+
71+ @retry_decorator ()
72+ def click_one_topic (self , topic_url ):
73+ page = self .context .new_page ()
74+ page .goto (HOME_URL + topic_url )
75+ if random .random () < 0.3 : # 0.3 * 30 = 9
76+ self .click_like (page )
77+ self .browse_post (page )
78+ page .close ()
5679
5780 def browse_post (self , page ):
5881 prev_url = None
5982 # 开始自动滚动,最多滚动10次
6083 for _ in range (10 ):
6184 # 随机滚动一段距离
6285 scroll_distance = random .randint (550 , 650 ) # 随机滚动 550-650 像素
63- logger .info (f"Scrolling down by { scroll_distance } pixels ..." )
86+ logger .info (f"向下滚动 { scroll_distance } 像素 ..." )
6487 page .evaluate (f"window.scrollBy(0, { scroll_distance } )" )
65- logger .info (f"Loaded : { page .url } " )
88+ logger .info (f"已加载页面 : { page .url } " )
6689
6790 if random .random () < 0.03 : # 33 * 4 = 132
68- logger .success ("Randomly exit " )
91+ logger .success ("随机退出浏览 " )
6992 break
7093
7194 # 检查是否到达页面底部
@@ -74,12 +97,12 @@ def browse_post(self, page):
7497 if current_url != prev_url :
7598 prev_url = current_url
7699 elif at_bottom and prev_url == current_url :
77- logger .success ("Reached the bottom of the page. Exiting. " )
100+ logger .success ("已到达页面底部,退出浏览 " )
78101 break
79102
80103 # 动态随机等待
81104 wait_time = random .uniform (2 , 4 ) # 随机等待 2-4 秒
82- logger .info (f"Waiting for { wait_time :.2f} seconds ..." )
105+ logger .info (f"等待 { wait_time :.2f} 秒 ..." )
83106 time .sleep (wait_time )
84107
85108 def run (self ):
@@ -103,7 +126,7 @@ def click_like(self, page):
103126 logger .error (f"点赞失败: { str (e )} " )
104127
105128 def print_connect_info (self ):
106- logger .info ("Print connect info " )
129+ logger .info ("获取连接信息 " )
107130 page = self .context .new_page ()
108131 page .goto ("https://connect.linux.do/" )
109132 rows = page .query_selector_all ("table tr" )
0 commit comments