├── .env ├── .github └── workflows │ └── daily.yml ├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── nodeseek_daily.py └── requirements.txt /.env: -------------------------------------------------------------------------------- 1 | NS_COOKIE=如果本地调试这里填你的cookie -------------------------------------------------------------------------------- /.github/workflows/daily.yml: -------------------------------------------------------------------------------- 1 | name: NodeSeek 自动签到评论加鸡腿 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | schedule: 8 | - cron: '00 16 * * *' # UTC 16:00,即北京时间 00:00 9 | 10 | jobs: 11 | run-nodeseek-daily: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Checkout repository 16 | uses: actions/checkout@v3 17 | 18 | - name: Set up Python 19 | uses: actions/setup-python@v2 20 | with: 21 | python-version: '3.11.8' 22 | 23 | - name: Install Chrome and Xvfb 24 | run: | 25 | sudo apt-get update 26 | sudo apt-get install -y chromium-browser chromium-chromedriver xvfb 27 | echo "Chrome version:" 28 | chromium-browser --version 29 | echo "ChromeDriver version:" 30 | chromedriver --version 31 | 32 | - name: Install Python dependencies 33 | run: | 34 | python -m pip install --upgrade pip 35 | pip install -r requirements.txt 36 | 37 | - name: Run NodeSeek script 38 | env: 39 | NS_COOKIE: ${{ secrets.NS_COOKIE }} 40 | NS_RANDOM: ${{ secrets.NS_RANDOM }} 41 | HEADLESS: "true" 42 | run: | 43 | python nodeseek_daily.py -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.DS_Store 2 | /.venv 3 | /__pycache__ -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.envFile": "${workspaceFolder}/.env" 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 [Hosea] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NodeSeek 自动签到评论加鸡腿脚本 2 | 3 | 这是一个用于 NodeSeek 论坛的自动化脚本,包含签到、评论和加鸡腿功能。使用 Selenium 和 undetected-chromedriver 实现自动化操作。 4 | 5 | 强烈建议修改随机词。否则容易被举报被禁言。有能力的可以fork后自己定义改。 6 | 7 | ## 功能特点 8 | 9 | - 自动签到(点击签到图标) 10 | - 自动点击"试试手气"或"鸡腿 x 5"按钮(可配置) 11 | - 随机选择帖子进行评论 12 | - 自动给帖子加鸡腿(7天内的帖子) 13 | - 随机评论内容("bd"、"绑定"、"帮顶") 14 | - 支持 GitHub Actions 自动运行 15 | - 支持无头模式(可配置) 16 | 17 | ## 环境变量配置 18 | 19 | - `NS_COOKIE`: NodeSeek 的 Cookie(必需) 20 | - `NS_RANDOM`: 是否随机选择奖励,true/false(可选) 21 | - `HEADLESS`: 是否使用无头模式,true/false(可选,默认 true) 22 | 23 | ## 本地运行 24 | 25 | 1. 克隆仓库 26 | 2. 安装依赖:`pip install -r requirements.txt` 27 | 3. 设置环境变量(可使用 .env 文件) 28 | 4. 运行脚本:`python nodeseek_daily.py` 29 | 30 | ## GitHub Actions 自动运行 31 | 32 | 1. Fork 本仓库 33 | 2. 在仓库的 Settings -> Secrets 中添加 `NS_COOKIE` 34 | 3. 可选:添加 `NS_RANDOM` 设置是否随机选择奖励 35 | 4. Actions 会在每天 UTC 16:00(北京时间 00:00)自动运行 36 | 37 | ## 注意事项 38 | 39 | - 请确保 Cookie 有效且具有足够的权限 40 | - 评论内容较为简单,建议根据需要修改 `randomInputStr` 列表 41 | - 加鸡腿功能仅对 7 天内的帖子有效 42 | -------------------------------------------------------------------------------- /nodeseek_daily.py: -------------------------------------------------------------------------------- 1 | # -- coding: utf-8 -- 2 | """ 3 | Copyright (c) 2024 [Hosea] 4 | Licensed under the MIT License. 5 | See LICENSE file in the project root for full license information. 6 | """ 7 | import os 8 | from bs4 import BeautifulSoup 9 | from selenium.webdriver.common.by import By 10 | from selenium.webdriver.support.ui import WebDriverWait 11 | from selenium.webdriver.support import expected_conditions as EC 12 | import random 13 | import time 14 | import traceback 15 | import undetected_chromedriver as uc 16 | from selenium.webdriver.common.keys import Keys 17 | from selenium.webdriver.common.action_chains import ActionChains 18 | 19 | ns_random = os.environ.get("NS_RANDOM","false") 20 | cookie = os.environ.get("NS_COOKIE") or os.environ.get("COOKIE") 21 | # 通过环境变量控制是否使用无头模式,默认为 True(无头模式) 22 | headless = os.environ.get("HEADLESS", "true").lower() == "true" 23 | 24 | randomInputStr = ["bd","绑定","帮顶"] 25 | 26 | def click_sign_icon(driver): 27 | """ 28 | 尝试点击签到图标和试试手气按钮的通用方法 29 | """ 30 | try: 31 | print("开始查找签到图标...") 32 | # 使用更精确的选择器定位签到图标 33 | sign_icon = WebDriverWait(driver, 30).until( 34 | EC.presence_of_element_located((By.XPATH, "//span[@title='签到']")) 35 | ) 36 | print("找到签到图标,准备点击...") 37 | 38 | # 确保元素可见和可点击 39 | driver.execute_script("arguments[0].scrollIntoView(true);", sign_icon) 40 | time.sleep(0.5) 41 | 42 | # 打印元素信息 43 | print(f"签到图标元素: {sign_icon.get_attribute('outerHTML')}") 44 | 45 | # 尝试点击 46 | try: 47 | 48 | 49 | sign_icon.click() 50 | print("签到图标点击成功") 51 | except Exception as click_error: 52 | print(f"点击失败,尝试使用 JavaScript 点击: {str(click_error)}") 53 | driver.execute_script("arguments[0].click();", sign_icon) 54 | 55 | print("等待页面跳转...") 56 | time.sleep(5) 57 | 58 | # 打印当前URL 59 | print(f"当前页面URL: {driver.current_url}") 60 | 61 | # 点击"试试手气"按钮 62 | try: 63 | click_button:None 64 | 65 | if ns_random: 66 | click_button = WebDriverWait(driver, 5).until( 67 | EC.element_to_be_clickable((By.XPATH, "//button[contains(text(), '试试手气')]")) 68 | ) 69 | else: 70 | click_button = WebDriverWait(driver, 5).until( 71 | EC.element_to_be_clickable((By.XPATH, "//button[contains(text(), '鸡腿 x 5')]")) 72 | ) 73 | 74 | click_button.click() 75 | print("完成试试手气点击") 76 | except Exception as lucky_error: 77 | print(f"试试手气按钮点击失败或者签到过了: {str(lucky_error)}") 78 | 79 | return True 80 | 81 | except Exception as e: 82 | print(f"签到过程中出错:") 83 | print(f"错误类型: {type(e).__name__}") 84 | print(f"错误信息: {str(e)}") 85 | print(f"当前页面URL: {driver.current_url}") 86 | print(f"当前页面源码片段: {driver.page_source[:500]}...") 87 | print("详细错误信息:") 88 | traceback.print_exc() 89 | return False 90 | 91 | def setup_driver_and_cookies(): 92 | """ 93 | 初始化浏览器并设置cookie的通用方法 94 | 返回: 设置好cookie的driver实例 95 | """ 96 | try: 97 | cookie = os.environ.get("NS_COOKIE") or os.environ.get("COOKIE") 98 | headless = os.environ.get("HEADLESS", "true").lower() == "true" 99 | 100 | if not cookie: 101 | print("未找到cookie配置") 102 | return None 103 | 104 | print("开始初始化浏览器...") 105 | options = uc.ChromeOptions() 106 | options.add_argument('--no-sandbox') 107 | options.add_argument('--disable-dev-shm-usage') 108 | 109 | if headless: 110 | print("启用无头模式...") 111 | options.add_argument('--headless') 112 | # 添加以下参数来绕过 Cloudflare 检测 113 | options.add_argument('--disable-blink-features=AutomationControlled') 114 | options.add_argument('--disable-gpu') 115 | options.add_argument('--window-size=1920,1080') 116 | # 设置 User-Agent 117 | options.add_argument('--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36') 118 | 119 | print("正在启动Chrome...") 120 | driver = uc.Chrome(options=options) 121 | 122 | if headless: 123 | # 执行 JavaScript 来修改 webdriver 标记 124 | driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") 125 | driver.set_window_size(1920, 1080) 126 | 127 | print("Chrome启动成功") 128 | 129 | print("正在设置cookie...") 130 | driver.get('https://www.nodeseek.com') 131 | 132 | # 等待页面加载完成 133 | time.sleep(5) 134 | 135 | for cookie_item in cookie.split(';'): 136 | try: 137 | name, value = cookie_item.strip().split('=', 1) 138 | driver.add_cookie({ 139 | 'name': name, 140 | 'value': value, 141 | 'domain': '.nodeseek.com', 142 | 'path': '/' 143 | }) 144 | except Exception as e: 145 | print(f"设置cookie出错: {str(e)}") 146 | continue 147 | 148 | print("刷新页面...") 149 | driver.refresh() 150 | time.sleep(5) # 增加等待时间 151 | 152 | return driver 153 | 154 | except Exception as e: 155 | print(f"设置浏览器和Cookie时出错: {str(e)}") 156 | print("详细错误信息:") 157 | print(traceback.format_exc()) 158 | return None 159 | 160 | def nodeseek_comment(driver): 161 | try: 162 | print("正在访问交易区...") 163 | target_url = 'https://www.nodeseek.com/categories/trade' 164 | driver.get(target_url) 165 | print("等待页面加载...") 166 | 167 | # 获取初始帖子列表 168 | posts = WebDriverWait(driver, 30).until( 169 | EC.presence_of_all_elements_located((By.CSS_SELECTOR, '.post-list-item')) 170 | ) 171 | print(f"成功获取到 {len(posts)} 个帖子") 172 | 173 | # 过滤掉置顶帖 174 | valid_posts = [post for post in posts if not post.find_elements(By.CSS_SELECTOR, '.pined')] 175 | selected_posts = random.sample(valid_posts, min(20, len(valid_posts))) 176 | 177 | # 存储已选择的帖子URL 178 | selected_urls = [] 179 | for post in selected_posts: 180 | try: 181 | post_link = post.find_element(By.CSS_SELECTOR, '.post-title a') 182 | selected_urls.append(post_link.get_attribute('href')) 183 | except: 184 | continue 185 | 186 | is_chicken_leg = False 187 | 188 | # 使用URL列表进行操作 189 | for i, post_url in enumerate(selected_urls): 190 | try: 191 | print(f"正在处理第 {i+1} 个帖子") 192 | driver.get(post_url) 193 | 194 | # 处理加鸡腿 195 | if is_chicken_leg is False: 196 | is_chicken_leg = click_chicken_leg(driver) 197 | 198 | # 等待 CodeMirror 编辑器加载 199 | editor = WebDriverWait(driver, 30).until( 200 | EC.presence_of_element_located((By.CSS_SELECTOR, '.CodeMirror')) 201 | ) 202 | 203 | # 点击编辑器区域获取焦点 204 | editor.click() 205 | time.sleep(0.5) 206 | input_text = random.choice(randomInputStr) 207 | 208 | # 模拟输入 209 | actions = ActionChains(driver) 210 | # 随机输入 randomInputStr 211 | for char in input_text: 212 | actions.send_keys(char) 213 | actions.pause(random.uniform(0.1, 0.3)) 214 | actions.perform() 215 | 216 | # 等待一下确保内容已经输入 217 | time.sleep(2) 218 | 219 | # 使用更精确的选择器定位提交按钮 220 | submit_button = WebDriverWait(driver, 30).until( 221 | EC.element_to_be_clickable((By.XPATH, "//button[contains(@class, 'submit') and contains(@class, 'btn') and contains(text(), '发布评论')]")) 222 | ) 223 | # 确保按钮可见并可点击 224 | driver.execute_script("arguments[0].scrollIntoView(true);", submit_button) 225 | time.sleep(0.5) 226 | submit_button.click() 227 | 228 | print(f"已在帖子 {post_url} 中完成评论") 229 | 230 | # 返回交易区 231 | # driver.get(target_url) 232 | # time.sleep(2) # 等待页面加载 233 | time.sleep(random.uniform(2,5)) 234 | 235 | except Exception as e: 236 | print(f"处理帖子时出错: {str(e)}") 237 | continue 238 | 239 | print("NodeSeek评论任务完成") 240 | 241 | except Exception as e: 242 | print(f"NodeSeek评论出错: {str(e)}") 243 | print("详细错误信息:") 244 | print(traceback.format_exc()) 245 | 246 | def click_chicken_leg(driver): 247 | try: 248 | print("尝试点击加鸡腿按钮...") 249 | chicken_btn = WebDriverWait(driver, 5).until( 250 | EC.element_to_be_clickable((By.XPATH, '//div[@class="nsk-post"]//div[@title="加鸡腿"][1]')) 251 | ) 252 | driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", chicken_btn) 253 | time.sleep(0.5) 254 | chicken_btn.click() 255 | print("加鸡腿按钮点击成功") 256 | 257 | # 等待确认对话框出现 258 | WebDriverWait(driver, 5).until( 259 | EC.presence_of_element_located((By.CSS_SELECTOR, '.msc-confirm')) 260 | ) 261 | 262 | # 检查是否是7天前的帖子 263 | try: 264 | error_title = driver.find_element(By.XPATH, "//h3[contains(text(), '该评论创建于7天前')]") 265 | if error_title: 266 | print("该帖子超过7天,无法加鸡腿") 267 | ok_btn = driver.find_element(By.CSS_SELECTOR, '.msc-confirm .msc-ok') 268 | ok_btn.click() 269 | return False 270 | except: 271 | ok_btn = WebDriverWait(driver, 5).until( 272 | EC.element_to_be_clickable((By.CSS_SELECTOR, '.msc-confirm .msc-ok')) 273 | ) 274 | ok_btn.click() 275 | print("确认加鸡腿成功") 276 | 277 | # 等待确认对话框消失 278 | WebDriverWait(driver, 5).until_not( 279 | EC.presence_of_element_located((By.CSS_SELECTOR, '.msc-overlay')) 280 | ) 281 | time.sleep(1) # 额外等待以确保对话框完全消失 282 | 283 | return True 284 | 285 | except Exception as e: 286 | print(f"加鸡腿操作失败: {str(e)}") 287 | return False 288 | 289 | if __name__ == "__main__": 290 | print("开始执行NodeSeek评论脚本...") 291 | driver = setup_driver_and_cookies() 292 | if not driver: 293 | print("浏览器初始化失败") 294 | exit(1) 295 | nodeseek_comment(driver) 296 | click_sign_icon(driver) 297 | print("脚本执行完成") 298 | # while True: 299 | # time.sleep(1) 300 | 301 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | selenium>=4.18.1 2 | requests>=2.31.0 3 | curl_cffi>=0.6.2 4 | beautifulsoup4>=4.12.3 5 | undetected-chromedriver>=3.5.5 6 | webdriver_manager>=4.0.1 --------------------------------------------------------------------------------