Showing
6 changed files
with
179 additions
and
7 deletions
| ... | @@ -11,10 +11,11 @@ from uploader.tencent_uploader.main import weixin_setup, TencentVideo | ... | @@ -11,10 +11,11 @@ from uploader.tencent_uploader.main import weixin_setup, TencentVideo |
| 11 | from uploader.tk_uploader.main_chrome import tiktok_setup, TiktokVideo | 11 | from uploader.tk_uploader.main_chrome import tiktok_setup, TiktokVideo |
| 12 | from uploader.xhs_uploader.main import xhs_setup, XHSVideo | 12 | from uploader.xhs_uploader.main import xhs_setup, XHSVideo |
| 13 | from uploader.wyh_uploader.main import wyh_setup | 13 | from uploader.wyh_uploader.main import wyh_setup |
| 14 | +from uploader.sohu_uploader.main import sohu_setup, SOHUVideo | ||
| 14 | from uploader.toutiao_uploader.main import toutiao_setup | 15 | from uploader.toutiao_uploader.main import toutiao_setup |
| 15 | from utils.base_social_media import get_supported_social_media, get_cli_action, SOCIAL_MEDIA_DOUYIN, \ | 16 | from utils.base_social_media import get_supported_social_media, get_cli_action, SOCIAL_MEDIA_DOUYIN, \ |
| 16 | SOCIAL_MEDIA_TENCENT, SOCIAL_MEDIA_TIKTOK, SOCIAL_MEDIA_KUAISHOU, SOCIAL_MEDIA_WANGYIHAO, \ | 17 | SOCIAL_MEDIA_TENCENT, SOCIAL_MEDIA_TIKTOK, SOCIAL_MEDIA_KUAISHOU, SOCIAL_MEDIA_WANGYIHAO, \ |
| 17 | - SOCIAL_MEDIA_XHS, SOCIAL_MEDIA_TOUTIAO, SOCIAL_MEDIA_BAIJIAHAO | 18 | + SOCIAL_MEDIA_XHS, SOCIAL_MEDIA_TOUTIAO, SOCIAL_MEDIA_BAIJIAHAO, SOCIAL_MEDIA_SOHU |
| 18 | from utils.constant import TencentZoneTypes | 19 | from utils.constant import TencentZoneTypes |
| 19 | from utils.files_times import get_title_and_hashtags | 20 | from utils.files_times import get_title_and_hashtags |
| 20 | 21 | ||
| ... | @@ -80,6 +81,8 @@ async def main(): | ... | @@ -80,6 +81,8 @@ async def main(): |
| 80 | await toutiao_setup(str(account_file), handle=True) | 81 | await toutiao_setup(str(account_file), handle=True) |
| 81 | elif args.platform == SOCIAL_MEDIA_BAIJIAHAO: | 82 | elif args.platform == SOCIAL_MEDIA_BAIJIAHAO: |
| 82 | await toutiao_setup(str(account_file), handle=True) | 83 | await toutiao_setup(str(account_file), handle=True) |
| 84 | + elif args.platform == SOCIAL_MEDIA_SOHU: | ||
| 85 | + await sohu_setup(str(account_file), handle=True) | ||
| 83 | 86 | ||
| 84 | elif args.action == 'upload': | 87 | elif args.action == 'upload': |
| 85 | title, tags = get_title_and_hashtags(args.video_file) | 88 | title, tags = get_title_and_hashtags(args.video_file) |
| ... | @@ -108,6 +111,9 @@ async def main(): | ... | @@ -108,6 +111,9 @@ async def main(): |
| 108 | elif args.platform == SOCIAL_MEDIA_XHS: | 111 | elif args.platform == SOCIAL_MEDIA_XHS: |
| 109 | await xhs_setup(account_file, handle=True) | 112 | await xhs_setup(account_file, handle=True) |
| 110 | app = XHSVideo(title, video_file, tags, publish_date, account_file) | 113 | app = XHSVideo(title, video_file, tags, publish_date, account_file) |
| 114 | + elif args.platform == SOCIAL_MEDIA_SOHU: | ||
| 115 | + await sohu_setup(account_file, handle=True) | ||
| 116 | + app = SOHUVideo(title, video_file, tags, None, account_file) | ||
| 111 | else: | 117 | else: |
| 112 | print("Wrong platform, please check your input") | 118 | print("Wrong platform, please check your input") |
| 113 | exit() | 119 | exit() | ... | ... |
uploader/sohu_uploader/__init__.py
0 → 100644
File mode changed
uploader/sohu_uploader/main.py
0 → 100644
| 1 | +# -*- coding: utf-8 -*- | ||
| 2 | +from datetime import datetime | ||
| 3 | + | ||
| 4 | +from playwright.async_api import Playwright, async_playwright | ||
| 5 | +import os | ||
| 6 | +import asyncio | ||
| 7 | +import json | ||
| 8 | +from conf import LOCAL_CHROME_PATH | ||
| 9 | +from utils.base_social_media import set_init_script | ||
| 10 | +from utils.files_times import get_absolute_path | ||
| 11 | +from utils.log import sohu_logger | ||
| 12 | + | ||
| 13 | + | ||
| 14 | +async def cookie_auth(account_file): | ||
| 15 | + async with async_playwright() as playwright: | ||
| 16 | + browser = await playwright.chromium.launch(headless=False) | ||
| 17 | + context = await browser.new_context(storage_state=account_file) | ||
| 18 | + await set_init_script(context) | ||
| 19 | + # context = await browser.new_context() | ||
| 20 | + page = await context.new_page() | ||
| 21 | + # saved_cookies = await read_cookies_from_file(account_file) | ||
| 22 | + # await context.add_cookies(saved_cookies) | ||
| 23 | + try: | ||
| 24 | + await page.goto("https://tv.sohu.com/", timeout=5000) | ||
| 25 | + except: | ||
| 26 | + pass | ||
| 27 | + try: | ||
| 28 | + await page.wait_for_selector("div.user-ico", timeout=5000) # 等待5秒 | ||
| 29 | + sohu_logger.success("[+] cookie 有效") | ||
| 30 | + return True | ||
| 31 | + except: | ||
| 32 | + sohu_logger.info("[+] 等待5秒 cookie 失效") | ||
| 33 | + return False | ||
| 34 | + | ||
| 35 | + | ||
| 36 | +async def sohu_setup(account_file, handle=False): | ||
| 37 | + account_file = get_absolute_path(account_file, "sohu_uploader") | ||
| 38 | + if not os.path.exists(account_file) or not await cookie_auth(account_file): | ||
| 39 | + if not handle: | ||
| 40 | + return False | ||
| 41 | + sohu_logger.info('[+] cookie文件不存在或已失效,即将自动打开浏览器,请扫码登录,登陆后会自动生成cookie文件') | ||
| 42 | + await get_sohu_cookie(account_file) | ||
| 43 | + return True | ||
| 44 | + | ||
| 45 | + | ||
| 46 | +async def get_sohu_cookie(account_file): | ||
| 47 | + async with async_playwright() as playwright: | ||
| 48 | + options = { | ||
| 49 | + 'args': [ | ||
| 50 | + '--lang en-GB' | ||
| 51 | + ], | ||
| 52 | + 'headless': False, # Set headless option here | ||
| 53 | + } | ||
| 54 | + # Make sure to run headed. | ||
| 55 | + browser = await playwright.chromium.launch(**options) | ||
| 56 | + # Setup context however you like. | ||
| 57 | + context = await browser.new_context() # Pass any options | ||
| 58 | + context = await set_init_script(context) | ||
| 59 | + # Pause the page, and start recording manually. | ||
| 60 | + page = await context.new_page() | ||
| 61 | + try: | ||
| 62 | + await page.goto("https://tv.sohu.com/", timeout=5000) | ||
| 63 | + except: | ||
| 64 | + pass | ||
| 65 | + await asyncio.sleep(1) | ||
| 66 | + await page.wait_for_selector("div.user-ico", timeout=50000) | ||
| 67 | + sohu_logger.info("搜狐视频登录成功") | ||
| 68 | + await asyncio.sleep(3) | ||
| 69 | + | ||
| 70 | + # await page.pause() | ||
| 71 | + # 点击调试器的继续,保存cookie | ||
| 72 | + # cookies = await context.cookies() | ||
| 73 | + # await write_cookies_to_file(cookies, account_file) | ||
| 74 | + await context.storage_state(path=account_file) | ||
| 75 | + | ||
| 76 | + | ||
| 77 | +class SOHUVideo(object): | ||
| 78 | + def __init__(self, title, file_path, tags, publish_date: datetime, account_file): | ||
| 79 | + self.title = title # 视频标题 | ||
| 80 | + self.file_path = file_path | ||
| 81 | + self.tags = tags | ||
| 82 | + self.publish_date = publish_date | ||
| 83 | + self.account_file = account_file | ||
| 84 | + self.date_format = '%Y-%m-%d %H:%M' | ||
| 85 | + self.local_executable_path = LOCAL_CHROME_PATH | ||
| 86 | + | ||
| 87 | + async def handle_upload_error(self, page): | ||
| 88 | + pass | ||
| 89 | + # sohu_logger.error("视频出错了,重新上传中") | ||
| 90 | + # await page.locator('div.progress-div [class^="upload-btn-input"]').set_input_files(self.file_path) | ||
| 91 | + | ||
| 92 | + async def upload(self, playwright: Playwright) -> None: | ||
| 93 | + # 使用 Chromium 浏览器启动一个浏览器实例 | ||
| 94 | + if self.local_executable_path: | ||
| 95 | + browser = await playwright.chromium.launch( | ||
| 96 | + headless=False, | ||
| 97 | + executable_path=self.local_executable_path, | ||
| 98 | + ) | ||
| 99 | + else: | ||
| 100 | + browser = await playwright.chromium.launch( | ||
| 101 | + headless=False | ||
| 102 | + ) # 创建一个浏览器上下文,使用指定的 cookie 文件 | ||
| 103 | + context = await browser.new_context(storage_state=self.account_file) | ||
| 104 | + page = await context.new_page() | ||
| 105 | + # saved_cookies = await read_cookies_from_file(self.account_file) | ||
| 106 | + # await context.add_cookies(saved_cookies) | ||
| 107 | + # context = await set_init_script(context) | ||
| 108 | + # context.on("close", lambda: ) | ||
| 109 | + | ||
| 110 | + # 创建一个新的页面 | ||
| 111 | + # 访问指定的 URL | ||
| 112 | + try: | ||
| 113 | + await page.goto("https://tv.sohu.com/s/center/index.html#/", timeout=5000) | ||
| 114 | + except: | ||
| 115 | + pass | ||
| 116 | + sohu_logger.info('正在上传-------{}.mp4'.format(self.title)) | ||
| 117 | + # 等待页面跳转到指定的 URL,没进入,则自动等待到超时 | ||
| 118 | + # 点击 "上传视频" 按钮 | ||
| 119 | + | ||
| 120 | + # await page.locator("dev.release-top").set_input_files( | ||
| 121 | + # self.file_path) | ||
| 122 | + await page.locator("input[type='file']").set_input_files( | ||
| 123 | + self.file_path) | ||
| 124 | + | ||
| 125 | + upload_button = page.locator('div.form-button span:has-text("发布")') | ||
| 126 | + await upload_button.wait_for(state='visible') # 确保按钮可见 | ||
| 127 | + await asyncio.sleep(1) | ||
| 128 | + | ||
| 129 | + sohu_logger.info("正在填充标题...") | ||
| 130 | + await page.locator("input.input-topic").nth(0).fill(self.title[:99]) # 搜狐最多100 | ||
| 131 | + await asyncio.sleep(1) | ||
| 132 | + sohu_logger.info("正在填充话题...") | ||
| 133 | + inputTag = page.locator("input.input-topic").nth(1) | ||
| 134 | + await inputTag.click() | ||
| 135 | + for index, tag in enumerate(self.tags[:2], start=1): | ||
| 136 | + await page.keyboard.type(f"#{tag}") | ||
| 137 | + await page.keyboard.press("Enter") | ||
| 138 | + | ||
| 139 | + | ||
| 140 | + sohu_logger.info("已写完tag") | ||
| 141 | + await asyncio.sleep(1) | ||
| 142 | + | ||
| 143 | + sohu_logger.info(self.publish_date) | ||
| 144 | + # 定时任务 搜狐没有定时发布 | ||
| 145 | + # if self.publish_date != 0: | ||
| 146 | + # await self.set_schedule_time(page, self.publish_date) | ||
| 147 | + # upload_button = page.locator('button div span:has-text("定时发布")') | ||
| 148 | + sohu_logger.info("提交") | ||
| 149 | + await upload_button.click() | ||
| 150 | + await page.wait_for_selector('h3:has-text("视频管理")') | ||
| 151 | + await context.storage_state(path=self.account_file) | ||
| 152 | + sohu_logger.info('cookie更新完毕!') | ||
| 153 | + await asyncio.sleep(4) # 这里延迟是为了方便眼睛直观的观看 | ||
| 154 | + # 关闭浏览器上下文和浏览器实例 | ||
| 155 | + await context.close() | ||
| 156 | + await browser.close() | ||
| 157 | + | ||
| 158 | + async def main(self): | ||
| 159 | + async with async_playwright() as playwright: | ||
| 160 | + await self.upload(playwright) | ||
| 161 | + | ||
| 162 | + |
| ... | @@ -90,8 +90,7 @@ class XHSVideo(object): | ... | @@ -90,8 +90,7 @@ class XHSVideo(object): |
| 90 | self.local_executable_path = LOCAL_CHROME_PATH | 90 | self.local_executable_path = LOCAL_CHROME_PATH |
| 91 | 91 | ||
| 92 | async def handle_upload_error(self, page): | 92 | async def handle_upload_error(self, page): |
| 93 | - xhs_logger.error("视频出错了,重新上传中") | 93 | + pass |
| 94 | - await page.locator('div.progress-div [class^="upload-btn-input"]').set_input_files(self.file_path) | ||
| 95 | 94 | ||
| 96 | async def upload(self, playwright: Playwright) -> None: | 95 | async def upload(self, playwright: Playwright) -> None: |
| 97 | # 使用 Chromium 浏览器启动一个浏览器实例 | 96 | # 使用 Chromium 浏览器启动一个浏览器实例 |
| ... | @@ -131,8 +130,10 @@ class XHSVideo(object): | ... | @@ -131,8 +130,10 @@ class XHSVideo(object): |
| 131 | inputTag = page.locator('id=quillEditor').locator('div p') | 130 | inputTag = page.locator('id=quillEditor').locator('div p') |
| 132 | await inputTag.click() | 131 | await inputTag.click() |
| 133 | for index, tag in enumerate(self.tags, start=1): | 132 | for index, tag in enumerate(self.tags, start=1): |
| 134 | - await page.keyboard.type(f"#{tag} ") | 133 | + await page.keyboard.type(f"#{tag}") |
| 135 | - await asyncio.sleep(2) | 134 | + await page.wait_for_selector("ul.ql-mention-list") |
| 135 | + await page.keyboard.press("Enter") | ||
| 136 | + | ||
| 136 | 137 | ||
| 137 | xhs_logger.info("已写完tag") | 138 | xhs_logger.info("已写完tag") |
| 138 | await asyncio.sleep(1) | 139 | await asyncio.sleep(1) | ... | ... |
| ... | @@ -9,14 +9,16 @@ SOCIAL_MEDIA_TIKTOK = "tiktok" | ... | @@ -9,14 +9,16 @@ SOCIAL_MEDIA_TIKTOK = "tiktok" |
| 9 | SOCIAL_MEDIA_BILIBILI = "bilibili" | 9 | SOCIAL_MEDIA_BILIBILI = "bilibili" |
| 10 | SOCIAL_MEDIA_KUAISHOU = "kuaishou" | 10 | SOCIAL_MEDIA_KUAISHOU = "kuaishou" |
| 11 | SOCIAL_MEDIA_WANGYIHAO = 'wangyihao' | 11 | SOCIAL_MEDIA_WANGYIHAO = 'wangyihao' |
| 12 | -SOCIAL_MEDIA_XHS = 'xiaohongshu' | 12 | +SOCIAL_MEDIA_XHS = 'xiaohongshu' # 小红书最长标题是20 |
| 13 | SOCIAL_MEDIA_TOUTIAO = 'toutiao' | 13 | SOCIAL_MEDIA_TOUTIAO = 'toutiao' |
| 14 | SOCIAL_MEDIA_BAIJIAHAO = 'baijiahao' | 14 | SOCIAL_MEDIA_BAIJIAHAO = 'baijiahao' |
| 15 | +SOCIAL_MEDIA_SOHU = 'sohu' # 搜狐视频话题最多2个 标题最多100 标题不支持🩹 | ||
| 15 | 16 | ||
| 16 | 17 | ||
| 17 | def get_supported_social_media() -> List[str]: | 18 | def get_supported_social_media() -> List[str]: |
| 18 | return [SOCIAL_MEDIA_DOUYIN, SOCIAL_MEDIA_TENCENT, SOCIAL_MEDIA_TIKTOK, SOCIAL_MEDIA_KUAISHOU, | 19 | return [SOCIAL_MEDIA_DOUYIN, SOCIAL_MEDIA_TENCENT, SOCIAL_MEDIA_TIKTOK, SOCIAL_MEDIA_KUAISHOU, |
| 19 | - SOCIAL_MEDIA_WANGYIHAO, SOCIAL_MEDIA_TOUTIAO, SOCIAL_MEDIA_BAIJIAHAO, SOCIAL_MEDIA_XHS] | 20 | + SOCIAL_MEDIA_WANGYIHAO, SOCIAL_MEDIA_TOUTIAO, SOCIAL_MEDIA_BAIJIAHAO, SOCIAL_MEDIA_XHS, |
| 21 | + SOCIAL_MEDIA_SOHU] | ||
| 20 | 22 | ||
| 21 | 23 | ||
| 22 | def get_cli_action() -> List[str]: | 24 | def get_cli_action() -> List[str]: | ... | ... |
| ... | @@ -46,6 +46,7 @@ logger.add(stdout, colorize=True, format=log_formatter) | ... | @@ -46,6 +46,7 @@ logger.add(stdout, colorize=True, format=log_formatter) |
| 46 | douyin_logger = create_logger('douyin', 'logs/douyin.log') | 46 | douyin_logger = create_logger('douyin', 'logs/douyin.log') |
| 47 | tencent_logger = create_logger('tencent', 'logs/tencent.log') | 47 | tencent_logger = create_logger('tencent', 'logs/tencent.log') |
| 48 | xhs_logger = create_logger('xhs', 'logs/xhs.log') | 48 | xhs_logger = create_logger('xhs', 'logs/xhs.log') |
| 49 | +sohu_logger = create_logger('sohu', 'logs/sohu.log') | ||
| 49 | tiktok_logger = create_logger('tiktok', 'logs/tiktok.log') | 50 | tiktok_logger = create_logger('tiktok', 'logs/tiktok.log') |
| 50 | bilibili_logger = create_logger('bilibili', 'logs/bilibili.log') | 51 | bilibili_logger = create_logger('bilibili', 'logs/bilibili.log') |
| 51 | kuaishou_logger = create_logger('kuaishou', 'logs/kuaishou.log') | 52 | kuaishou_logger = create_logger('kuaishou', 'logs/kuaishou.log') | ... | ... |
-
Please register or login to post a comment