cursor_pro_keep_alive.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. from DrissionPage import ChromiumOptions, Chromium
  2. from DrissionPage.common import Keys
  3. import re
  4. import time
  5. import random
  6. from cursor_auth_manager import CursorAuthManager
  7. from configparser import ConfigParser
  8. import os
  9. import sys
  10. def load_config():
  11. """加载配置文件"""
  12. config = ConfigParser()
  13. # 获取程序运行的根目录
  14. root_dir = os.getcwd()
  15. config_path = os.path.join(root_dir, "config.ini")
  16. if os.path.exists(config_path):
  17. config.read(config_path, encoding="utf-8")
  18. print(f"已加载配置文件: {config_path}")
  19. return {
  20. "account": config["Account"]["email"],
  21. "password": config["Account"]["password"],
  22. "first_name": config["Account"]["first_name"],
  23. "last_name": config["Account"]["last_name"],
  24. }
  25. raise FileNotFoundError(
  26. f"配置文件不存在: {config_path}\n请确保配置文件在程序运行目录下"
  27. )
  28. def get_veri_code(tab):
  29. """获取验证码"""
  30. username = account.split("@")[0]
  31. try:
  32. while True:
  33. if tab.ele("@id=pre_button"):
  34. tab.actions.click("@id=pre_button").type(Keys.CTRL_A).key_down(
  35. Keys.BACKSPACE
  36. ).key_up(Keys.BACKSPACE).input(username).key_down(Keys.ENTER).key_up(
  37. Keys.ENTER
  38. )
  39. break
  40. time.sleep(1)
  41. while True:
  42. new_mail = tab.ele("@class=mail")
  43. if new_mail:
  44. if new_mail.text:
  45. print("最新的邮件:", new_mail.text)
  46. tab.actions.click("@class=mail")
  47. break
  48. else:
  49. print(new_mail)
  50. break
  51. time.sleep(1)
  52. if tab.ele("@class=overflow-auto mb-20"):
  53. email_content = tab.ele("@class=overflow-auto mb-20").text
  54. verification_code = re.search(
  55. r"verification code is (\d{6})", email_content
  56. )
  57. if verification_code:
  58. code = verification_code.group(1)
  59. print("验证码:", code)
  60. else:
  61. print("未找到验证码")
  62. if tab.ele("@id=delete_mail"):
  63. tab.actions.click("@id=delete_mail")
  64. time.sleep(1)
  65. if tab.ele("@id=confirm_mail"):
  66. tab.actions.click("@id=confirm_mail")
  67. print("删除邮件")
  68. tab.close()
  69. except Exception as e:
  70. print(e)
  71. return code
  72. def handle_turnstile(tab):
  73. """处理 Turnstile 验证"""
  74. print("准备处理验证")
  75. try:
  76. while True:
  77. try:
  78. challengeCheck = (
  79. tab.ele("@id=cf-turnstile", timeout=2)
  80. .child()
  81. .shadow_root.ele("tag:iframe")
  82. .ele("tag:body")
  83. .sr("tag:input")
  84. )
  85. if challengeCheck:
  86. print("验证框加载完成")
  87. time.sleep(random.uniform(1, 3))
  88. challengeCheck.click()
  89. print("验证按钮已点击,等待验证完成...")
  90. time.sleep(2)
  91. return True
  92. except:
  93. pass
  94. if tab.ele("@name=password"):
  95. print("无需验证")
  96. break
  97. if tab.ele("@data-index=0"):
  98. print("无需验证")
  99. break
  100. if tab.ele("Account Settings"):
  101. print("无需验证")
  102. break
  103. time.sleep(random.uniform(1, 2))
  104. except Exception as e:
  105. print(e)
  106. print("跳过验证")
  107. return False
  108. def delete_account(browser, tab):
  109. """删除账户流程"""
  110. print("\n开始删除账户...")
  111. try:
  112. if tab.ele("@name=email"):
  113. tab.ele("@name=email").input(account)
  114. print("输入账号")
  115. time.sleep(random.uniform(1, 3))
  116. except Exception as e:
  117. print(f"输入账号失败: {str(e)}")
  118. try:
  119. if tab.ele("Continue"):
  120. tab.ele("Continue").click()
  121. print("点击Continue")
  122. except Exception as e:
  123. print(f"点击Continue失败: {str(e)}")
  124. handle_turnstile(tab)
  125. time.sleep(5)
  126. try:
  127. if tab.ele("@name=password"):
  128. tab.ele("@name=password").input(password)
  129. print("输入密码")
  130. time.sleep(random.uniform(1, 3))
  131. except Exception as e:
  132. print("输入密码失败")
  133. sign_in_button = tab.ele(
  134. "xpath:/html/body/div[1]/div/div/div[2]/div/form/div/button"
  135. )
  136. try:
  137. if sign_in_button:
  138. sign_in_button.click(by_js=True)
  139. print("点击Sign in")
  140. except Exception as e:
  141. print(f"点击Sign in失败: {str(e)}")
  142. handle_turnstile(tab)
  143. # 处理验证码
  144. while True:
  145. try:
  146. if tab.ele("Account Settings"):
  147. break
  148. if tab.ele("@data-index=0"):
  149. tab_mail = browser.new_tab(mail_url)
  150. browser.activate_tab(tab_mail)
  151. print("打开邮箱页面")
  152. code = get_veri_code(tab_mail)
  153. if code:
  154. print("获取验证码成功:", code)
  155. browser.activate_tab(tab)
  156. else:
  157. print("获取验证码失败,程序退出")
  158. return False
  159. i = 0
  160. for digit in code:
  161. tab.ele(f"@data-index={i}").input(digit)
  162. time.sleep(random.uniform(0.1, 0.3))
  163. i += 1
  164. break
  165. except Exception as e:
  166. print(e)
  167. handle_turnstile(tab)
  168. time.sleep(random.uniform(1, 3))
  169. # tab.get_screenshot('sign-in_success.png')
  170. # print("登录账户截图")
  171. tab.get(settings_url)
  172. print("进入设置页面")
  173. try:
  174. if tab.ele("@class=mt-1"):
  175. tab.ele("@class=mt-1").click()
  176. print("点击Adavance")
  177. time.sleep(random.uniform(1, 2))
  178. except Exception as e:
  179. print(f"点击Adavance失败: {str(e)}")
  180. try:
  181. if tab.ele("Delete Account"):
  182. tab.ele("Delete Account").click()
  183. print("点击Delete Account")
  184. time.sleep(random.uniform(1, 2))
  185. except Exception as e:
  186. print(f"点击Delete Account失败: {str(e)}")
  187. try:
  188. if tab.ele("tag:input"):
  189. tab.actions.click("tag:input").type("delete")
  190. print("输入delete")
  191. time.sleep(random.uniform(1, 2))
  192. except Exception as e:
  193. print(f"输入delete失败: {str(e)}")
  194. delete_button = tab.ele(
  195. "xpath:/html/body/main/div/div/div/div/div/div[1]/div[2]/div[3]/div[2]/div/div/div[2]/button[2]"
  196. )
  197. try:
  198. if delete_button:
  199. print("点击Delete")
  200. delete_button.click()
  201. time.sleep(5)
  202. # tab.get_screenshot('delete_account.png')
  203. # print("删除账户截图")
  204. return True
  205. except Exception as e:
  206. print(f"点击Delete失败: {str(e)}")
  207. return False
  208. def get_cursor_session_token(tab):
  209. """获取cursor session token"""
  210. cookies = tab.cookies()
  211. cursor_session_token = None
  212. for cookie in cookies:
  213. if cookie["name"] == "WorkosCursorSessionToken":
  214. cursor_session_token = cookie["value"].split("%3A%3A")[1]
  215. break
  216. return cursor_session_token
  217. def update_cursor_auth(email=None, access_token=None, refresh_token=None):
  218. """
  219. 更新Cursor的认证信息的便捷函数
  220. """
  221. auth_manager = CursorAuthManager()
  222. return auth_manager.update_auth(email, access_token, refresh_token)
  223. def sign_up_account(browser, tab):
  224. """注册账户流程"""
  225. print("\n开始注册新账户...")
  226. tab.get(sign_up_url)
  227. try:
  228. if tab.ele("@name=first_name"):
  229. print("已打开注册页面")
  230. tab.actions.click("@name=first_name").input(first_name)
  231. time.sleep(random.uniform(1, 3))
  232. tab.actions.click("@name=last_name").input(last_name)
  233. time.sleep(random.uniform(1, 3))
  234. tab.actions.click("@name=email").input(account)
  235. print("输入邮箱")
  236. time.sleep(random.uniform(1, 3))
  237. tab.actions.click("@type=submit")
  238. print("点击注册按钮")
  239. except Exception as e:
  240. print("打开注册页面失败")
  241. return False
  242. handle_turnstile(tab)
  243. try:
  244. if tab.ele("@name=password"):
  245. tab.ele("@name=password").input(password)
  246. print("输入密码")
  247. time.sleep(random.uniform(1, 3))
  248. tab.ele("@type=submit").click()
  249. print("点击Continue按钮")
  250. except Exception as e:
  251. print("输入密码失败")
  252. return False
  253. time.sleep(random.uniform(1, 3))
  254. if tab.ele("This email is not available."):
  255. print("This email is not available.")
  256. return False
  257. handle_turnstile(tab)
  258. while True:
  259. try:
  260. if tab.ele("Account Settings"):
  261. break
  262. if tab.ele("@data-index=0"):
  263. tab_mail = browser.new_tab(mail_url)
  264. browser.activate_tab(tab_mail)
  265. print("打开邮箱页面")
  266. code = get_veri_code(tab_mail)
  267. if code:
  268. print("获取验证码成功:", code)
  269. browser.activate_tab(tab)
  270. else:
  271. print("获取验证码失败,程序退出")
  272. return False
  273. i = 0
  274. for digit in code:
  275. tab.ele(f"@data-index={i}").input(digit)
  276. time.sleep(random.uniform(0.1, 0.3))
  277. i += 1
  278. break
  279. except Exception as e:
  280. print(e)
  281. handle_turnstile(tab)
  282. time.sleep(random.uniform(1, 3))
  283. print("进入设置页面")
  284. tab.get(settings_url)
  285. try:
  286. usage_ele = tab.ele(
  287. "xpath:/html/body/main/div/div/div/div/div/div[2]/div/div/div/div[1]/div[1]/span[2]"
  288. )
  289. if usage_ele:
  290. usage_info = usage_ele.text
  291. total_usage = usage_info.split("/")[-1].strip()
  292. print("可用上限: " + total_usage)
  293. except Exception as e:
  294. print("获取可用上限失败")
  295. # tab.get_screenshot("sign_up_success.png")
  296. # print("注册账户截图")
  297. print("注册完成")
  298. print("Cursor 账号: " + account)
  299. print(" 密码: " + password)
  300. return True
  301. def get_extension_path():
  302. """获取插件路径"""
  303. root_dir = os.getcwd()
  304. extension_path = os.path.join(root_dir, "turnstilePatch")
  305. if hasattr(sys, "_MEIPASS"):
  306. print("运行在打包环境中")
  307. extension_path = os.path.join(sys._MEIPASS, "turnstilePatch")
  308. print(f"尝试加载插件路径: {extension_path}")
  309. if not os.path.exists(extension_path):
  310. raise FileNotFoundError(
  311. f"插件不存在: {extension_path}\n请确保 turnstilePatch 文件夹在正确位置"
  312. )
  313. return extension_path
  314. if __name__ == "__main__":
  315. try:
  316. # 加载配置
  317. config = load_config()
  318. # 固定的 URL 配置
  319. login_url = "https://authenticator.cursor.sh"
  320. sign_up_url = "https://authenticator.cursor.sh/sign-up"
  321. settings_url = "https://www.cursor.com/settings"
  322. mail_url = "https://tempmail.plus"
  323. # 账号信息
  324. account = config["account"]
  325. password = config["password"]
  326. first_name = config["first_name"]
  327. last_name = config["last_name"]
  328. auto_update_cursor_auth = True
  329. # 浏览器配置
  330. co = ChromiumOptions()
  331. try:
  332. extension_path = get_extension_path()
  333. co.add_extension(extension_path)
  334. except FileNotFoundError as e:
  335. print(f"警告: {e}")
  336. print("将尝试继续执行...")
  337. co.headless() # 无头模式
  338. co.set_user_agent(
  339. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36"
  340. )
  341. co.set_pref("credentials_enable_service", False)
  342. co.set_argument("--hide-crash-restore-bubble")
  343. co.auto_port()
  344. # co.set_argument('--no-sandbox') # 无沙盒模式 用于linux
  345. # co.set_argument('--headless=new') #无界面系统启动参数 用于linux
  346. # co.set_proxy('127.0.0.1:10809') #设置代理
  347. browser = Chromium(co)
  348. tab = browser.latest_tab
  349. tab.run_js("try { turnstile.reset() } catch(e) { }")
  350. print("开始执行删除和注册流程")
  351. print("***请确认已经用https://tempmail.plus/zh邮箱成功申请过cursor账号!***")
  352. tab.get(login_url)
  353. # 执行删除和注册流程
  354. if delete_account(browser, tab):
  355. print("账户删除成功")
  356. time.sleep(3)
  357. if sign_up_account(browser, tab):
  358. token = get_cursor_session_token(tab)
  359. print(f"CursorSessionToken: {token}")
  360. print("账户注册成功")
  361. if auto_update_cursor_auth:
  362. update_cursor_auth(
  363. email=account, access_token=token, refresh_token=token
  364. )
  365. else:
  366. print("账户注册失败")
  367. else:
  368. print("账户删除失败")
  369. print("脚本执行完毕")
  370. browser.quit()
  371. # 添加等待用户输入后再退出
  372. input("\n按回车键退出...")
  373. except FileNotFoundError as e:
  374. print(f"���误: {e}")
  375. print("请确保 config.ini 文件存在并包含正确的配置信息")
  376. input("\n按回车键退出...")
  377. except Exception as e:
  378. print(f"加载配置时出错: {e}")
  379. input("\n按回车键退出...")