post.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import os
  2. import time
  3. import shutil
  4. import logging
  5. import psutil
  6. import subprocess
  7. from selenium import webdriver
  8. from selenium.webdriver.chrome.service import Service
  9. from .post_page import XiaohongshuPostPage
  10. from .post_config import Config
  11. def kill_chrome_processes():
  12. """结束所有Chrome相关进程"""
  13. try:
  14. if os.name == 'nt': # Windows
  15. subprocess.run(['taskkill', '/F', '/IM', 'chrome.exe'], capture_output=True)
  16. subprocess.run(['taskkill', '/F', '/IM', 'chromedriver.exe'], capture_output=True)
  17. else: # Linux/Mac
  18. os.system("pkill -f chrome")
  19. os.system("pkill -f chromedriver")
  20. logging.info("已清理Chrome相关进程")
  21. except Exception as e:
  22. logging.warning(f"清理Chrome进程失败: {str(e)}")
  23. def clean_user_data(if_clean=True):
  24. """清理用户数据目录"""
  25. user_data_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), 'user_data'))
  26. # 检查并清理锁文件
  27. lock_files = ['SingletonLock', 'SingletonCookie', 'SingletonSocket', 'Singleton*']
  28. for lock_file in lock_files:
  29. try:
  30. lock_path = os.path.join(user_data_dir, 'Default', lock_file)
  31. if os.path.exists(lock_path):
  32. os.remove(lock_path)
  33. logging.info(f"已删除锁文件: {lock_path}")
  34. except Exception as e:
  35. logging.warning(f"删除锁文件失败: {str(e)}")
  36. if os.path.exists(user_data_dir) and if_clean:
  37. logging.info(f"清理并创建新用户数据目录: {user_data_dir}")
  38. try:
  39. # 先尝试删除可能导致问题的文件
  40. problem_files = [
  41. os.path.join(user_data_dir, 'Default', 'Preferences'),
  42. os.path.join(user_data_dir, 'Default', 'Network Persistent State'),
  43. os.path.join(user_data_dir, 'Default', 'Network Action Predictor'),
  44. os.path.join(user_data_dir, 'Default', 'History'),
  45. os.path.join(user_data_dir, 'Default', 'History-journal')
  46. ]
  47. for file in problem_files:
  48. if os.path.exists(file):
  49. os.remove(file)
  50. logging.info(f"已删除文件: {file}")
  51. # 如果需要完全清理
  52. if if_clean:
  53. shutil.rmtree(user_data_dir)
  54. os.makedirs(user_data_dir)
  55. logging.info(f"已完全清理用户数据目录: {user_data_dir}")
  56. except Exception as e:
  57. logging.warning(f"清理用户数据目录失败: {str(e)}")
  58. else:
  59. logging.info(f"沿用旧用户数据目录")
  60. # 确保目录存在
  61. os.makedirs(user_data_dir, exist_ok=True)
  62. return user_data_dir
  63. def xiaohonshu_upload(if_clean=False):
  64. """上传图文到小红书"""
  65. driver = None
  66. max_attempts = 3
  67. for attempt in range(max_attempts):
  68. try:
  69. # 清理Chrome进程和用户数据
  70. kill_chrome_processes()
  71. user_data_dir = clean_user_data(if_clean=False)
  72. time.sleep(2) # 等待进程完全结束
  73. logging.info(f"第{attempt + 1}次尝试启动浏览器,用户数据目录: {user_data_dir}")
  74. # 初始化WebDriver
  75. options = webdriver.ChromeOptions()
  76. options.add_argument(f'--user-data-dir={user_data_dir}')
  77. options.add_argument('--profile-directory=Default')
  78. options.add_experimental_option('excludeSwitches', ['enable-automation'])
  79. options.add_experimental_option('useAutomationExtension', False)
  80. options.add_experimental_option("detach", True)
  81. # 添加必要的配置
  82. # options.add_argument('--headless')
  83. options.add_argument('--disable-gpu')
  84. options.add_argument('--no-sandbox')
  85. options.add_argument('--disable-dev-shm-usage')
  86. options.add_argument('--window-size=1920,1080')
  87. options.add_argument('--start-maximized')
  88. options.add_argument('--disable-blink-features=AutomationControlled')
  89. options.add_argument('--disable-extensions')
  90. options.add_argument('--disable-popup-blocking')
  91. options.add_argument('--disable-notifications')
  92. options.add_argument('--remote-debugging-port=0') # 使用随机调试端口
  93. service = Service(Config.CHROME_DRIVER_PATH)
  94. driver = webdriver.Chrome(service=service, options=options)
  95. # 如果成功创建driver,跳出重试循环
  96. break
  97. except Exception as e:
  98. logging.error(f"第{attempt + 1}次启动浏览器失败: {str(e)}")
  99. if driver:
  100. try:
  101. driver.quit()
  102. except:
  103. pass
  104. if attempt == max_attempts - 1:
  105. raise
  106. time.sleep(5) # 等待一段时间后重试
  107. try:
  108. post_page = XiaohongshuPostPage(driver)
  109. post_page.open()
  110. post_page.click_upload_button()
  111. post_page.upload_images(Config._POST_CONFIG['image_paths'])
  112. post_page.input_title(Config._POST_CONFIG['title'])
  113. post_page.input_description(Config._POST_CONFIG['description'], Config._POST_CONFIG['topic'])
  114. post_page.schedule_post(Config._POST_CONFIG['upload_time'])
  115. except Exception as e:
  116. print(f"发生错误: {str(e)}")
  117. driver.save_screenshot("error.png")
  118. raise
  119. finally:
  120. time.sleep(10)
  121. driver.quit()
  122. if __name__ == "__main__":
  123. Config.set_post_config(
  124. image_paths=[r"D:\桌面\研究生\组会\rednote\data\flower.jpg", r"D:\桌面\研究生\组会\rednote\data\test_img.png"],
  125. title="💙被问爆的蓝色仙女裙,美到犯规!",
  126. description="👗宝子们,挖到一条超绝的蓝色长裙!温柔的浅蓝色,仿佛把天空穿在了身上~V领设计巧妙修饰颈部线条,增添了一丝小性感。泡泡袖又带着点复古甜美感,谁穿谁是在逃公主!腰部的设计很贴心,能很好地勾勒出腰线,显得腰细细的~裙摆大大的,走路都带风,氛围感直接拉满!无论是日常出街还是度假穿都超合适,真的会被美到失语,闭眼入不亏~",
  127. topic=["每日穿搭", "今日分享", "蓝色长裙", "仙女裙", "复古甜美", "小性感", "氛围感", "闭眼入不亏"],
  128. upload_time="2025-07-09 10:26"
  129. )
  130. xiaohonshu_upload(if_clean=False)