| | |
| | | # -*- coding: utf-8 -*- |
| | | from playwright.async_api import Playwright, Page |
| | | import asyncio |
| | | import random |
| | | import datetime |
| | | |
| | | from auto_media_publisher.uploaders.uploader_base import UploaderBase |
| | | |
| | |
| | | |
| | | |
| | | class UploaderBaijiahao(UploaderBase): |
| | | |
| | | |
| | | |
| | | async def virtual_scroll_select(self,page,text, wrapper_index = 0,panel_selector="div.rc-virtual-list-holder-inner", |
| | | item_selector_template='div.cheetah-select-item-option-content:has-text("{text}")', |
| | | step=200, # 每次滚动像素 |
| | | max_attempts=15, |
| | | direction="down" # "down" 或 "up" |
| | | ): |
| | | await page.locator('div.select-wrap').nth(wrapper_index).click() |
| | | await asyncio.sleep(1) |
| | | |
| | | panel = page.locator(panel_selector).nth(wrapper_index) |
| | | item_selector = item_selector_template.format(text=text) |
| | | |
| | | |
| | | for i in range(max_attempts): |
| | | # 尝试查找 |
| | | items = page.locator(item_selector) |
| | | if await items.count() > 0: |
| | | # 找到了,滚下去保证可见,再点击 |
| | | await items.first.scroll_into_view_if_needed() |
| | | await items.first.click() |
| | | return |
| | | |
| | | # 没找到就滚一轮 |
| | | delta = step if direction == "down" else -step |
| | | await panel.evaluate(f"(el) => el.scrollTop += {delta}") |
| | | await asyncio.sleep(0.2) |
| | | await asyncio.sleep(1) |
| | | |
| | | |
| | | async def set_schedule_time(self, page): |
| | | """ |
| | | TODO 时间选择,日后在处理 百家号的时间选择不准确,目前是随机 |
| | | """ |
| | | publish_datetime_day = f"{self.publish_datetime.month}月{self.publish_datetime.day}日" if self.publish_datetime.day >9 else f"{self.publish_datetime.month}月0{self.publish_datetime.day}日" |
| | | publish_datetime_hour = f"{self.publish_datetime.hour}点" |
| | | publish_datetime_min = f"{self.publish_datetime.minute}分" |
| | | scheduled_time_day = f"{self.scheduled_time.month}月{self.scheduled_time.day}日" if self.scheduled_time.day >9 else f"{self.scheduled_time.month}月0{self.scheduled_time.day}日" |
| | | scheduled_time_hour = f"{self.scheduled_time.hour}点" |
| | | scheduled_time_min = f"{self.scheduled_time.minute}分" |
| | | await page.locator("div.cheetah-modal-confirm-body-wrapper").wait_for(state='visible',timeout=30000) |
| | | |
| | | current_hour = datetime.datetime.now().hour |
| | | current_min = datetime.datetime.now().minute |
| | | direction_hour = "down" if self.scheduled_time.hour > current_hour else "up" |
| | | direction_minute = "down" if self.scheduled_time.minute > current_min else "up" |
| | | |
| | | print(direction_hour) |
| | | print(dir) |
| | | |
| | | |
| | | try: |
| | | await page.locator('div.select-wrap').nth(0).click() |
| | | await asyncio.sleep(1) |
| | | target = page.locator(f'div[title="{publish_datetime_day}"]') |
| | | await target.wait_for(state='visible') |
| | | target = page.locator(f'div[title="{scheduled_time_day}"]') |
| | | #await target.wait_for(state='visible') |
| | | await target.click() |
| | | await asyncio.sleep(1) |
| | | await page.locator('div.select-wrap').nth(1).click() |
| | | await asyncio.sleep(1) |
| | | target = page.locator(f'div.cheetah-select-item-option-content:has-text("{publish_datetime_hour}")') |
| | | await target.wait_for(state='visible') |
| | | await target.click() |
| | | await asyncio.sleep(1) |
| | | await page.locator('div.select-wrap').nth(2).click() |
| | | await asyncio.sleep(1) |
| | | target = page.locator(f'div.cheetah-select-item-option-content:has-text("{publish_datetime_min}")') |
| | | await target.wait_for(state='visible') |
| | | await target.click() |
| | | await asyncio.sleep(1) |
| | | await self.virtual_scroll_select(page,scheduled_time_hour,wrapper_index=1,direction=direction_hour) |
| | | await self.virtual_scroll_select(page,scheduled_time_min,wrapper_index=2,direction=direction_minute) |
| | | #await page.locator('div.select-wrap').nth(2).click() |
| | | #await asyncio.sleep(1) |
| | | #target = page.locator(f'div.cheetah-select-item-option-content:has-text("{scheduled_time_min}")') |
| | | #await target.wait_for(state='visible') |
| | | #await target.scroll_into_view_if_needed() |
| | | #await target.click() |
| | | #await asyncio.sleep(1) |
| | | |
| | | except Exception as e: |
| | | self.logger.error(f"[Baidu BaiJiaHao] 设置时间发生错误.{e}") |
| | | |
| | | await page.locator("div.cheetah-modal-confirm-btns > button").nth(1).click() |
| | | #await page.locator("div.cheetah-modal-confirm-btns > button").nth(1).click() |
| | | |
| | | async def handle_upload_error(self, page): |
| | | # 日后实现,目前没遇到 |
| | |
| | | raise # 重新抛出异常,让重试装饰器捕获 |
| | | |
| | | async def publish_video(self, page: Page): |
| | | if self.publish_datetime != 0: |
| | | if self.scheduled_time != 0: |
| | | # 定时发布 |
| | | await self.set_schedule_publish(page) |
| | | else: |
| | |
| | | |
| | | page = await self.context.new_page() |
| | | await page.goto(CONTENT_UPLOAD_URL, timeout=120000) |
| | | self.logger.info(f"正在上传-------{self.path_video}") |
| | | self.logger.info(f"正在上传-------{self.path_media}") |
| | | await page.wait_for_url(CONTENT_UPLOAD_URL, timeout=120000) |
| | | |
| | | # 点击 "上传视频" 按钮 |
| | | await page.locator("div[class^='video-main-page'] input").set_input_files(self.path_video) |
| | | upload_div = page.locator(".PL3VsCg3MxIPY5UYiCS_") |
| | | await upload_div.wait_for(state="visible", timeout=10000) |
| | | async with page.expect_file_chooser() as fc_info: |
| | | await upload_div.click() |
| | | file_chooser = await fc_info.value |
| | | await file_chooser.set_files(self.path_media) |
| | | await asyncio.sleep(2) |
| | | |
| | | # 等待页面跳转到指定的 URL |
| | | while True: |
| | | # 判断是是否进入视频发布页面,没进入,则自动等待到超时 |
| | | for i in range(10): |
| | | try: |
| | | await page.locator("div#formMain:visible").wait_for(timeout=30000) |
| | | break |
| | | except: |
| | | self.logger.info("正在等待进入视频发布页面...") |
| | | self.logger.info(f"第 {i+1} 次尝试:正在等待进入视频发布页面...") |
| | | await asyncio.sleep(0.1) |
| | | else: |
| | | self.logger.warning("超过最大尝试次数,仍未进入视频发布页面。") |
| | | |
| | | # 填充标题和话题 |
| | | # 这里为了避免页面变化,故使用相对位置定位:作品标题父级右侧第一个元素的input子元素 |
| | |
| | | |
| | | upload_status = await self.uploading_video(page) |
| | | if not upload_status: |
| | | self.logger.error(f"发现上传出错了... 文件:{self.path_video}") |
| | | self.logger.error(f"发现上传出错了... 文件:{self.path_media}") |
| | | raise |
| | | |
| | | # 判断视频封面图是否生成成功 |
| | | while True: |
| | | self.logger.info("正在确认封面完成, 准备去点击定时/发布...") |
| | | if await page.locator("div.cheetah-spin-page img").count(): |
| | | if await page.locator("div.erVanTLKMOvnU7OgFaoD img").count(): |
| | | self.logger.info("封面已完成,点击定时/发布...") |
| | | break |
| | | else: |
| | |
| | | |
| | | return True |
| | | except Exception as e: |
| | | self.logger.error(f"{self.user} upload video {self.path_video} fails, error is :{e}") |
| | | self.logger.error(f"{self.user} upload video {self.path_media} fails, error is :{e}") |
| | | return False |