python爬虫实战——抖音

news2024/11/15 11:14:02

目录

1、分析主页作品列表标签结构

2、进入作品页前 判断作品是视频作品还是图文作品

3、进入视频作品页面,获取视频

4、进入图文作品页面,获取图片

5、完整参考代码

6、获取全部作品的一种方法


        本文主要使用 selenium.webdriver(Firefox)、BeautifulSoup等相关库,在 centos 系统中,以无登录状态 进行网页爬取练习。仅做学习和交流使用。

安装和配置 driver 参考:

[1]: Linux无图形界面环境使用Python+Selenium最佳实践 - 知乎

[2]: 错误'chromedriver' executable needs to be in PATH如何解 - 知乎

1、分析主页作品列表标签结构

# webdriver 初始化
driver = webdriver.Firefox(options=firefox_options)

# 设置页面加载的超时时间为6秒
driver.set_page_load_timeout(6)

# 访问目标博主页面
# 如 https://www.douyin.com/user/MS4wLjABAAAAnq8nmb35fUqerHx54jlTx76AEkfq-sMD3cj7QdgsOiM
driver.get(target)

# 分别等待 class='e6wsjNLL' 和 class='niBfRBgX' 的元素加载完毕再继续执行
#(等ul.e6wsjNLL加载完就行了)
# WebDriverWait(driver, 6) 设置最长的等待事间为 6 秒
WebDriverWait(driver, 6).until(EC.presence_of_element_located((By.CLASS_NAME, 'e6wsjNLL')))
WebDriverWait(driver, 6).until(EC.presence_of_element_located((By.CLASS_NAME, 'niBfRBgX')))

# 在浏览器中执行脚本,滚动页面到最底部,有可能会显示更多的作品
driver.execute_script('document.querySelector(".wcHSRAj6").scrollIntoView()')
sleep(1)
        
# 使用 beautifulsoup 解析页面源代码
html = BeautifulSoup(driver.page_source, 'lxml')

# 关闭driver
driver.quit()

# 获取作品列表
ul = html.find(class_='e6wsjNLL')

# 获取每一个作品
lis = ul.findAll(class_='niBfRBgX')

2、进入作品页前 判断作品是视频作品还是图文作品

element_a = li.find('a')
# a 标签下如果能找到 class = 'TQTCdYql' 的元素,
# 则表示该作品是图文,如果没有(则为None),则表示该作品是视频
is_pictures = element_a.find(class_='TQTCdYql')


if (not is_pictures) or (not is_pictures.svg):
    # 视频作品
    pass
else:
    # 图文作品
    pass

3、进入视频作品页面,获取视频

# 拼接作品地址
href = f'https://www.douyin.com{element_a["href"]}'
                
# 使用 webdriver 访问作品页面
temp_driver = webdriver.Firefox(options=firefox_options)
temp_driver.set_page_load_timeout(6)
temp_driver.get(href)
    
# 等待 class='D8UdT9V8' 的元素显示后再执行(该元素的内容是作品的发布日期)
WebDriverWait(temp_driver, 6).until(EC.presence_of_element_located((By.CLASS_NAME, 'D8UdT9V8')))
                
html_v = BeautifulSoup(temp_driver.page_source, 'lxml')
temp_driver.quit()
                
# 获取该作品的发布时间
publish_time = html_v.find(class_='D8UdT9V8').string[5:]

video = html_v.find(class_='xg-video-container').video
source = video.find('source')

# 为该作品创建文件夹(一个作品一个文件夹)
# 以该作品的 发布时间 加 作品类型来命名文件夹
path = create_dir(f'{publish_time}_video')

# 下载作品
download_works(path, f'{get_current_time()}.mp4', f'https:{source["src"]}')

4、进入图文作品页面,获取图片

# 拼接作品页地址
href = f'https:{element_a["href"]}'
                
# 使用webdriver访问作品页面
temp_driver = webdriver.Firefox(options=firefox_options)
temp_driver.set_page_load_timeout(6)
temp_driver.get(href)

# 等待包含作品发表时间的标签加载完成
WebDriverWait(temp_driver, 6).until(EC.presence_of_element_located((By.CLASS_NAME, 'YWeXsAGK')))

# 获取当前页面的源代码,关闭webdriver,交给beautifulsoup来处理
# (剩下的任务 继续使用webdriver也能完成)
html_p = BeautifulSoup(temp_driver.page_source, 'lxml')
temp_driver.quit()
                
# 获取该作品的发布时间
publish_time = f'{html_p.find(class_="YWeXsAGK")}'[-23:-7]
                
# 图片列表
img_ul = html_p.find(class_='KiGtXxLr')
imgs = img_ul.findAll('img')
                
# 为该作品创建文件夹,以作品的发布时间+作品类型+图片数量(如果是图片类型作品)
path = create_dir(f'{publish_time}_pictures_{len(imgs)}')

# 遍历图片,获取url 然后下载
for img in imgs:
    download_works(path, f'{get_current_time()}.webp', f'{img["src"]}')

5、完整参考代码

# -*- coding: utf-8 -*-

import threading,requests,os,zipfile
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from datetime import datetime
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from pyvirtualdisplay import Display
from time import sleep
from bs4 import BeautifulSoup
from selenium.common.exceptions import WebDriverException

display = Display(visible=0, size=(1980, 1440))
display.start()

firefox_options = Options()
firefox_options.headless = True
firefox_options.binary_location = '/home/lighthouse/firefox/firefox'

# 获取当前时间
def get_current_time():
    now = datetime.now()
    format_time = now.strftime("_%Y-%m-%d__%H-%M-%S-%f__")
    return format_time

# 设置一个根路径,作品文件以及日志文件都保留在此
ABS_PATH = f'/home/resources/{get_current_time()}'

# 创建目录,dir_name 是作品的发布时间,格式为:2024-02-26 16:59,需要进行处理
def create_dir(dir_name):
    dir_name = dir_name.replace(' ', '-').replace(':', '-')
    path = f'{ABS_PATH}/{dir_name}'
    try:
        os.makedirs(path)
    except FileExistsError:
        print(f'试图创建已存在的文件, 失败({path})')
    else:
        print(f'创建目录成功  {path}')
    finally:
        return path

# 下载    目录名称,当前文件的命名,下载的地址
def download_works(dir_name, work_name, src):
    response = requests.get(src, stream=True)
    if response.status_code == 200:
        with open(f'{dir_name}/{work_name}', mode='wb') as f:
            for chunk in response.iter_content(1024):
                f.write(chunk)

# 判断作品是否已经下载过
def test_work_exist(dir_name):
    dir_name = dir_name.replace(' ', '-').replace(':', '-')
    path = f'{ABS_PATH}/{dir_name}'
    if os.path.exists(path) and os.path.isdir(path):
        if os.listdir(path):
            return True
    return False

def get_all_works(target):
    try:
        driver = webdriver.Firefox(options=firefox_options)
        driver.set_page_load_timeout(6)
        # 目标博主页面
        driver.get(target)
        WebDriverWait(driver, 6).until(EC.presence_of_element_located((By.CLASS_NAME, 'e6wsjNLL')))
        WebDriverWait(driver, 6).until(EC.presence_of_element_located((By.CLASS_NAME, 'niBfRBgX')))
        
        driver.execute_script('document.querySelector(".wcHSRAj6").scrollIntoView()')
        sleep(1)
        
        html = BeautifulSoup(driver.page_source, 'lxml')
        driver.quit()
        # 作品列表
        ul = html.find(class_='e6wsjNLL')
        # 每一个作品
        lis = ul.findAll(class_='niBfRBgX')
        
        for li in lis:
            element_a = li.find('a')
            is_pictures = element_a.find(class_='TQTCdYql')
            
            if (not is_pictures) or (not is_pictures.svg):
                href = f'https://www.douyin.com{element_a["href"]}'
                
                temp_driver = webdriver.Firefox(options=firefox_options)
                temp_driver.set_page_load_timeout(6)
                temp_driver.get(href)
    
                WebDriverWait(temp_driver, 6).until(EC.presence_of_element_located((By.CLASS_NAME, 'D8UdT9V8')))
                
                # 不是必须,剩余内容webdriver也能胜任
                html_v = BeautifulSoup(temp_driver.page_source, 'lxml')
                temp_driver.quit()
                
                # 获取该作品的发布时间
                publish_time = html_v.find(class_='D8UdT9V8').string[5:]

                # if test_work_exist(f'{publish_time}_video'):
                #     continue
                
                video = html_v.find(class_='xg-video-container').video
                source = video.find('source')
                
                # 为该作品创建文件夹
                path = create_dir(f'{publish_time}_video')
                
                # 下载作品
                download_works(path, f'{get_current_time()}.mp4', f'https:{source["src"]}')
            else:
                href = f'https:{element_a["href"]}'
                
                temp_driver = webdriver.Firefox(options=firefox_options)
                temp_driver.set_page_load_timeout(6)
                temp_driver.get(href)
                WebDriverWait(temp_driver, 6).until(EC.presence_of_element_located((By.CLASS_NAME, 'YWeXsAGK')))

                # 使用 beautifulsoup 不是必须
                html_p = BeautifulSoup(temp_driver.page_source, 'lxml')
                temp_driver.quit()
                
                publish_time = f'{html_p.find(class_="YWeXsAGK")}'[-23:-7]
                
                # 图片列表
                img_ul = html_p.find(class_='KiGtXxLr')
                imgs = img_ul.findAll('img')

                # if test_work_exist(f'{publish_time}_pictures_{len(imgs)}'):
                #     continue
                
                path = create_dir(f'{publish_time}_pictures_{len(imgs)}')
                for img in imgs:
                    download_works(path, f'{get_current_time()}.webp', f'{img["src"]}')
                
        display.stop()
        print('##### finish #####')
    except WebDriverException as e: 
        print(f"捕获到 WebDriverException: {e}")  
    except Exception as err:
        print("捕获到其他错误 get_all_works 末尾")
        print(err)
    finally:
        driver.quit()
        display.stop()

# 将目录进行压缩
def zipdir(path, ziph):
    # ziph 是 zipfile.ZipFile 对象
    for root, dirs, files in os.walk(path):
        for file in files:
            ziph.write(os.path.join(root, file),
                       os.path.relpath(os.path.join(root, file), os.path.join(path, '..')))

def dy_download_all(target_url):
    get_all_works(target_url)

    directory_to_zip = ABS_PATH  # 目录路径
    output_filename = f'{ABS_PATH}.zip'  # 输出ZIP文件的名称

    with zipfile.ZipFile(output_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
        zipdir(directory_to_zip, zipf)

    return f'{ABS_PATH}.zip'             # 返回下载地址

if __name__ == '__main__':
    # 简单测试
    url = input('请输入博主主页url:')
    path = dy_download_all(url)
    print('下载完成')
    print(f'地址:{path}')


测试结果:

6、获取全部作品的一种方法

        上述的操作是在无登录状态下进行的,即使在webdriver中操作让页面滚动,也只能获取到有限的作品,大约是 20 项左右。对此提出一个解决方案。

         以登录状态(或者有cookies本地存储等状态)访问目标博主页面,滚动到作品最底部,然后在控制台中执行JavaScript脚本,获取全部作品的信息(在这里是作品链接以及作品类型),然后写出到文本文件中。

JavaScript 代码: 

let ul = document.querySelector('.e6wsjNLL');

// 存放结果
works_list = [];

// 遍历,每一次都加入一个对象,包括作品页的地址、作品是否为图片作品
ul.childNodes.forEach((e)=>{
  let href = e.querySelector('a').href;
  let is_pictures = e.querySelector('a').querySelector('.TQTCdYql') ? true : false;
  works_list.push({href, is_pictures})
})

// 创建一个Blob对象,包含要写入文件的内容  
var content = JSON.stringify(works_list);  
var blob = new Blob([content], {type: "text/plain;charset=utf-8"});  
  
// 创建一个链接元素  
var link = document.createElement("a");  
  
// 设置链接的href属性为Blob对象的URL  
link.href = URL.createObjectURL(blob);  
  
// 设置链接的下载属性,指定下载文件的名称  
link.download = "example.txt";  
  
// 触发链接的点击事件,开始下载文件  
link.click();

写出结果: 

        列表中的每一个元素都是一个对象,href 是作品的地址,is_pictures 以 boolean 值表示该作品是否为图片作品

        

然后在 python 中读入该文件,使用 json 解析,转成字典列表的形式,遍历列表,对每一个字典(就是每一个作品)进行处理即可。

示例代码:

         win 环境下

import json
import threading,requests,os
from bs4 import BeautifulSoup
from seleniumwire import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
from datetime import datetime
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

# 获取当前时间
def get_current_time():
    now = datetime.now()
    format_time = now.strftime("_%Y-%m-%d__%H-%M-%S-%f__")
    return format_time

# 设置一个根路径,作品文件以及日志文件都保留在此
ABS_PATH = f'F:\\{get_current_time()}'

# 创建目录,dir_name 是作品的发布时间,格式为:2024-02-26 16:59,需要进行处理
def create_dir(dir_name):
    dir_name = dir_name.replace(' ', '-').replace(':', '-')
    path = f'{ABS_PATH}/{dir_name}'
    try:
        os.makedirs(path)
    except FileExistsError:
        print(f'试图创建已存在的文件, 失败({path})')
    else:
        print(f'创建目录成功  {path}')
    finally:
        return path

# 下载    目录名称,当前文件的命名,下载的地址
def download_works(dir_name, work_name, src):
    response = requests.get(src, stream=True)
    if response.status_code == 200:
        with open(f'{dir_name}/{work_name}', mode='wb') as f:
            for chunk in response.iter_content(1024):
                f.write(chunk)

# 判断作品是否已经下载过
def test_work_exist(dir_name):
    dir_name = dir_name.replace(' ', '-').replace(':', '-')
    path = f'{ABS_PATH}/{dir_name}'
    if os.path.exists(path) and os.path.isdir(path):
        if os.listdir(path):
            return True
    return False

# 下载一个作品
def thread_task(ul):
    for item in ul:
        href = item['href']
        is_pictures = item['is_pictures']

        if is_pictures:
            temp_driver = webdriver.Chrome()
            temp_driver.set_page_load_timeout(6)
            temp_driver.get(href)
            WebDriverWait(temp_driver, 6).until(EC.presence_of_element_located((By.CLASS_NAME, 'YWeXsAGK')))

            # 使用 beautifulsoup 不是必须
            html_p = BeautifulSoup(temp_driver.page_source, 'lxml')
            temp_driver.quit()

            publish_time = f'{html_p.find(class_="YWeXsAGK")}'[-23:-7]

            # 图片列表
            img_ul = html_p.find(class_='KiGtXxLr')
            imgs = img_ul.findAll('img')

            # if test_work_exist(f'{publish_time}_pictures_{len(imgs)}'):
            #     continue

            path = create_dir(f'{publish_time}_pictures_{len(imgs)}')
            for img in imgs:
                download_works(path, f'{get_current_time()}.webp', f'{img["src"]}')
        else:
            temp_driver = webdriver.Chrome()
            temp_driver.set_page_load_timeout(6)
            temp_driver.get(href)

            WebDriverWait(temp_driver, 6).until(EC.presence_of_element_located((By.CLASS_NAME, 'D8UdT9V8')))

            # 不是必须,剩余内容webdriver也能胜任
            html_v = BeautifulSoup(temp_driver.page_source, 'lxml')
            temp_driver.quit()

            # 获取该作品的发布时间
            publish_time = html_v.find(class_='D8UdT9V8').string[5:]

            # if test_work_exist(f'{publish_time}_video'):
            #     continue

            video = html_v.find(class_='xg-video-container').video
            source = video.find('source')

            # 为该作品创建文件夹
            path = create_dir(f'{publish_time}_video')

            # 下载作品
            download_works(path, f'{get_current_time()}.mp4', f'https:{source["src"]}')

if __name__ == '__main__':
    content = ''
    # 外部读入作品链接文件
    with open('../abc.txt', mode='r', encoding='utf-8') as f:
        content = json.load(f)

    length = len(content)
    if length <= 3 :
        thread_task(content)
    else:
        # 分三个线程
        ul = [content[0: int(length / 3) + 1], content[int(length / 3) + 1: int(length / 3) * 2 + 1],
                   content[int(length / 3) * 2 + 1: length]]
        for child_ul in ul:
            thread = threading.Thread(target=thread_task, args=(child_ul,))
            thread.start()


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1515927.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【js刷题:数据结构数组篇之移除元素】

移除元素 一、题目二、思路三、方法1.暴力解法2.双指针法定义快指针和慢指针代码展示 三、力扣刷题1.删除排序数组中的重复项 一、题目 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额…

vivo统一接入网关VUA转发性能优化实践

作者&#xff1a;vivo 互联网服务器团队 - Qiu Xiangcun 本文将探讨如何通过使用Intel QuickAssist Technology&#xff08;QAT&#xff09;来优化VUA的HTTPS转发性能。我们将介绍如何使用QAT通过硬件加速来提高HTTPS转发的性能&#xff0c;并探讨QAT在不同应用场景中的表现。最…

重学SpringBoot3-内容协商机制

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-内容协商机制 ContentNegotiationConfigurer接口配置内容协商URL参数Accept头使用Url扩展名 自定义内容协商格式步骤1: 注册自定义媒体类型步骤2: 实现H…

AI实战:借助Python与PaddleOCR,实现高精度文本检测与识别

1、引言 欢迎来到今天的教程&#xff1a;“驾驭PaddleOCR&#xff0c;解锁Python文字识别新技能”。在本篇文章中&#xff0c;我们将手把手教你如何安装及使用这款强大的Python库&#xff0c;轻松应对各类图像中的文字识别问题。 2、安装PaddleOCR 首先确保你的环境中已安装…

苹果电脑下载crossover对电脑有影响吗 crossover mac 好用吗CrossOver虚拟机 CrossOver打游戏

苹果电脑下载crossover对电脑有影响吗&#xff1f; 在苹果电脑下载安装crossover对电脑没有什么影响&#xff0c;并且可以解决macOS系统不能安装Windows应用程序的问题。相较于虚拟机和双系统而言&#xff0c;crossover安装软件更简单&#xff0c;占用内存也更小。下面我们来看…

Css基础——精灵图(sprites)和字体图标

1、精灵图 1.1、精灵图的由来 一个网页中往往会应用很多小的背景图像作为修饰&#xff0c;当网页中的图像过多时&#xff0c;服务器就会频繁地接收和发送 请求图片&#xff0c;造成服务器请求压力过大&#xff0c;这将大大降低页面的加载速度。 因此&#xff0c;为了有效地减…

可行性研究报告模板

1业务需求可行性分析 2技术可行性分析 2.1规范化原则 2.2高度的兼容性和可移植性 2.3人性化、适用性 2.4标准化统一设计原则 2.5先进安全可扩展性原则 3开发周期可行性分析 4人力资源可行性分析 5成本分析 6收益分析 7结论 软件项目全套资料获取下载&#xff1a;软件开发全套资…

链路聚合练习

下面的接口都改为Etherent [LSW1]int Eth-Trunk 1 创建一个eth-trunk 1[LSW1-Eth-Trunk1]int g0/0/1[LSW1-GigabitEthernet0/0/1]eth-trunk 1 将接口0/0/1加入eth-trunk 1[LSW1-GigabitEthernet0/0/1]int g0/0/2[LSW1-GigabitEthernet0/0/2]eth-trunk 1[LSW1-GigabitEthernet…

CAQ六西格玛绿带认证流程:从能力考试到评价全解析

六西格玛绿带认证&#xff0c;作为质量管理领域的一个重要里程碑&#xff0c;对于专业人士来说是一项极具价值的认证。张驰咨询将详细解读这一流程&#xff0c;包括理论知识考试、项目实践能力评价&#xff0c;以及期满换证的相关细节。 一、理论知识考试 六西格玛绿带的理论…

OpenAI机器人,一出手就是王炸

「借助 OpenAI 的能力&#xff0c;Figure 01 现在可以与人全面对话了&#xff01;」 本周三&#xff0c;半个硅谷都在投的明星机器人创业公司Figure&#xff0c;发布了自己第一个 OpenAI 大模型加持的机器人 demo。 这家公司在 3 月 1 日刚刚宣布获得 OpenAI 等公司的投资&…

论文阅读——VSA

VSA: Learning Varied-Size Window Attention in Vision Transformers 方法&#xff1a; 给定输入特征X&#xff0c;VSA首先按照基线方法的例程&#xff0c;将这些标记划分为几个窗口Xw&#xff0c;窗口大小为预定义的w。我们将这些窗口称为默认窗口&#xff0c;并从默认窗口中…

(一)搭建Android Studio开发环境

一、JDK 1、下载 2、安装 双击进行安装&#xff0c;修改安装路径为&#xff1a;D:\Java\jdk-17.0.4.1即可&#xff0c;安装完成后目录如下&#xff1a; 配置环境变量 3、测试 WinR&#xff0c;输入cmd&#xff0c;按Enter后&#xff0c;键入&#xff1a;java --version&…

面试经典-18-合并两个有序链表

题目 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4] 解 class Solution {// 成功public ListNode mergeTwoLists(ListN…

探索世界的第一步:新生儿抬头指南

引言&#xff1a; 新生儿的抬头能力是他们发展早期的重要里程碑之一。这不仅是对颈部肌肉的锻炼&#xff0c;更是对视觉和感觉系统的发展的重要促进。在这个阶段&#xff0c;父母的关注和引导至关重要&#xff0c;以帮助宝宝安全地探索和发展。 1. 激发兴趣&#xff1a; 从宝宝…

matlab调用nlopt时向目标函数中传入数据的案例

matlab调用nlopt时向目标函数中传入数据的案例&#xff0c;如代码所示&#xff1a; clc,clear,close allopt.algorithm NLOPT_LN_AUGLAG; opt.lower_bounds -10; opt.upper_bounds 10; opt.min_objective (x) goal_function(x,[1,2,3,4,5,6,7,8,9]); opt.xtol_rel 1e-8; …

week07day01(powerbi)

一. Power BI简介 1. 构成部分 power query: 进行简单的数据清洗power pivot : 进行指标计算power view &#xff1a; 进行报表视图 二. Power Query (进行数据清洗) 1. 如何获取数据&#xff1a; 点击获取数据 ——> 选择导入数据的类型——> 会出现 "加载&…

Python学习:数据类型转换

数据类型转换 对数据内置的类型进行转换&#xff0c;数据类型的转换&#xff0c;一般情况下你只需要将数据类型作为函数名即可。 Python 数据类型转换可以分为两种&#xff1a; 隐式类型转换 - 自动完成显式类型转换 - 需要使用类型函数来转换 隐式类型转换 Python 会自动…

c/c++ | 求叶子结点个数 |构建B树 | 动态规划--找叶子结点个数

是这样的&#xff0c;一道代码题&#xff0c;根据输入数据&#xff0c;计算运行结果 #include<bits/stdc.h> using namespace std; vector<int>g[10]; int ans 0; void dfs(int x){if(g[x].size() 0){ans;return;}for(int i 0; i < g[x].size(); i){dfs(g[x]…

CVE-2019-5782:kArgumentsLengthType 设置偏小导致优化阶段可以错误的去除 CheckBound 节点

文章目录 环境搭建漏洞分析笔者初分析笔者再分析漏洞触发源码分析 漏洞利用总结 环境搭建 sudo apt install pythongit reset --hard b474b3102bd4a95eafcdb68e0e44656046132bc9 export DEPOT_TOOLS_UPDATE0 gclient sync -D// debug version tools/dev/v8gen.py x64.debug ni…

学会这几步,让酷开系统的使用体验更加出色!

在当今数字化快速发展的时代&#xff0c;用户体验&#xff08;User Experience, UX&#xff09;已成为产品和服务成功的关键因素之一。随着市场竞争的加剧&#xff0c;仅仅提供功能性强大的产品已不足以满足用户的需求&#xff0c;如何提升整体体验、确保用户的满意度和忠诚度&…