snapshot_taobao_login.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import time
  2. import random
  3. import signal
  4. import sys
  5. from DrissionPage import ChromiumPage, ChromiumOptions
  6. import socket
  7. from commons.conn_mysql import MySQLPoolOn2
  8. from commons.Logger import logger
  9. from commons.config import CHROME_PATH
  10. MAX_PAGES = 5
  11. WAIT_BETWEEN_PAGES = (8, 15) # 页间等待时间范围(秒)
  12. SCROLL_DELAY = (0.3, 0.8) # 滚动延迟范围
  13. CLICK_DELAY = (0.5, 1.2) # 点击延迟范围
  14. BROWSE_TIME = (5, 10) # 浏览时间范围
  15. chrome_path = CHROME_PATH
  16. class TaobaoAutoCrawl:
  17. def __init__(self, account_name, ip, key_word):
  18. self.driver = None
  19. self.register_signal_handler()
  20. self.db = MySQLPoolOn2()
  21. self.account_name = account_name
  22. self.ip = ip
  23. self.keyword = key_word
  24. @staticmethod
  25. def _get_free_port():
  26. """获取一个当前可用的本地端口,供 Chrome 调试使用。"""
  27. with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
  28. s.bind(("127.0.0.1", 0))
  29. return s.getsockname()[1]
  30. def init_drissionpage(self):
  31. # 避免 auto_port 在部分环境下生成异常地址(无端口)导致 ChromiumPage 初始化失败
  32. co = ChromiumOptions().set_browser_path(chrome_path)
  33. #debug_port = self._get_free_port()
  34. #co.set_argument(f"--remote-debugging-port={debug_port}")
  35. co.set_user_data_path(f"./account_cache/taobao/{'TB_103'}")
  36. if self.ip:
  37. proxy = self.ip.strip()
  38. if not proxy.startswith(("http://", "https://")):
  39. proxy = f"http://{proxy}"
  40. co.set_argument(f"--proxy-server={proxy}")
  41. self.driver = ChromiumPage(co)
  42. def register_signal_handler(self):
  43. """ 非常必要,注册信号处理,确保状态保存"""
  44. def signal_handler(signum, frame):
  45. print("\n⚠️ 收到退出信号,正在保存状态并退出...")
  46. if self.driver:
  47. self.driver.quit()
  48. sys.exit(0)
  49. signal.signal(signal.SIGINT, signal_handler)
  50. # Windows 上可能不支持 SIGTERM,做兼容处理
  51. if hasattr(signal, "SIGTERM"):
  52. signal.signal(signal.SIGTERM, signal_handler)
  53. # ==================== 人工行为模拟 ====================
  54. def random_wait(self, min_sec, max_sec=None):
  55. """随机等待"""
  56. if max_sec is None:
  57. max_sec = min_sec
  58. time.sleep(random.uniform(min_sec, max_sec))
  59. def move_mouse_to_element(self, element):
  60. """移动鼠标到元素"""
  61. if not element:
  62. return
  63. try:
  64. # 优先使用 DrissionPage 推荐方式
  65. self.driver.actions.move_to(element)
  66. except Exception:
  67. # 兼容旧逻辑:按元素中心点移动(不同版本 move 参数可能不同)
  68. box = element.rect
  69. try:
  70. center_x = int(box.x + box.width / 2)
  71. center_y = int(box.y + box.height / 2)
  72. except Exception:
  73. center_x = int(box["x"] + box["width"] / 2)
  74. center_y = int(box["y"] + box["height"] / 2)
  75. try:
  76. self.driver.actions.move(center_x, center_y)
  77. except TypeError:
  78. # 某些版本仅支持关键字参数
  79. self.driver.actions.move(offset_x=center_x, offset_y=center_y)
  80. self.random_wait(0.2, 0.5)
  81. def human_type(self, element, text):
  82. """模拟人类输入"""
  83. for char in text:
  84. element.send_keys(char)
  85. time.sleep(random.uniform(0.1, 0.3))
  86. def login(self, username, password):
  87. self.driver.get("https://login.taobao.com")
  88. self.random_wait(5, 8)
  89. # 输入账号
  90. login_name = self.driver.ele("xpath=//input[@name='fm-login-id']", timeout=30)
  91. if login_name:
  92. self.move_mouse_to_element(login_name)
  93. self.human_type(login_name, username)
  94. self.random_wait(1, 3)
  95. # 输入密码
  96. login_pass = self.driver.ele("xpath=//input[@name='fm-login-password']", timeout=30)
  97. if login_pass:
  98. self.move_mouse_to_element(login_pass)
  99. self.human_type(login_pass, password)
  100. self.random_wait(1, 3)
  101. # 点击登录
  102. login_button = self.driver.ele("xpath=//button[text()='登录']", timeout=30)
  103. if login_button:
  104. self.move_mouse_to_element(login_button)
  105. login_button.click()
  106. self.random_wait(1, 3)
  107. # 处理同意按钮
  108. login_agree = self.driver.ele("xpath=//button[text()='同意']", timeout=5)
  109. if login_agree:
  110. self.move_mouse_to_element(login_agree)
  111. login_agree.click()
  112. self.random_wait(1, 3)
  113. # 等待登录结果
  114. self.random_wait(10, 20)
  115. # 检查是否登录成功
  116. user_info = self.driver.ele("xpath=//a[@class='site-nav-login-info-nick']", timeout=10)
  117. if user_info:
  118. print("登录成功!")
  119. else:
  120. print("登录失败,请检查账号密码或验证码")
  121. def get_search(self):
  122. url = "https://www.taobao.com"
  123. self.driver.get(url, timeout=30)
  124. time.sleep(20)
  125. time.sleep(random.uniform(3, 8))
  126. # 刷新一次,否则可能未找到登录状态
  127. self.driver.refresh()
  128. self.random_wait(5, 10)
  129. # login_name = self.driver.ele("xpath=//input[@name='fm-login-id']")
  130. # if login_name:
  131. # self.login("aqwwer","wewetrv")
  132. # self.driver.refresh()
  133. # self.random_wait(5, 10)
  134. ele_iframe = self.driver.ele("xpath=//iframe[@id='baxia-dialog-content']")
  135. ele = self.driver.ele('xpath=//*[contains(@class,"site-nav-login-info-nick")]', timeout=30)
  136. if ele:
  137. cookies_list = self.driver.cookies()
  138. cookies_dict = {c['name']: c['value'] for c in cookies_list}
  139. timestamp = int(time.time())
  140. # 保存 cookie 到文件
  141. print(f"{self.account_name},获取 cookie 成功!")
  142. logger.info(f"{self.account_name},获取 cookie 成功!")
  143. self.random_wait(3, 5)
  144. return True
  145. else:
  146. return False
  147. def run(self):
  148. bool_login = False
  149. try:
  150. self.init_drissionpage()
  151. bool_login = self.get_search()
  152. except Exception as e:
  153. logger.exception(f"{self.account_name} 获取 cookie 异常: {e}")
  154. finally:
  155. if self.driver:
  156. return self.driver
  157. return bool(bool_login)
  158. if __name__ == '__main__':
  159. account_name = "tb_account10"
  160. ip = ""
  161. keyword = "手机"
  162. taobao_crawl = TaobaoAutoCrawl(account_name, ip, keyword)
  163. taobao_crawl.run()