login_yaoshibang.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import random
  2. import signal
  3. import socket
  4. import sys
  5. import time
  6. from commons.conn_mysql import MySQLPoolOnline
  7. from DrissionPage import ChromiumPage, ChromiumOptions
  8. from commons.Logger import logger
  9. from oss_upload.oss_upload import AliyunOSSUploader
  10. from commons.config import YSB_ACCOUNT
  11. from spiders.yaoshibang.yidun_slider_captcha import solve_slider_captcha
  12. import json
  13. chrome_path = r"C:\Program Files\Google\Chrome\Application\chrome.exe"
  14. class YaoShiBangLogin:
  15. def __init__(self, product=None):
  16. self.product = product
  17. self.driver = None
  18. self.account_name = None
  19. self.platform = 5
  20. self.phone = None
  21. self.password = None
  22. self.db_online = MySQLPoolOnline()
  23. self.ossuploader = AliyunOSSUploader()
  24. self._register_signal_handler()
  25. def _register_signal_handler(self):
  26. def handler(signum, frame):
  27. logger.info("收到退出信号,正在关闭浏览器...")
  28. self._quit_browser()
  29. sys.exit(0)
  30. signal.signal(signal.SIGINT, handler)
  31. if hasattr(signal, "SIGTERM"):
  32. signal.signal(signal.SIGTERM, handler)
  33. def _quit_browser(self):
  34. if self.driver:
  35. try:
  36. self.driver.quit()
  37. except Exception:
  38. pass
  39. self.driver = None
  40. @staticmethod
  41. def _get_free_port():
  42. """获取一个当前可用的本地端口,供 Chrome 调试使用。"""
  43. with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
  44. s.bind(("127.0.0.1", 0))
  45. return s.getsockname()[1]
  46. def init_browser(self):
  47. co = ChromiumOptions().set_browser_path(chrome_path)
  48. debug_port = self._get_free_port()
  49. co.set_user_data_path(f"./spiders/yaoshibang/{self.account_name}")
  50. co.set_local_port(debug_port)
  51. co.set_argument(f"--remote-debugging-port={debug_port}")
  52. co.set_argument("--remote-debugging-address=127.0.0.1")
  53. # co.set_argument("--disable-blink-features=AutomationControlled")
  54. co.set_argument("--disable-dev-shm-usage")
  55. co.set_argument("--start-maximized")
  56. co.set_argument("--no-first-run") # 避免首次运行弹窗
  57. co.set_argument("--no-default-browser-check") # 避免默认浏览器检查
  58. self.driver = ChromiumPage(co)
  59. def _is_logged_in(self):
  60. # 与当前账号店铺展示文案一致;换店后需同步修改或改为配置项
  61. title = self.driver.ele(
  62. "xpath=//span[@class='logout']",
  63. timeout=8,
  64. )
  65. return bool(title)
  66. def login(self, account_dict):
  67. logger.info("开始登录药师帮")
  68. self.driver.get("https://dian.ysbang.cn/#/login", timeout=15)
  69. self.driver.wait.doc_loaded(timeout=10)
  70. time.sleep(2)
  71. input_name = self.driver.ele("xpath://input[@name='userAccount']", timeout=5)
  72. if not input_name:
  73. logger.error("未找到账号输入框")
  74. return False
  75. input_name.input(account_dict["phone"])
  76. time.sleep(random.uniform(1.5, 2.5))
  77. input_pass = self.driver.ele("xpath://input[@name='password']", timeout=5)
  78. if not input_pass:
  79. logger.error("未找到密码输入框")
  80. return False
  81. input_pass.input(account_dict["password"])
  82. time.sleep(random.uniform(1.5, 2.5))
  83. login_btn = self.driver.ele("xpath://button[text()='登录']", timeout=5)
  84. if not login_btn:
  85. logger.error("未找到登录按钮")
  86. return False
  87. login_btn.click()
  88. time.sleep(3)
  89. for i in range(3):
  90. solve_slider_captcha(self.driver)
  91. time.sleep(3)
  92. if self._is_logged_in():
  93. time.sleep(3)
  94. logger.info("登录成功")
  95. cookies_list = self.driver.cookies()
  96. self.save_cookies(cookies_list)
  97. return True
  98. logger.error("登录后未检测到目标店铺名,登录可能失败")
  99. return False
  100. def save_cookies(self, cookies_list):
  101. cookies_dict = {c['name']: c['value'] for c in cookies_list}
  102. timestamp = int(time.time())
  103. next_update_time = timestamp + random.randint(3600, 7200)
  104. # 保存 cookie 到文件
  105. update_sql = f""" UPDATE `accounts_platform` SET `cookie_timestamp` = %s, `cookie_str`= %s,`cookie_update_time` = %s, `status`= %s WHERE `name` = %s; """
  106. self.db_online.execute(update_sql,
  107. (timestamp, json.dumps(cookies_dict), next_update_time, 1, self.account_name))
  108. logger.info("cookie已保存成功")
  109. def search(self, account_dict):
  110. self.driver.get("https://dian.ysbang.cn/#/home", timeout=15)
  111. self.driver.wait.doc_loaded(timeout=10)
  112. time.sleep(2)
  113. if not self._is_logged_in():
  114. if not self.login(account_dict):
  115. return False
  116. else:
  117. cookies_list = self.driver.cookies()
  118. self.save_cookies(cookies_list)
  119. def get_account(self):
  120. sql_account = f""" select `id`,`name`,`ip`,`phone`,`password`,`cookie_timestamp`,`cookie_str` from `accounts_platform` where `platform`=5 and `status`=1 and `equipment_id`=3 order by `cookie_timestamp` asc limit 1 """
  121. account_list = self.db_online.select_data(sql_account)
  122. if not account_list:
  123. return {}
  124. account_dict = account_list[0]
  125. self.account_name = account_dict["name"]
  126. self.phone = account_dict["phone"]
  127. self.password = account_dict["password"]
  128. return account_dict
  129. def run(self):
  130. account_dict = self.get_account()
  131. if not account_dict:
  132. logger.error("ysb无账号可用")
  133. print(account_dict)
  134. try:
  135. self.init_browser()
  136. self.search(account_dict)
  137. except Exception as e:
  138. logger.exception("运行异常: %s", e)
  139. finally:
  140. self._quit_browser()
  141. if __name__ == "__main__":
  142. YaoShiBangLogin().run()