item_get_video-获取视频详情(bili.item_get_video)

B站(Bilibili)的item_get_video API用于获取视频的详细信息。通过调用该API,您将能够获得视频的基本信息、元数据、播放链接等。这使得开发者可以轻松地将B站视频集成到自己的应用程序或网站中,为用户提供更丰富的内容和更好的体验。

公共参数

名称 类型 必须 描述
key String 调用key(必须以GET方式拼接在URL中)
secret String 调用密钥
api_name String API接口名称(包括在请求地址中)[item_search,item_get,item_search_shop等]
cache String [yes,no]默认yes,将调用缓存的数据,速度比较快
result_type String [json,jsonu,xml,serialize,var_export]返回数据格式,默认为json,jsonu输出的内容中文可以直接阅读
lang String [cn,en,ru]翻译语言,默认cn简体中文
version Strin
import time import pandas as pd import openpyxl from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.select import Select from selenium.webdriver import ActionChains, Keys from selenium.webdriver.chrome.options import Options chrome_options = Options() chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False) chrome_options.add_argument("--disable-blink-features=AutomationControlled") service = Service("D:/Python313/chromedriver.exe") driver = webdriver.Chrome(service=service, options=chrome_options) driver.maximize_window() file_path = 'C:/Users/一羽风/Desktop/机器人python/1.小组件测试文件/Best_Match.xlsx' wb = openpyxl.load_workbook(file_path) sheet1 = wb.worksheets[0] list_text = [] account_list = [] for row in sheet1.iter_rows(min_row=1,values_only=True): account_list.append((row[0])) driver.get("https://www.bilibili.com/") search_box = driver.find_element(By.XPATH, '//*[@id="nav-searchform"]/div[1]/input') for account in account_list[:2]: search_box.send_keys(Keys.CONTROL + 'a') search_box.send_keys(Keys.DELETE) search_box.send_keys(account) search_box.send_keys(Keys.RETURN) time.sleep(2) original_window = driver.current_window_handle new_window = [w for w in driver.window_handles if w != original_window][0] driver.switch_to.window(new_window) for page in range(3): next_page = driver.find_element(By.CLASS_NAME, 'vui_button vui_pagenation--btn') elements = driver.find_elements(By.CLASS_NAME,'bili-video-card__info') for element in elements[:5]: value2 = element.get_attribute("innerText") # print(value2) time.sleep(5) list_text.append(value2) print(list_text) next_page.click() time.sleep(8) driver.close() driver.switch_to.window(original_window) b搜索内容之后,想点击下一页获取数据,但总是点击不了下一页按钮,总是报错,出错代码为:next_page = driver.find_element(By.CLASS_NAME, 'vui_button vui_pagenation--btn')
03-08
from bs4 import BeautifulSoup import requests html = input() def parse_video_info(html): soup = BeautifulSoup(html, 'html.parser') video_data = [] for video_card in soup.find('div', class_='upload-video-card'): # 提取视频地址 video_url = video_card.find('a', class_='bili-cover-card')['href'] full_video_url = f"https:{video_url}" if video_url.startswith('//') else video_url # 提取封面图地址 img_tag = video_card.find('img') img_url = img_tag['src'] if img_tag else None full_img_url = f"https:{img_url}" if img_url and img_url.startswith('//') else img_url # 提取标题 title_tag = video_card.find('div', class_='bili-video-card__title') title = title_tag.get_text(strip=True) if title_tag else None # 提取统计数据 stats = video_card.find_all('div', class_='bili-cover-card__stat') play_count = stats[0].find('span').get_text(strip=True) if len(stats) > 0 else None danmu_count = stats[1].find('span').get_text(strip=True) if len(stats) > 1 else None duration = stats[2].find('span').get_text(strip=True) if len(stats) > 2 else None video_data.append({ "video_url": full_video_url, "cover_image": full_img_url, "title": title, "play_count": play_count, "danmu_count": danmu_count, "duration": duration }) return video_data # 示例使用 if __name__ == "__main__": result = parse_video_info(html) for video in result: print('{') print(f' "title": {repr(video["title"])},') print(f' "videoUrl": "{video["video_url"]}",') print(f' "imgUrl": "{video["cover_image"]}",') print(f' "playCount": {repr(video["play_count"])},') # 保留"万"单位 print(f' "danmuCount": {video["danmu_count"]},') # 直接数字 print(f' "duration": {repr(video["duration"])}') # 带引号的时间 print('},')帮我改一下可以获取多条信息
05-27
import requests import time import hashlib import json import pandas as pd from urllib.parse import quote from typing import List, Union, Dict, Any class BilibiliCrawler: def __init__(self, keywords: Union[str, List[str]] = None, max_results: int = 30): """ 初始化爬虫 参数: keywords: 关键词或关键词列表,默认为["高等数学", "概率论", "Python"] max_results: 每个关键词最大爬取结果数 """ # 处理关键词类型,支持字符串和列表 if keywords is None: self.keywords = ["高等数学", "概率论", "Python"] elif isinstance(keywords, str): self.keywords = [keywords] else: self.keywords = keywords self.max_results = max_results self.session = requests.Session() self.headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36', 'Referer': 'https://www.bilibili.com/', 'Origin': 'https://www.bilibili.com', 'Cookie': 'your_cookie_here' # 替换为实际Cookie } self.video_data = [] self.mixin_key = None # 缓存混合密钥 self.request_count = 0 # 请求计数器 def get_mixin_key(self) -> str: """获取并缓存混合密钥""" if self.mixin_key: return self.mixin_key nav_url = "https://api.bilibili.com/x/web-interface/nav" try: nav_res = self.session.get(nav_url, headers=self.headers, timeout=10) nav_res.raise_for_status() wbi_img = nav_res.json().get('data', {}).get('wbi_img', {}) img_key = wbi_img.get('img_url', '').split('/')[-1].split('.')[0] sub_key = wbi_img.get('sub_url', '').split('/')[-1].split('.')[0] self.mixin_key = (img_key + sub_key)[:32] return self.mixin_key except Exception as e: print(f"获取混合密钥失败: {str(e)}") # 使用备用密钥 return "ea1db124af3c7062474693fa704f4ff8" def get_wbi_sign(self, params: Dict[str, Any]) -> str: """生成WBI签名""" # 获取混合密钥 mixin_key = self.get_mixin_key() # 对参数排序并生成查询字符串 sorted_params = dict(sorted(params.items())) query = '&'.join([f'{k}={quote(str(v))}' for k, v in sorted_params.items()]) # 计算MD5签名 wbi_sign = hashlib.md5((query + mixin_key).encode()).hexdigest() return wbi_sign def search_videos(self): """搜索多个关键词的视频""" total_videos = 0 for keyword in self.keywords: print(f"\n开始爬取关键词: {keyword}") keyword_count = 0 page = 1 while keyword_count < self.max_results and total_videos < self.max_results * len(self.keywords): # 计算本页需要获取视频数量 page_size = min( 20, self.max_results - keyword_count, self.max_results * len(self.keywords) - total_videos ) # 基础参数 params = { 'search_type': 'video', 'keyword': keyword, 'page': page, 'page_size': page_size } # 添加WBI签名 params['w_rid'] = self.get_wbi_sign(params) try: # 发送搜索请求 response = self.session.get( "https://api.bilibili.com/x/web-interface/wbi/search/type", params=params, headers=self.headers, timeout=15 ) self.request_count += 1 # 处理412错误 if response.status_code == 412: print(f"第{page}页遇到412错误,正在重试...") time.sleep(3) response = self.session.get( "https://api.bilibili.com/x/web-interface/wbi/search/type", params=params, headers=self.headers, timeout=15 ) self.request_count += 1 response.raise_for_status() data = response.json() # 检查API响应状态 if data.get('code') != 0: error_msg = data.get('message', '未知错误') print(f"API返回错误: {error_msg} (代码: {data.get('code')})") break # 检查是否有有效数据 results = data.get('data', {}).get('result') if not results: print(f"关键词 '{keyword}' 第{page}页无结果") break # 提取视频基本信息 for video in results: if keyword_count >= self.max_results or total_videos >= self.max_results * len(self.keywords): break bvid = video.get('bvid') if bvid: video_info = self.get_video_details(bvid, keyword) if video_info: self.video_data.append(video_info) keyword_count += 1 total_videos += 1 print( f"已获取 {keyword_count}/{self.max_results} 条数据 | 关键词: {keyword} | 总进度: {total_videos}/{self.max_results * len(self.keywords)}") # 控制请求频率 (每5次请求休息2秒) if self.request_count % 5 == 0: time.sleep(2) else: time.sleep(0.5) page += 1 time.sleep(1.5) # 页间延迟 except requests.exceptions.RequestException as e: print(f"请求失败({keyword}): {str(e)}") time.sleep(5) # 请求失败后延长等待 except json.JSONDecodeError as e: print(f"JSON解析失败({keyword}): {str(e)}") print(f"响应内容: {response.text[:200]}...") except Exception as e: print(f"未知错误({keyword}): {str(e)}") break print(f"关键词 '{keyword}' 爬取完成, 共获取 {keyword_count} 条数据") def get_video_details(self, bvid: str, keyword: str) -> Dict[str, Any]: """获取视频详细信息""" detail_url = f"https://api.bilibili.com/x/web-interface/view?bvid={bvid}" try: response = self.session.get(detail_url, headers=self.headers, timeout=10) self.request_count += 1 # 处理详情页412错误 if response.status_code == 412: print(f"视频{bvid}详情页412错误,重试中...") time.sleep(2) response = self.session.get(detail_url, headers=self.headers, timeout=10) self.request_count += 1 response.raise_for_status() data = response.json() if data.get('code') != 0: error_msg = data.get('message', '未知错误') print(f"视频详情API错误({bvid}): {error_msg}") return None video_data = data.get('data', {}) if not video_data: print(f"视频{bvid}详情数据为空") return None stat = video_data.get('stat', {}) return { 'bvid': bvid, '关键词': keyword, '标题': video_data.get('title', ''), '博主': video_data.get('owner', {}).get('name', ''), '播放量': stat.get('view', 0), '点赞量': stat.get('like', 0), '收藏量': stat.get('favorite', 0), '弹幕量': stat.get('danmaku', 0), '分享量': stat.get('share', 0), '硬币数': stat.get('coin', 0), '视频时长': video_data.get('duration', 0), '发布时间': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(video_data.get('pubdate', 0))) } except requests.exceptions.RequestException as e: print(f"获取视频详情失败({bvid}): 请求错误 - {str(e)}") return None except json.JSONDecodeError as e: print(f"获取视频详情失败({bvid}): JSON解析错误 - {str(e)}") return None except Exception as e: print(f"获取视频详情失败({bvid}): 未知错误 - {str(e)}") return None def save_to_csv(self, filename='bilibili.csv'): """保存数据到CSV""" if not self.video_data: print("没有数据可保存") return df = pd.DataFrame(self.video_data) # 优化列顺序 columns_order = [ 'bvid', '关键词', '标题', '博主', '播放量', '点赞量', '收藏量', '弹幕量', '分享量', '硬币数', '视频时长', '发布时间' ] df = df.reindex(columns=[col for col in columns_order if col in df.columns]) df.to_csv(filename, index=False, encoding='utf_8_sig') print(f"已保存 {len(self.video_data)} 条数据到 {filename}") # 使用示例 if __name__ == "__main__": # 自定义关键词列表和最大结果数 keywords = [ "概率论", "Python数据分析", "随机过程", "高等数学", "Scipy概率分布" ] crawler = BilibiliCrawler(keywords=keywords, max_results=20) crawler.search_videos() crawler.save_to_csv('bilibili.csv') 请根据这个代码帮我写几个数据分析,例如词云图和条形图
06-15
import sys import json import os import warnings from datetime import datetime from PyQt5.QtCore import QUrl, Qt, QDateTime from PyQt5.QtWidgets import ( QApplication, QMainWindow, QLineEdit, QPushButton, QListWidget, QTabWidget, QVBoxLayout, QWidget, QHBoxLayout, QAction, QToolBar, QStatusBar, QProgressBar, QInputDialog, QFileDialog, QMessageBox ) from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineProfile, QWebEnginePage, QWebEngineSettings from PyQt5.QtNetwork import QNetworkProxy, QNetworkCookie # 修复代理设置导入问题 # 忽略弃用警告 warnings.filterwarnings("ignore", category=DeprecationWarning) class WebEnginePage(QWebEnginePage): def __init__(self, profile=None, parent=None): """修复参数传递问题:支持带profile和不带profile两种初始化方式""" if profile: super().__init__(profile, parent) # 使用profile初始化 else: super().__init__(parent) # 标准初始化 self.parent_window = parent.parent_window if parent and hasattr(parent, 'parent_window') else None def acceptNavigationRequest(self, url, _type, isMainFrame): # 检测视频流协议并调用播放器 if url.scheme() in ['rtmp', 'http-flv', 'ws-flv']: if self.parent_window: self.parent_window.play_with_jessibuca(url.toString()) return False return super().acceptNavigationRequest(url, _type, isMainFrame) def createWindow(self, type): # 在新标签页打开链接 if type == QWebEnginePage.WebBrowserTab: if self.parent_window: new_tab = self.parent_window.add_browser_tab("加载中...") return new_tab.page return super().createWindow(type) def javaScriptConsoleMessage(self, level, message, lineNumber, sourceID): """修复:正确映射JavaScript控制台日志级别""" # 创建日志级别映射字典 level_map = { QWebEnginePage.InfoMessageLevel: "INFO", QWebEnginePage.WarningMessageLevel: "WARNING", QWebEnginePage.ErrorMessageLevel: "ERROR" } # 获取可读的日志级别名称 level_str = level_map.get(level, "UNKNOWN") log_msg = f"[JS {level_str}] {sourceID}:{lineNumber} - {message}" if self.parent_window: self.parent_window.status_bar.showMessage(log_msg, 5000) print(log_msg) # 同时输出到控制台 class WebEngineView(QWebEngineView): def __init__(self, parent=None): super().__init__(parent) self.parent_window = parent # 修复:正确传递profile参数 self.page = WebEnginePage(profile=self.parent_window.profile, parent=self) self.setPage(self.page) self.page.loadFinished.connect(self.inject_jessibuca) def inject_jessibuca(self): self.page.runJavaScript(""" if (typeof window.Jessibuca === 'undefined') { const script = document.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/jessibuca@latest/dist/jessibuca.js'; script.onerror = () => console.error('Jessibuca加载失败'); document.head.appendChild(script); const container = document.createElement('div'); container.id = 'jessibuca-container'; container.style.position = 'fixed'; container.style.zIndex = '99999'; container.style.top = '0'; container.style.left = '0'; container.style.width = '100%'; container.style.height = '100%'; container.style.backgroundColor = 'black'; container.style.display = 'none'; document.body.appendChild(container); } """) def createWindow(self, type): # 创建新标签页 if type == QWebEnginePage.WebBrowserTab: new_tab = WebEngineView(self.parent_window) # 修复:直接返回page属性而非调用page() return new_tab.page return super().createWindow(type) class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("B多账号浏览器") self.setMinimumSize(1200, 800) # 初始化数据存储 self.account_db = {} self.cookies_db = [] # 创建持久化Cookie配置 self.cookie_storage_path = "cookies_storage" os.makedirs(self.cookie_storage_path, exist_ok=True) self.profile = QWebEngineProfile("BiliCookieProfile", self) self.profile.setPersistentCookiesPolicy(QWebEngineProfile.ForcePersistentCookies) self.profile.setPersistentStoragePath(self.cookie_storage_path) # 关键性能优化1: 全局禁用网络代理[8](@ref) QNetworkProxy.setApplicationProxy(QNetworkProxy(QNetworkProxy.NoProxy)) # 关键性能优化2: 启用HTTP内存缓存[9](@ref) self.profile.setHttpCacheType(QWebEngineProfile.MemoryHttpCache) # 启用HTML5支持的设置 profile_settings = self.profile.settings() profile_settings.setAttribute(QWebEngineSettings.PlaybackRequiresUserGesture, False) profile_settings.setAttribute(QWebEngineSettings.FullScreenSupportEnabled, True) profile_settings.setAttribute(QWebEngineSettings.WebGLEnabled, True) profile_settings.setAttribute(QWebEngineSettings.Accelerated2dCanvasEnabled, True) profile_settings.setAttribute(QWebEngineSettings.PluginsEnabled, True) profile_settings.setAttribute(QWebEngineSettings.AllowRunningInsecureContent, True) # 主界面布局 central_widget = QWidget() self.setCentralWidget(central_widget) main_layout = QVBoxLayout(central_widget) # 导航工具栏 navbar = QToolBar("导航栏") navbar.setMovable(False) # 禁止工具栏拖动提升性能 self.addToolBar(navbar) back_btn = QAction("←", self) back_btn.triggered.connect(self.navigate_back) navbar.addAction(back_btn) forward_btn = QAction("→", self) forward_btn.triggered.connect(self.navigate_forward) navbar.addAction(forward_btn) reload_btn = QAction("↻", self) reload_btn.triggered.connect(self.reload_page) navbar.addAction(reload_btn) home_btn = QAction("🏠", self) home_btn.triggered.connect(self.navigate_home) navbar.addAction(home_btn) navbar.addSeparator() self.url_bar = QLineEdit("https://www.bilibili.com") self.url_bar.setPlaceholderText("输入网址或搜索内容...") self.url_bar.returnPressed.connect(self.load_url) navbar.addWidget(self.url_bar) # 浏览器标签页 self.browser_tabs = QTabWidget() self.browser_tabs.setTabsClosable(True) self.browser_tabs.tabCloseRequested.connect(self.close_tab) self.browser_tabs.currentChanged.connect(self.update_url_bar) # 关键性能优化3: 启用标签页滚动 self.browser_tabs.setUsesScrollButtons(True) main_layout.addWidget(self.browser_tabs, 8) # 添加初始标签页 self.add_browser_tab("首页", "https://www.bilibili.com") # 管理面板 self.tabs = QTabWidget() self.cookie_list = QListWidget() self.tabs.addTab(self.cookie_list, "Cookie列表") self.account_list = QListWidget() self.tabs.addTab(self.account_list, "账号切换") self.account_list.itemClicked.connect(self.switch_account) main_layout.addWidget(self.tabs, 2) # 功能按钮 btn_layout = QHBoxLayout() self.import_btn = QPushButton("导入Cookie") self.import_btn.clicked.connect(self.import_cookies) self.save_btn = QPushButton("保存账号") self.save_btn.clicked.connect(self.save_account) self.export_btn = QPushButton("导出Cookie") self.export_btn.clicked.connect(self.export_cookies) self.new_tab_btn = QPushButton("新建标签页") self.new_tab_btn.clicked.connect(self.create_new_tab) for btn in [self.import_btn, self.save_btn, self.export_btn, self.new_tab_btn]: btn_layout.addWidget(btn) main_layout.addLayout(btn_layout) # 状态栏 self.status_bar = QStatusBar() self.setStatusBar(self.status_bar) self.progress_bar = QProgressBar() self.progress_bar.setMaximum(100) self.progress_bar.setVisible(False) self.progress_bar.setFixedWidth(200) self.status_bar.addPermanentWidget(self.progress_bar) # 加载数据 self.load_accounts() def add_browser_tab(self, title, url=None): browser = WebEngineView(self) browser.titleChanged.connect(lambda title, b=browser: self.update_tab_title(b, title)) browser.loadProgress.connect(self.update_progress) browser.loadFinished.connect(self.on_load_finished) index = self.browser_tabs.addTab(browser, title) self.browser_tabs.setCurrentIndex(index) # 关键性能优化4: 延迟加载提升启动速度 if url: QApplication.processEvents() # 确保UI更新 browser.load(QUrl(url)) return browser def update_tab_title(self, browser, title): index = self.browser_tabs.indexOf(browser) if index != -1: self.browser_tabs.setTabText(index, title[:15] + "..." if len(title) > 15 else title) def update_progress(self, progress): self.progress_bar.setVisible(progress < 100) self.progress_bar.setValue(progress) def close_tab(self, index): """修复资源释放问题:移除多余的括号""" if self.browser_tabs.count() > 1: widget = self.browser_tabs.widget(index) # 关键修复:直接访问page属性而非调用page() page = widget.page if page: # 关键优化: 正确的资源释放顺序 profile = page.profile() profile.cookieStore().deleteAllCookies() # 先删除页面再删除视图 page.deleteLater() widget.deleteLater() self.browser_tabs.removeTab(index) else: self.create_new_tab() def create_new_tab(self): self.add_browser_tab("新标签页", "about:blank") def navigate_back(self): current_browser = self.browser_tabs.currentWidget() if current_browser: current_browser.back() def navigate_forward(self): current_browser = self.browser_tabs.currentWidget() if current_browser: current_browser.forward() def reload_page(self): current_browser = self.browser_tabs.currentWidget() if current_browser: current_browser.reload() def navigate_home(self): self.load_url("https://www.bilibili.com") def on_load_finished(self, success): browser = self.sender() if browser and self.browser_tabs.currentWidget() == browser: current_url = browser.url().toString() self.url_bar.setText(current_url) self.status_bar.showMessage("页面加载完成" if success else "页面加载失败", 2000) # 关键优化: 登录页面自动处理 if "login" in current_url or "passport" in current_url: self.status_bar.showMessage("检测到登录页面,请完成登录", 5000) self.auto_handle_login_page(browser) def auto_handle_login_page(self, browser): """自动处理登录页面的JavaScript""" browser.page.runJavaScript(""" // 尝试自动填充已知的登录表单 const loginForm = document.querySelector('form[action*="login"]'); if (loginForm) { // 尝试填充测试账号 const usernameInput = loginForm.querySelector('input[name="username"], input[name="user"]'); const passwordInput = loginForm.querySelector('input[name="password"]'); if (usernameInput && passwordInput) { usernameInput.value = "test_account"; passwordInput.value = "test_password"; console.log("自动填充了登录表单"); } } """) def update_url_bar(self): current_browser = self.browser_tabs.currentWidget() if current_browser: current_url = current_browser.url().toString() self.url_bar.setText(current_url) # 登录页面特殊处理 if "login" in current_url or "passport" in current_url: self.url_bar.setStyleSheet("background-color: #FFF8E1;") else: self.url_bar.setStyleSheet("") def load_url(self, url_text=None): if url_text is None: url_text = self.url_bar.text().strip() if not url_text: return # 关键优化: 更智能的URL处理[10](@ref) if not url_text.startswith(("http://", "https://", "file://", "ftp://")): if "." in url_text: # 包含域名 url_text = "https://" + url_text else: # 可能是搜索内容 url_text = f"https://www.bilibili.com/search?keyword={url_text}" current_browser = self.browser_tabs.currentWidget() if current_browser: current_browser.load(QUrl(url_text)) self.status_bar.showMessage(f"正在加载: {url_text}", 3000) def play_with_jessibuca(self, stream_url): """使用Jessibuca播放视频流""" current_browser = self.browser_tabs.currentWidget() if not current_browser: return self.status_bar.showMessage("Jessibuca播放中...", 3000) current_browser.page.runJavaScript(f""" const container = document.getElementById('jessibuca-container'); if (container) {{ container.style.display = 'block'; if (!window.jessibucaPlayer) {{ window.jessibucaPlayer = new Jessibuca({{ container: container, videoBuffer: 0.2, isResize: true, text: '直播加载中...', decoder: 'ffmpeg.js', forceNoOffscreen: true }}); }} window.jessibucaPlayer.play('{stream_url}'); }} """) def import_cookies(self): """导入Cookie JSON文件""" file_path, _ = QFileDialog.getOpenFileName( self, "选择Cookie文件", "", "JSON文件 (*.json)" ) if file_path: try: with open(file_path, "r", encoding='utf-8') as f: cookies = json.load(f) if isinstance(cookies, list): self.cookies_db = cookies self.cookie_list.clear() self.cookie_list.addItems([f"{c['name']}: {c['value'][:10]}..." for c in cookies]) self.status_bar.showMessage(f"成功导入 {len(cookies)} 个Cookie", 3000) self.inject_cookies(cookies) else: QMessageBox.warning(self, "错误", "无效的Cookie格式") except Exception as e: QMessageBox.critical(self, "导入失败", f"错误: {str(e)}") def export_cookies(self): """导出Cookie到文件""" file_path, _ = QFileDialog.getSaveFileName( self, "保存Cookie文件", "", "JSON文件 (*.json)" ) if file_path: try: cookies = self.get_current_cookies() with open(file_path, "w", encoding='utf-8') as f: json.dump(cookies, f, indent=2, ensure_ascii=False) self.status_bar.showMessage("Cookie导出成功", 3000) except Exception as e: QMessageBox.critical(self, "导出失败", f"错误: {str(e)}") def get_current_cookies(self): """获取当前标签页的Cookie(模拟)""" # 实际实现需要异步获取,这里简化处理 return self.cookies_db if self.cookies_db else [] def inject_cookies(self, cookies): """将Cookie注入当前页面 - 修复登录问题[9](@ref)""" current_browser = self.browser_tabs.currentWidget() if current_browser: store = current_browser.page.profile().cookieStore() # 先清除现有Cookie store.deleteAllCookies() # 异步注入新的Cookie for cookie_data in cookies: # 创建Qt的Cookie对象 qt_cookie = QNetworkCookie( cookie_data['name'].encode('utf-8'), cookie_data['value'].encode('utf-8') ) # 设置Cookie属性 if 'domain' in cookie_data: qt_cookie.setDomain(cookie_data['domain']) if 'path' in cookie_data: qt_cookie.setPath(cookie_data['path']) if 'expiry' in cookie_data: # 转换为QDateTime expiry = QDateTime.fromSecsSinceEpoch(cookie_data['expiry']) qt_cookie.setExpirationDate(expiry) # 设置安全属性 qt_cookie.setSecure(cookie_data.get('secure', False)) qt_cookie.setHttpOnly(cookie_data.get('httpOnly', False)) # 注入Cookie store.setCookie(qt_cookie, QUrl(cookie_data.get('url', 'https://www.bilibili.com'))) self.status_bar.showMessage("Cookie注入成功,请刷新页面", 3000) def save_account(self): """保存当前账号配置""" account_name, ok = QInputDialog.getText( self, "保存账号", "输入账号名称:" ) if ok and account_name: cookies = self.get_current_cookies() if cookies: self.account_db[account_name] = { "cookies": cookies, "saved_date": datetime.now().isoformat() } self.account_list.addItem(account_name) # 持久化存储账号数据 try: with open("accounts.json", "w", encoding='utf-8') as f: json.dump(self.account_db, f, indent=2, ensure_ascii=False) QMessageBox.information(self, "成功", "账号保存成功") except Exception as e: QMessageBox.critical(self, "保存失败", f"账号保存失败: {str(e)}") else: QMessageBox.warning(self, "错误", "没有获取到有效Cookie") def switch_account(self, item): """切换账号""" account_name = item.text() if account_name in self.account_db: cookies = self.account_db[account_name].get("cookies", []) self.inject_cookies(cookies) self.status_bar.showMessage(f"已切换至账号: {account_name}", 3000) # 自动刷新当前页面 self.reload_page() else: QMessageBox.warning(self, "错误", "找不到该账号的Cookie信息") def load_accounts(self): """从文件加载保存的账号""" try: if os.path.exists("accounts.json"): with open("accounts.json", "r", encoding='utf-8') as f: self.account_db = json.load(f) self.account_list.addItems(self.account_db.keys()) except Exception as e: print(f"加载账号失败: {str(e)}") def closeEvent(self, event): """窗口关闭时释放全局资源[8](@ref)""" # 清理HTTP缓存和访问记录 self.profile.clearHttpCache() self.profile.clearAllVisitedLinks() # 保存账号数据 try: with open("accounts.json", "w", encoding='utf-8') as f: json.dump(self.account_db, f, indent=2, ensure_ascii=False) except Exception as e: print(f"保存账号失败: {str(e)}") super().closeEvent(event) if __name__ == "__main__": # 关键性能优化: 启用WebEngine调试日志[9](@ref) os.environ["QTWEBENGINE_CHROMIUM_FLAGS"] = "--enable-logging" app = QApplication(sys.argv) # 关键性能优化: 启用Qt内置的OpenGL渲染[7](@ref) app.setAttribute(Qt.AA_UseOpenGLES) window = MainWindow() window.show() sys.exit(app.exec_())
最新发布
07-09
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值