| 1 | # -*- coding: utf-8 -*- |
| 2 | import random |
| 3 | from datetime import datetime |
| 4 | |
| 5 | from playwright.async_api import Playwright, async_playwright, Page |
| 6 | import os |
| 7 | import time |
| 8 | import asyncio |
| 9 | |
| 10 | from conf import LOCAL_CHROME_PATH, LOCAL_CHROME_HEADLESS |
| 11 | from utils.base_social_media import set_init_script |
| 12 | from utils.log import baijiahao_logger |
| 13 | from utils.network import async_retry |
| 14 | |
| 15 | |
| 16 | async def baijiahao_cookie_gen(account_file): |
| 17 | async with async_playwright() as playwright: |
| 18 | options = { |
| 19 | 'args': [ |
| 20 | '--lang en-GB' |
| 21 | ], |
| 22 | 'headless': LOCAL_CHROME_HEADLESS, # Set headless option here |
| 23 | } |
| 24 | # Make sure to run headed. |
| 25 | browser = await playwright.chromium.launch(**options) |
| 26 | # Setup context however you like. |
| 27 | context = await browser.new_context() # Pass any options |
| 28 | context = await set_init_script(context) |
| 29 | # Pause the page, and start recording manually. |
| 30 | page = await context.new_page() |
| 31 | await page.goto("https://baijiahao.baidu.com/builder/theme/bjh/login") |
| 32 | await page.pause() |
| 33 | # 点击调试器的继续,保存cookie |
| 34 | await context.storage_state(path=account_file) |
| 35 | baijiahao_logger.success("cookie saved") |
| 36 | |
| 37 | |
| 38 | async def cookie_auth(account_file): |
| 39 | async with async_playwright() as playwright: |
| 40 | browser = await playwright.chromium.launch(headless=LOCAL_CHROME_HEADLESS) |
| 41 | context = await browser.new_context(storage_state=account_file) |
| 42 | context = await set_init_script(context) |
| 43 | # 创建一个新的页面 |
| 44 | page = await context.new_page() |
| 45 | # 访问指定的 URL |
| 46 | await page.goto("https://baijiahao.baidu.com/builder/rc/home") |
| 47 | await page.wait_for_timeout(timeout=5000) |
| 48 | |
| 49 | if await page.get_by_text('注册/登录百家号').count(): |
| 50 | baijiahao_logger.error("等待5秒 cookie 失效") |
| 51 | return False |
| 52 | else: |
| 53 | baijiahao_logger.success("[+] cookie 有效") |
| 54 | return True |
| 55 | |
| 56 | |
| 57 | async def baijiahao_setup(account_file, handle=False): |
| 58 | if not os.path.exists(account_file) or not await cookie_auth(account_file): |
| 59 | if not handle: |
| 60 | return False |
| 61 | baijiahao_logger.error("cookie文件不存在或已失效,即将自动打开浏览器,请扫码登录,登陆后会自动生成cookie文件") |
| 62 | await baijiahao_cookie_gen(account_file) |
| 63 | return True |
| 64 | |
| 65 | class BaiJiaHaoVideo(object): |
| 66 | def __init__(self, title, file_path, tags, publish_date: datetime, account_file, proxy_setting=None): |
| 67 | self.title = title # 视频标题 |
| 68 | self.file_path = file_path |
| 69 | self.tags = tags |
| 70 | self.publish_date = publish_date |
| 71 | self.account_file = account_file |
| 72 | self.date_format = '%Y年%m月%d日 %H:%M' |
| 73 | self.local_executable_path = LOCAL_CHROME_PATH |
| 74 | self.headless = LOCAL_CHROME_HEADLESS |
| 75 | self.proxy_setting = proxy_setting |
| 76 | |
| 77 | async def set_schedule_time(self, page, publish_date): |
| 78 | """ |
| 79 | todo 时间选择,日后在处理 百家号的时间选择不准确,目前是随机 |
| 80 | """ |
| 81 | publish_date_day = f"{publish_date.month}月{publish_date.day}日" if publish_date.day >9 else f"{publish_date.month}月0{publish_date.day}日" |
| 82 | publish_date_hour = f"{publish_date.hour}点" |
| 83 | publish_date_min = f"{publish_date.minute}分" |
| 84 | await page.wait_for_selector('div.select-wrap', timeout=5000) |
| 85 | for _ in range(3): |
| 86 | try: |
| 87 | await page.locator('div.select-wrap').nth(0).click() |
| 88 | await page.wait_for_selector('div.rc-virtual-list div.cheetah-select-item', timeout=5000) |
| 89 | break |
| 90 | except: |
| 91 | await page.locator('div.select-wrap').nth(0).click() |
| 92 | # page.locator(f'div.rc-virtual-list-holder-inner >> text={publish_date_day}').click() |
| 93 | await page.wait_for_timeout(2000) |
| 94 | await page.locator(f'div.rc-virtual-list div.cheetah-select-item >> text={publish_date_day}').click() |
| 95 | await page.wait_for_timeout(2000) |
| 96 | |
| 97 | # 改为随机点击一个 hour |
| 98 | for _ in range(3): |
| 99 | try: |
| 100 | await page.locator('div.select-wrap').nth(1).click() |
| 101 | await page.wait_for_selector('div.rc-virtual-list div.rc-virtual-list-holder-inner:visible', timeout=5000) |
| 102 | break |
| 103 | except: |
| 104 | await page.locator('div.select-wrap').nth(1).click() |
| 105 | await page.wait_for_timeout(2000) |
| 106 | current_choice_hour = await page.locator('div.rc-virtual-list:visible div.cheetah-select-item-option').count() |
| 107 | await page.wait_for_timeout(2000) |
| 108 | await page.locator('div.rc-virtual-list:visible div.cheetah-select-item-option').nth( |
| 109 | random.randint(1, current_choice_hour-3)).click() |
| 110 | # 2024.08.05 current_choice_hour的获取可能有问题,页面有7,这里获取了10,暂时硬编码至6 |
| 111 | |
| 112 | await page.wait_for_timeout(2000) |
| 113 | await page.locator("button >> text=定时发布").click() |
| 114 | |
| 115 | |
| 116 | async def handle_upload_error(self, page): |
| 117 | # 日后实现,目前没遇到 |
| 118 | return |
| 119 | print("视频出错了,重新上传中") |
| 120 | |
| 121 | async def upload(self, playwright: Playwright) -> None: |
| 122 | # 使用 Chromium 浏览器启动一个浏览器实例 |
| 123 | browser = await playwright.chromium.launch(headless=self.headless, executable_path=self.local_executable_path, proxy=self.proxy_setting) |
| 124 | # 创建一个浏览器上下文,使用指定的 cookie 文件 |
| 125 | context = await browser.new_context(storage_state=f"{self.account_file}", user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.4324.150 Safari/537.36') |
| 126 | # context = await set_init_script(context) |
| 127 | await context.grant_permissions(['geolocation']) |
| 128 | |
| 129 | # 创建一个新的页面 |
| 130 | page = await context.new_page() |
| 131 | # 访问指定的 URL |
| 132 | await page.goto("https://baijiahao.baidu.com/builder/rc/edit?type=videoV2", timeout=60000) |
| 133 | baijiahao_logger.info(f"正在上传-------{self.title}.mp4") |
| 134 | # 等待页面跳转到指定的 URL,没进入,则自动等待到超时 |
| 135 | baijiahao_logger.info('正在打开主页...') |
| 136 | await page.wait_for_url("https://baijiahao.baidu.com/builder/rc/edit?type=videoV2", timeout=60000) |
| 137 | |
| 138 | # 点击 "上传视频" 按钮 |
| 139 | await page.locator("div[class^='video-main-container'] input").set_input_files(self.file_path) |
| 140 | |
| 141 | # 等待页面跳转到指定的 URL |
| 142 | while True: |
| 143 | # 判断是是否进入视频发布页面,没进入,则自动等待到超时 |
| 144 | try: |
| 145 | await page.wait_for_selector("div#formMain:visible") |
| 146 | break |
| 147 | except: |
| 148 | baijiahao_logger.info("正在等待进入视频发布页面...") |
| 149 | await asyncio.sleep(0.1) |
| 150 | |
| 151 | # 填充标题和话题 |
| 152 | # 这里为了避免页面变化,故使用相对位置定位:作品标题父级右侧第一个元素的input子元素 |
| 153 | await asyncio.sleep(1) |
| 154 | baijiahao_logger.info("正在填充标题和话题...") |
| 155 | await self.add_title_tags(page) |
| 156 | |
| 157 | upload_status = await self.uploading_video(page) |
| 158 | if not upload_status: |
| 159 | baijiahao_logger.error(f"发现上传出错了... 文件:{self.file_path}") |
| 160 | raise |
| 161 | |
| 162 | # 判断视频封面图是否生成成功 |
| 163 | while True: |
| 164 | baijiahao_logger.info("正在确认封面完成, 准备去点击定时/发布...") |
| 165 | if await page.locator("div.cheetah-spin-container img").count(): |
| 166 | baijiahao_logger.info("封面已完成,点击定时/发布...") |
| 167 | break |
| 168 | else: |
| 169 | baijiahao_logger.info("等待封面生成...") |
| 170 | await asyncio.sleep(3) |
| 171 | |
| 172 | await self.publish_video(page, self.publish_date) |
| 173 | await page.wait_for_timeout(2000) |
| 174 | if await page.locator('div.passMod_dialog-container >> text=百度安全验证:visible').count(): |
| 175 | baijiahao_logger.error("出现验证,退出") |
| 176 | raise Exception("出现验证,退出") |
| 177 | await page.wait_for_url("https://baijiahao.baidu.com/builder/rc/clue**", timeout=5000) |
| 178 | baijiahao_logger.success("视频发布成功") |
| 179 | |
| 180 | await context.storage_state(path=self.account_file) # 保存cookie |
| 181 | baijiahao_logger.info('cookie更新完毕!') |
| 182 | await asyncio.sleep(2) # 这里延迟是为了方便眼睛直观的观看 |
| 183 | # 关闭浏览器上下文和浏览器实例 |
| 184 | await context.close() |
| 185 | await browser.close() |
| 186 | |
| 187 | |
| 188 | @async_retry(timeout=300) # 例如,最多重试3次,超时时间为180秒 |
| 189 | async def uploading_video(self, page): |
| 190 | while True: |
| 191 | upload_failed = await page.locator('div .cover-overlay:has-text("上传失败")').count() |
| 192 | if upload_failed: |
| 193 | baijiahao_logger.error("发现上传出错了...") |
| 194 | # await self.handle_upload_error(page) # 假设这是处理上传错误的函数 |
| 195 | return False |
| 196 | |
| 197 | uploading = await page.locator('div .cover-overlay:has-text("上传中")').count() |
| 198 | if uploading: |
| 199 | baijiahao_logger.info("正在上传视频中...") |
| 200 | await asyncio.sleep(2) # 等待2秒再次检查 |
| 201 | continue |
| 202 | |
| 203 | # 检查上传是否成功 |
| 204 | if not uploading and not upload_failed: |
| 205 | baijiahao_logger.success("视频上传完毕") |
| 206 | return True |
| 207 | |
| 208 | async def set_schedule_publish(self, page, publish_date): |
| 209 | while True: |
| 210 | schedule_element = page.locator("div.op-btn-outter-content >> text=定时发布").locator("..").locator( |
| 211 | 'button') |
| 212 | try: |
| 213 | await schedule_element.click() |
| 214 | await page.wait_for_selector('div.select-wrap:visible', timeout=3000) |
| 215 | await page.wait_for_timeout(timeout=2000) |
| 216 | baijiahao_logger.info("开始点击发布定时...") |
| 217 | await self.set_schedule_time(page, publish_date) |
| 218 | break |
| 219 | except Exception as e: |
| 220 | baijiahao_logger.error(f"定时发布失败: {e}") |
| 221 | raise # 重新抛出异常,让重试装饰器捕获 |
| 222 | |
| 223 | @async_retry(timeout=300) # 例如,最多重试3次,超时时间为180秒 |
| 224 | async def publish_video(self, page: Page, publish_date): |
| 225 | if publish_date != 0: |
| 226 | # 定时发布 |
| 227 | await self.set_schedule_publish(page, publish_date) |
| 228 | else: |
| 229 | # 立即发布 |
| 230 | await self.direct_publish(page) |
| 231 | |
| 232 | async def direct_publish(self, page): |
| 233 | try: |
| 234 | publish_button = page.locator("button >> text=发布") |
| 235 | if await publish_button.count(): |
| 236 | await publish_button.click() |
| 237 | except Exception as e: |
| 238 | baijiahao_logger.error(f"直接发布视频失败: {e}") |
| 239 | raise # 重新抛出异常,让重试装饰器捕获 |
| 240 | |
| 241 | async def add_title_tags(self, page): |
| 242 | title_container = page.get_by_placeholder('添加标题获得更多推荐') |
| 243 | if len(self.title) <= 8: |
| 244 | self.title += " 你不知道的" |
| 245 | await title_container.fill(self.title[:30]) |
| 246 | |
| 247 | async def main(self): |
| 248 | async with async_playwright() as playwright: |
| 249 | await self.upload(playwright) |
| 250 | |
| 251 | |
| 252 | |
| 253 | # 使用 AI成片 功能 |
| 254 | async def ai2video(self, playwright: Playwright) -> None: |
| 255 | # 使用 Chromium 浏览器启动一个浏览器实例 |
| 256 | browser = await playwright.chromium.launch(headless=self.headless, executable_path=self.local_executable_path, proxy=self.proxy_setting) |
| 257 | # 创建一个浏览器上下文,使用指定的 cookie 文件 |
| 258 | context = await browser.new_context( |
| 259 | viewport={"width": 1600, "height": 900}, |
| 260 | storage_state=f"{self.account_file}", |
| 261 | user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.4324.150 Safari/537.36' |
| 262 | ) |
| 263 | # context = await set_init_script(context) |
| 264 | await context.grant_permissions(['geolocation']) |
| 265 | |
| 266 | # 创建一个新的页面 |
| 267 | page = await context.new_page() |
| 268 | # 访问指定的 URL |
| 269 | await page.goto("https://aigc.baidu.com/make", timeout=60000) |
| 270 | # 等待页面跳转到指定的 URL,没进入,则自动等待到超时 |
| 271 | baijiahao_logger.info('正在打开主页...') |
| 272 | await page.wait_for_url("https://aigc.baidu.com/make", timeout=60000) |
| 273 | |
| 274 | # 点击"全网"标签 |
| 275 | await page.locator('div.rounded-lg.border:has-text("全网")').click() |
| 276 | await asyncio.sleep(1) # 这里延迟是为了方便眼睛直观的观看 |
| 277 | |
| 278 | # 点击 "上传视频" 按钮 |
| 279 | # await page.locator("div[class^='video-main-container'] input").set_input_files(self.file_path) |
| 280 | |
| 281 | # region 操作处 |
| 282 | |
| 283 | # 生成日期时间键名(格式:ai2video_YYYYMMDDHHMM) |
| 284 | now = datetime.now() |
| 285 | datetime_str = now.strftime("%Y%m%d%H%M") |
| 286 | processed_key = "ai2video_processed_titles" |
| 287 | batch_key = f"ai2video_{datetime_str}" |
| 288 | |
| 289 | # 初始化LocalStorage |
| 290 | await page.evaluate(f""" |
| 291 | if (!localStorage.getItem("{processed_key}")) {{ |
| 292 | localStorage.setItem("{processed_key}", JSON.stringify([])); |
| 293 | }} |
| 294 | if (!localStorage.getItem("{batch_key}")) {{ |
| 295 | localStorage.setItem("{batch_key}", JSON.stringify([])); |
| 296 | }} |
| 297 | """) |
| 298 | |
| 299 | # 定位新闻列表容器(转义特殊CSS字符) |
| 300 | container_selector = '.overflow-auto.flex-grow.h-0.saas-scrollbar.mt\-\[-4px\].pl\-\[24px\].pr\-\[10px\].pb\-\[18px\]' |
| 301 | news_items = await page.locator(container_selector).locator('div.py\-\[6px\].group.cursor-pointer').all() |
| 302 | |
| 303 | for item in news_items: |
| 304 | try: |
| 305 | # 获取新闻标题 |
| 306 | title_elem = item.locator('div.flex.text-gray-darker.items-center.relative.pr\-\[56px\] > span') |
| 307 | title = await title_elem.text_content() |
| 308 | if not title: |
| 309 | continue |
| 310 | |
| 311 | # 检查是否已处理过 |
| 312 | is_processed = await page.evaluate( |
| 313 | f"""title => {{ |
| 314 | const processedList = JSON.parse(localStorage.getItem("{processed_key}") || "[]"); |
| 315 | return processedList.includes(title); |
| 316 | }}""", |
| 317 | title |
| 318 | ) |
| 319 | |
| 320 | if is_processed: |
| 321 | print(f"[跳过] {title}") |
| 322 | continue |
| 323 | |
| 324 | # 悬停显示按钮(根据HTML结构,按钮在悬停时显示) |
| 325 | await item.hover() |
| 326 | |
| 327 | # 点击生成文案按钮 |
| 328 | button = item.locator('button:has-text("生成文案")') |
| 329 | await button.click() |
| 330 | print(f"[点击] {title}") |
| 331 | |
| 332 | # 等待30秒 |
| 333 | # await page.wait_for_timeout(30000) |
| 334 | print(f"[等待完成] {title}") |
| 335 | |
| 336 | # 监听"一键成片"按钮 |
| 337 | print(f"[开始监听] 一键成片按钮") |
| 338 | should_exit_while_loop = False # 添加标志变量 |
| 339 | while True: |
| 340 | # 定位"一键成片"按钮 |
| 341 | one_key_button = page.locator("button:has-text('一键成片')") |
| 342 | |
| 343 | # 检查按钮是否存在 |
| 344 | if await one_key_button.count() > 0: |
| 345 | # 检查按钮是否有disabled属性 |
| 346 | is_disabled = await one_key_button.get_attribute("disabled") |
| 347 | |
| 348 | if is_disabled is None: |
| 349 | # 按钮不再被禁用,点击它 |
| 350 | print(f"[发现可点击按钮] 一键成片") |
| 351 | await one_key_button.click() # 先点击一键成片按钮 |
| 352 | |
| 353 | # 等待可能出现的"温馨提示"窗口 |
| 354 | print(f"[检查] 是否出现温馨提示窗口") |
| 355 | await page.wait_for_timeout(2000) # 等待2秒,让窗口有时间显示 |
| 356 | |
| 357 | try: |
| 358 | # 检查是否存在"温馨提示"窗口,设置较短的超时时间 |
| 359 | tip_window = page.locator("div:has-text('温馨提示') >> visible=true") |
| 360 | if await tip_window.count() > 0: |
| 361 | print(f"[发现] 温馨提示窗口") |
| 362 | |
| 363 | # 定位并点击"知道了"按钮,设置较短的超时时间 |
| 364 | know_button = page.locator("button:has-text('知道了')") |
| 365 | if await know_button.count() > 0: |
| 366 | try: |
| 367 | # 设置较短的超时时间进行点击 |
| 368 | await know_button.click(timeout=5000) |
| 369 | print(f"[已点击] 知道了按钮") |
| 370 | except Exception as e: |
| 371 | print(f"[警告] 点击知道了按钮时出错: {str(e)}") |
| 372 | else: |
| 373 | print(f"[警告] 未找到知道了按钮") |
| 374 | else: |
| 375 | print(f"[信息] 未出现温馨提示窗口,继续执行") |
| 376 | except Exception as e: |
| 377 | print(f"[警告] 处理温馨提示窗口时出错: {str(e)}") |
| 378 | # 继续执行,不要因为这个错误中断流程 |
| 379 | |
| 380 | # 记录到LocalStorage前打印日志 |
| 381 | print(f"[开始记录] 准备将标题 '{title}' 记录到LocalStorage") |
| 382 | |
| 383 | # 记录到LocalStorage |
| 384 | await page.evaluate( |
| 385 | f""" |
| 386 | (title, processedKey, batchKey) => {{ |
| 387 | // 更新已处理列表 |
| 388 | const processedList = JSON.parse(localStorage.getItem(processedKey) || "[]"); |
| 389 | if (!processedList.includes(title)) {{ |
| 390 | processedList.push(title); |
| 391 | localStorage.setItem(processedKey, JSON.stringify(processedList)); |
| 392 | }} |
| 393 | |
| 394 | // 更新当前批次记录 |
| 395 | const batchList = JSON.parse(localStorage.getItem(batchKey) || "[]"); |
| 396 | if (!batchList.includes(title)) {{ |
| 397 | batchList.push(title); |
| 398 | localStorage.setItem(batchKey, JSON.stringify(batchList)); |
| 399 | }} |
| 400 | }} |
| 401 | """, |
| 402 | title, processed_key, batch_key |
| 403 | ) |
| 404 | |
| 405 | # 记录完成后打印日志 |
| 406 | print(f"[记录完成] 标题 '{title}' 已成功记录到LocalStorage") |
| 407 | |
| 408 | print(f"[记录完成] {title}") |
| 409 | |
| 410 | # 监听新打开的标签页 |
| 411 | print(f"[监听] 等待新标签页打开") |
| 412 | # 获取当前所有页面 |
| 413 | current_pages = context.pages |
| 414 | current_page_count = len(current_pages) |
| 415 | |
| 416 | # 等待新标签页打开(最多等待10秒) |
| 417 | new_page = None |
| 418 | max_wait_time = 10 # 最大等待时间(秒) |
| 419 | start_time = time.time() |
| 420 | |
| 421 | while time.time() - start_time < max_wait_time: |
| 422 | # 获取最新的页面列表 |
| 423 | pages = context.pages |
| 424 | # 如果页面数量增加,说明新标签页已打开 |
| 425 | if len(pages) > current_page_count: |
| 426 | # 获取最新打开的页面(通常是列表中的最后一个) |
| 427 | new_page = pages[-1] |
| 428 | print(f"[发现] 新标签页已打开") |
| 429 | break |
| 430 | # 短暂等待后再次检查 |
| 431 | await asyncio.sleep(0.5) |
| 432 | |
| 433 | # 如果找到新标签页,获取其标题和URL并保存 |
| 434 | if new_page: |
| 435 | # 等待页面加载完成 |
| 436 | try: |
| 437 | await new_page.wait_for_load_state("domcontentloaded", timeout=5000) |
| 438 | # 获取页面标题和URL |
| 439 | page_title = await new_page.title() |
| 440 | page_url = new_page.url |
| 441 | |
| 442 | print(f"[获取] 标题: {page_title}") |
| 443 | print(f"[获取] URL: {page_url}") |
| 444 | |
| 445 | # 将标题和URL保存到url.txt文件 |
| 446 | with open("url.txt", "a", encoding="utf-8") as f: |
| 447 | f.write(f"{page_title}\n{page_url}\n\n") |
| 448 | |
| 449 | print(f"[保存] 标题和URL已保存到url.txt") |
| 450 | |
| 451 | # 等待5秒后关闭新标签页 |
| 452 | print(f"[等待] 5秒后将关闭新标签页") |
| 453 | await asyncio.sleep(5) |
| 454 | await new_page.close() |
| 455 | print(f"[关闭] 新标签页已关闭") |
| 456 | except Exception as e: |
| 457 | print(f"[错误] 处理新标签页时出错: {str(e)}") |
| 458 | try: |
| 459 | # 尝试关闭页面,即使出错 |
| 460 | await new_page.close() |
| 461 | print(f"[关闭] 新标签页已关闭(出错后)") |
| 462 | except: |
| 463 | pass |
| 464 | else: |
| 465 | print(f"[警告] 未检测到新标签页打开") |
| 466 | |
| 467 | # 跳出整个while循环 |
| 468 | print(f"[操作] 跳出所有循环,不再处理其他新闻") |
| 469 | should_exit_while_loop = True # 设置标志变量 |
| 470 | break # 跳出while循环 |
| 471 | |
| 472 | # 检查是否需要跳出while循环 |
| 473 | if should_exit_while_loop: |
| 474 | break |
| 475 | |
| 476 | # 每秒检查一次按钮状态 |
| 477 | await page.wait_for_timeout(1000) |
| 478 | |
| 479 | # 检查是否需要跳出for循环 |
| 480 | if should_exit_while_loop: |
| 481 | print(f"[操作] 跳出for循环,完全结束处理") |
| 482 | break # 跳出for循环 |
| 483 | except Exception as e: |
| 484 | print(f"处理新闻时出错: {str(e)}") |
| 485 | continue |
| 486 | |
| 487 | |
| 488 | # endregion 操作处 |
| 489 | |
| 490 | print(f"[循环完成] 准备关闭浏览器") |
| 491 | |
| 492 | # 暂停 1000s |
| 493 | await asyncio.sleep(1000) # 这里延迟是为了方便眼睛直观的观看 |
| 494 | |
| 495 | # 退出前保存 storage 信息 |
| 496 | await context.storage_state(path=self.account_file) # 保存cookie |
| 497 | baijiahao_logger.info('cookie更新完毕!') |
| 498 | await asyncio.sleep(2) # 这里延迟是为了方便眼睛直观的观看 |
| 499 | # 关闭浏览器上下文和浏览器实例 |
| 500 | await context.close() |
| 501 | await browser.close() |
| 502 | |
| 503 | |
| 504 | async def mainAi(self): |
| 505 | async with async_playwright() as playwright: |
| 506 | await self.ai2video(playwright) |
| 507 |