精华内容
下载资源
问答
  • 为什么要保存 B 站视频的播放记录呢? 因为 B 站的历史记录,最多保存 3 个月,超过 3 个月自动清除。所以我专门写一个脚本,将历史记录导出,保存在数据库中,一来是本地保存,二来也方便对这些视频按自己的习惯进行...

    为什么要保存 B 站视频的播放记录呢? 因为 B 站的历史记录,最多保存 3 个月,超过 3 个月自动清除。所以我专门写一个脚本,将历史记录导出,保存在数据库中,一来是是以备以后需要时能够找到,二来也方便对这些视频按自己的习惯进行分类和做备注。

    B 站的历史记录,后端以 Web API 的方式将数据提交到前台,前后端是分离的。在浏览器中滚动条向下滑动的时候,动态提交 HTTP 请求,数据分批渲染。首先,我们需要学会如何查看 Web API。以 Chrome 浏览器为例。进入 B 站,点击右上角 「历史记录」按钮,然后按下 F12,调出开发者调试工具,切换到 Network 页签。因为历史记录是动态加载的,所以再点击筛选区的 「XHR」(XmlHttpRequest,其实就是 HTTP Request)。点击后,下面显示的都是与 xhr 相关的内容。

    点击第二行(cursor***),右边出现多个页签,在 Headers 页签中,重要的有 Request URL 和 Request Headers 区域的 Cookie。将 Cookie 的内容拷贝到文本文件,比如将文件名命名为 cookie.txt。在 Chrome 浏览器中,默认情况下,右键不出现拷贝菜单,需要三次点击,选中整个字段,此时右键菜单有拷贝菜单出现。


    切换到 Preview 页签,可以看出,B 站每次从后台返回 20 笔记录。我们可以通过 Preview 和 Response 来了解返回信息的数据结构。


    向下滚动历史记录,左边出现更多的动态的请求内容,这些请求的 url path 主要的差异在 cursor 后面的 max 和 view_at 参数不同,max 和 view_at 来自上一次 response。换一个角度来说,每次服务端的 response,除本次 20 笔历史记录外,还同时返回下一次请求的 max 参数(表示最大的目标 ID号)和 view_at (查看的时间戳)参数。下图展示了刚才所述内容:


    当所有的历史记录完毕,最后一次请求的响应,cursor 的 max = 0, view_at = 0, ps = 0。基于了解的这些信息,接下来可以通过 Python 代码来获取历史记录了。本次实现两个功能:

    • 获取历史记录
    • 保存到数据库

    获取 B 站历史记录

    编写一个从 url 返回 json 数据的函数。在该函数中,request header 参数有两个作用:提供客户端 cookie,以及将请求伪装为浏览器。

    def get_response_json(url, req_headers):
        """根据url获取json格式的response文本"""
        resp = requests.get(url, headers=req_headers)
        return json.loads(resp.text)
    

    从 B 站历史记录的 api 获取 json 格式数据,刚刚提到的客户端 cookie,作用是提供客户端的登录信息,cookie 信息在 request header 中。通过面向对象的方式封装代码。将 cookie 和 header 的加载放在 _init_ 方法中。BiliHistory 类对外提供两个方法:

    • get_all_history(): 获取所有的浏览历史,list 类型。每一个元素为 dict 类型
    • save_db(): 将历史记录保存至 sqlite 数据库 (history.db3,硬编码)

    BiliHistory 类的完整代码如下:

    class BiliHistory(object):
    
        def __init__(self, cookie_file):
            self.base_url = "https://api.bilibili.com/x/web-interface/history/cursor"
            self.cookie = self._get_cookie_content(cookie_file)
            self.request_headers = self._set_req_headers()
     
        def _get_cookie_content(self, cookie_file):
            """从cookies.txt中读取cookie"""
    
            with open(cookie_file, 'r') as fp:
                cookies = fp.read()
                return cookies
    
        def _set_req_headers(self):
            """设置请求头:1)模拟浏览器;2)提供cookie"""
    
            headers = {
            "Accept": "*/*",
            "Accept-Encoding": "gzip, deflate, br",
            "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
            "Connection": "keep-alive",
            "Cookie": self.cookie,
            "Host": "api.bilibili.com",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "  \
                          "Chrome/88.0.4324.96 Safari/537.36 Edg/88.0.705.50"
            }
            
            return headers
    
        def _get_history(self, max, view_at, business):
            """根据url以及查询字符串中三个参数,获取20个历史记录,
            history_list: 为包含dict的列表,每一个list是一个历史记录
            cursor: 下一个请求的cursor信息
            """
    
            url = self.base_url + f"?max={max}&view_at={view_at}&business={business}"
            resp = get_response_json(url, self.request_headers)
            history_list = resp.get("data").get("list")
            next_cursor = resp.get("data").get("cursor")
    
            return history_list, next_cursor 
    
        def get_all_history(self):
            """获取所有的的浏览历史记录"""
    
            histories = []
            max = 0
            view_at = 0
            business = ''
            ps = 20
    
            while(ps!=0): # ps为0表示后面没有记录
                history, cursor = self._get_history(max, view_at, business)
                max = cursor.get("max")
                view_at = cursor.get("view_at")
                business = cursor.get("business")
                ps = cursor.get("ps")
    
                for item in history:
                    histories.append(item)
                time.sleep(0.1)
    
            return histories
    
        def save_db(self):
            """保存到sqlite3数据库"""
    
            histories = self.get_all_history()
            for item in histories:
                history = item.get("history")
                view_time = item.get("view_at")
    
                # 如果记录不在数据库中,则新增记录
                if is_url_exists(view_time) == False:
                    url_content = {
                        "title": item.get("title"),
    
                        "business": history.get("business"),
                        "bvid": history.get("bvid"),
                        "cid": history.get("cid"),
                        "epid": history.get("epid"),
                        "oid": history.get("oid"),
                        "page": history.get("page"),
                        "part": history.get("part"),
                        "dt": history.get("dt"),
    
                        "author_name": item.get("author_name"),
                        "videos": item.get("videos"),
                        "is_fav": item.get("is_fav"),
                        "tag_name": item.get("tag_name"),
                        "view_at": item.get("view_at"),
                        "progress": item.get("progress"),
                        "show_title": item.get("show_title"),
                        "cover": item.get("cover"),
                        "uri": item.get("uri")
                    }
                    create_url_info(url_content)
    

    每次获取 20 条记录,在每次 Http 请求后,暂停 0.2 秒钟。

    数据保存到数据库

    使用 sqlalchemy ORM 的数据创建和查询功能。sqlalchemy 的用法本篇不讲述,只提供数据库操作的代码。有需要的小伙伴请参考我的博客:SQLAlchemy简明教程

    数据库操作的相关代码如下:

    from sqlalchemy import create_engine
    from sqlalchemy.orm import sessionmaker
    from model import BiliHistory
    
    engine = create_engine("sqlite:///history.db3", echo=False)
    session = sessionmaker(bind=engine)()
    
    def is_url_exists(view_time):
        """根据浏览时间判断记录是否存在"""
        item = session.query(BiliHistory).filter(BiliHistory.view_at==view_time).first()
        return item != None
    
    
    def create_url_info(url):
        url = BiliHistory(
            title = url.get("title"),
    
            business = url.get("business"),
            bvid = url.get("bvid"),
            cid = url.get("cid"),
            epid = url.get("epid"),
            oid = url.get("oid"),
            page = url.get("page"),
            part = url.get("part"),
            dt = url.get("dt"),
    
            author_name = url.get("author_name"),
            videos = url.get("videos"),
            is_fav  = url.get("is_fav"),
            tag_name = url.get("tag_name"),
            view_at = url.get("view_at"),
            progress = url.get("progress"),
            show_title = url.get("show_title"),
            cover =url.get("cover"),
            uri = url.get("uri")
        )
    
        session.add(url)
        session.commit()
        session.close()
    

    源码

    github - bilibili history

    参考

    Bilibili 历史记录API

    展开全文
  • 如何用Matlab一键下载B站高清视频(上)如何用Matlab一键下载B站高清视频(上)0. 前言1. 模拟鼠标键盘2. Matlab 与 ie 交互3. 最后 如何用Matlab一键下载B站高清视频(上) 0. 前言 关注B站两年有余,有时看到...

    如何用Matlab一键下载B站高清视频(上)

    0. 前言

    关注B站两年有余,有时看到有意思的视频很想保存下来,但在播放界面只能眼睁睁看着,找不到保存的按键…

    在这里插入图片描述

    特别对于有些学习类的视频教程,很想保存到本地以方便观看,可能 wifi 并不是无处不在,在线观看还是有一定流量成本的,那么在有免费上网的地方,有必要薅一把羊毛。

    经过网上一顿狂搜,最终发现了一个非常好的B站1080p视频解析网站,名称为:贝贝bilibili-B站视频下载

    在这里插入图片描述

    如上图所示,该网站的使用非常简单,我们只需要输入B站中视频的播放地址,然后点击**<<解析视频>>**按键就可以响应得到解析后的重要视频信息了,如标题,作者,链接等。可以说这是个非常良心的API接口网站了,此处送上万千个热烈掌声…

    下面以尚硅谷的 Web前端HTML5&CSS3初学者零基础入门全套完整版 视频下载为例,简要说明主要的下载过程。

    在这里插入图片描述

    我们把请求地址复制粘贴到 贝贝bilibili 中,响应得到的信息如下:

    在这里插入图片描述

    然后,直接复制表单中的 mp4 播放地址 ,在浏览器中打开就可以下载视频了!

    在这里插入图片描述

    这样机械式地下载愉快是愉快(终于可以下载B站视频了),但是面对这种教学视频,动辄就是百十来个,难道我们一个视频接一个视频的这样下载吗?愉快中增添了不少哀叹!

    但对于一位 Matlab 爱好者 来说岂能这样麻烦呢,何不解放双手?

    在这里插入图片描述

    网上查了下标准的 贝贝bilibili 网址接口:https://xbeibeix.com/api/bilibili/biliplayer/?url= ,其中参数 url后面输入的是B站视频播放地址,但在抓包的过程中我彻底失败了,因为这个页面根本就没怎么响应啊 (如下动图所示),抓神马包呢,原谅我的无知,请知道的朋友们指点指点。

    在这里插入图片描述

    在这里插入图片描述

    好吧,抓包失败了,看来得开启”曲线救国“路线了…

    1. 模拟鼠标键盘

    ”曲线救国“ 之模拟鼠标键盘:我们日常工作中凡是批量、重复性的工作,都是能用模拟鼠标键盘帮我们完成的,比如通过 贝贝bilibili 网站下载B站视频这件事。

    在介绍这部分之前,我强烈推荐一个优质的公众号:打浦桥程序员,这个公众号是与Matlab、提高工作效率技术相关,是我经常性保持阅读的公众号,其中原创性的东西非常多,朋友们可以关注关注。

    接下来用到的 ”利用Matlab模拟鼠标键盘“ 功能,即 “HaoTemplate” 中的鼠标精灵GUI工具就来源于此公众号,具体使用细节可以移步这里—> 一起摸鱼吗?用MATLAB全自动的那种…

    下面来聊聊模拟的具体过程:

    Step 1 首先得用 Matlab 打开本地浏览器并输入目标网址:https://xbeibeix.com/api/bilibili,进入 贝贝bilibili 网站首页,请求的源代码如下:

    function openMicroEdge(url)
    edgePath = '"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"';
    edgeCmd = sprintf('%s %s', edgePath, url);
    system(edgeCmd);
    end  % end function
    

    注意:edgePath 替换为我们本地浏览器所在地址,不同电脑的不同浏览器安装位置可能不太一样。

    调用源代码:

    openMicroEdge('https://xbeibeix.com/api/bilibili');
    

    Step 2 构造并复制B站待下载的视频地址,鼠标左键点击一下输入框,然后全选输入框中的内容,再按键 backspace清除内容,最后按快捷键 Ctrl+V 就将目标地址输入到 贝贝bilibili 的表单中,待网页加载完毕后,鼠标移动 <<解析视频>> 位置,鼠标左键点击 <<解析视频>>。这些过程可以利用 鼠标精灵GUI工具 帮我们完成,将生成的模拟鼠标键盘代码稍加修改就可以了,代码如下:

    import java.awt.Robot;
    import java.awt.event.*;
    vb = actxserver('wscript.shell');
    robot = Robot;
    
    url = 'https://www.bilibili.com/video/BV1XJ411X7Ud?p=1';
    clipboard('copy', url)
    pause(8)
    % 创建鼠标键盘模拟代码
    % 移动到点 (41,122)
    robot.mouseMove(-1, -1);
    robot.mouseMove(41, 122);
    pause(0.2)
        
    % 左键点击
    robot.mousePress(InputEvent.BUTTON1_MASK );
    robot.mouseRelease(InputEvent.BUTTON1_MASK );
    pause(0.2)
        
    % 快捷键操作: control+a
    vb.SendKeys('^a');
    pause(0.2)
        
    % 快捷键操作: backspace
    vb.SendKeys('{backspace}');
    pause(0.2)
        
    % 快捷键操作: control+v
    vb.SendKeys('^v');
    pause(0.2)
        
    % 移动到点 (833,114)
    robot.mouseMove(-1, -1);
    robot.mouseMove(833, 114);
    pause(0.2)
        
    % 左键点击
    robot.mousePress(InputEvent.BUTTON1_MASK );
    robot.mouseRelease(InputEvent.BUTTON1_MASK );
    pause(randNum(1))
    

    Step 3 待响应后,需要进行翻页(下拉)到底部操作(按键 ‘PageDown’ 按个两三次,为保证彻底下拉到网页底部,我们这里选择按下3次 ‘PageDown’),然后移动鼠标到title的位置,鼠标左键点击,再按快捷键 ‘Ctrl + A’ 和 ‘Ctrl + C’,这样我们就得到了视频的标题,保存视频会用到,这一步的代码如下:

    % 快捷键操作: pagedown
    for ii = 1 : 3
        vb.SendKeys('{pgdn}');
        pause(0.5)
    end
    % ---------------------------------------
    % Get vedio title
    % ---------------------------------------
    % 移动到点 (94,476)
    robot.mouseMove(-1, -1);
    robot.mouseMove(95, 451);
    pause(0.5)
    
    % 左键点击
    robot.mousePress(InputEvent.BUTTON1_MASK );
    robot.mouseRelease(InputEvent.BUTTON1_MASK );
    pause(0.5)
    
    % 快捷键操作: control+a
    vb.SendKeys('^a');
    pause(1)
    
    % 快捷键操作: control+c
    vb.SendKeys('^c');
    pause(1)
    title = clipboard('paste');
    titles = split(title, ' ');
    vedioTitle = titles{2};
    

    Step 4 获取解析后视频的地址:鼠标移动到 “mp4地址” 位置处,鼠标左键点击,快捷键 ‘Ctrl + A’ 和 ‘Ctrl + C’, 这一步代码如下:

    % ---------------------------------------
    % Get vedio url
    % ---------------------------------------
    % 移动到点 (168,772)
    robot.mouseMove(-1, -1);
    robot.mouseMove(128, 727);
    pause(0.3)
    
    % 左键点击
    robot.mousePress(InputEvent.BUTTON1_MASK );
    robot.mouseRelease(InputEvent.BUTTON1_MASK );
    pause(0.3)
    
    % 快捷键操作: control+a
    vb.SendKeys('^a');
    pause(1)
    
    % 快捷键操作: control+c
    vb.SendKeys('^c');
    pause(1)
    
    vedioUrl = clipboard('paste');
    

    Step 5 利用 websave下载视频 outFileName = websave(vedioName, vedioUrl);

    Step 6 视频下载完成后,需要移动到 贝贝bilibili 的输入网址界面,那就需要快捷键 ”PageUp“ 上拉页面操作了,这里按键 3 次,以保证上拉到最顶部,操作代码如下:

    % 快捷键操作: pageup
    for ii = 1 : 3
        vb.SendKeys('{pgup}');
        pause(0.5)
    end
    

    以上是下载一个视频的模拟过程,下载多个视频时可以用 for 循环来完成,需要注意的是上述代码中有很多暂停的地方,这是因为网页需要加载,需要时间,如果不暂停的话,会错误操作页面的,也就得不到我们想要的模拟请求。

    下面是最终效果演示动图:

    在这里插入图片描述

    查看下载的部分视频:

    在这里插入图片描述

    模拟鼠标键盘的方法有一定的局限性,比如开始下载视频的时候,不能干其它的事情,如打开文件夹,打开其他软件等都会受到影响,因为程序要不断与浏览器界面交互;当然这对闲置的电脑这样做是完全没问题的。

    知识渊博的朋友们可能已经知道了,上面这种操作是一种表单提交的问题,比如日常生活中登录微博等操作,需要向表单中提交 “用户名” 和 “登录密码” 等,然后点击登录,将表单数据发送给服务器端, 网页就会有个响应…这可以用模拟浏览器的方式完成

    接下来我们利用 “Matlab 与 IE浏览器” 交互的方式爬取视频。

    2. Matlab 与 ie 交互

    这部分的逻辑其实很简单,即把目标网址提交到输入表单中,然后点击 <<解析视频>> 按键。那关键是如何定位输入表单所在的元素呢?

    浏览器中打开 https://xbeibeix.com/api/bilibiliF12后查看 ‘Elements’ , 定位如下图所示:

    在这里插入图片描述

    我们可以看到 <input> 这个元素有个参数 class ,值为 form-control 。同样的方法可以定位到 <<解析视频>> 按键的,为 btn btn-block btn-dark

    这部分的核心代码如下:

    try
        ie = actxGetRunningServer('internetexplorer.application');
    catch
        ie = actxserver('internetexplorer.application');
    end
    
    inputUrl = ie.document.body.getElementsByClassName('form-control').item(1);
    inputUrl.value = url;
        
    jiexiBtn = ie.document.body.getElementsByClassName('btn btn-block btn-dark').item(0);
    jiexiBtn.click;
    

    表单提交,网页响应之后可以爬取我们所需要的重要信息了:视频标题 title 和 解析后的视频链接 url

    通过 htmlContent = ie.document.body.innerHTML; 就可以得到详细的文本信息,再利用正则表达式匹配需要的信息。

    核心代码如下:

    % ---------------------------------------
    %  Get title
    % ---------------------------------------
    pat = '(?<=<input class="form-control" aria-describedby="basic-addon1" type="text" readonly="" value=").*?(?=">)';
    titles = (regexp(htmlContent, pat, 'match'))';
    vtitles = split(titles{2}, ' ');
    videoTitle = vtitles{2};
    
    textContent = ie.document.body.innerText;
    % ---------------------------------------
    %  Get video url
    % ---------------------------------------
    pat = 'https://upos-sz.+logo=80000000';
    videoUrls = (regexp(textContent, pat, 'match'))';
    videoUrl = videoUrls{1};
    

    最后还是利用 websave 保存视频了。

    最终效果如下:

    在这里插入图片描述

    保存的部分视频:

    在这里插入图片描述

    利用 “Matlab 与 IE浏览器” 交互的方式速度上要比第一种方式有很大提升,再者爬取视频的过程中可以干其他事情了,这是很推荐的一种方法,终于可以愉快的玩耍了…

    3. 最后

    其实,除了上面介绍的两种方法外,我们还有另外一种常见的方式了,还是通过API接口,通过 weboptions 设置请求头参数,可以直接响应来获得结构化的数据,如 json 数据,再进行解析,这样就更方便了。这部分内容留到下次再介绍…

    要想获取今天介绍的源代码,请在公众号后台回复:bilibli视频(上)

    今天的内容就分享到这里,希望朋友们喜欢,最后祝大家生活愉快!

    展开全文
  • 爬取B站视频 - m4s文件的相关研究

    万次阅读 2019-10-31 09:35:24
    b站视频怎么保存在手机本地 偶遇的网站: 看哔哩哔哩 唧唧-哔哩哔哩唧唧-bilibili视频|弹幕在线下载 BiliPlus , ( ゜- ゜)つロ 乾杯~ 爱哔哩(bilibili视频、音频mp3解析下载站) 爬取B站视频 目录 一、前言 ↶ ...

    相关教程的直通车:

    偶遇的网站:

    爬取B站视频

    目录

    一、前言 ↶

    最近一段时间,突然想爬B站视频,发现竟然不是flv格式的视频文件了,全变成一堆的m4s格式的文件,那怎么办,视频没办法正常的爬取,所以我就上网收集资料,研究了一下,算是可以解决如何爬取B站视频了,可能不是很好地办法,但是不管怎么样,只要能到达自己的目的,也算是成功了。

    二、分析思路 ↶

    1. 首先要解决的问题:什么是m4s文件
      在这里插入图片描述
      这大概就是说明了,m4s格式文件的确是我们要的视频。
    2. 测试视频:av55287468【PS.长短视频的方法是差不多的,这里就以短视频为例】
      在这里插入图片描述
    3. 同样的,先从F12开始
      在这里插入图片描述
      得到一堆文件
    4. 查看其中比较典型的两种文件
      一个是30280.m4s,对应了音频文件
      在这里插入图片描述
      另一种是30064.m4s,对应了视频文件
      在这里插入图片描述
      至于区别方式,可以从它们视频传到最后的字节大小来看:
      用Fiddler抓包,这一块就比较清晰:
      在这里插入图片描述
      在这里插入图片描述
      从单个数据包大小就可以分辨出音频和视频。当然,至于为什么它们就是音频和视频,一开始我也是不知道的,但是在查找资料的过程中,猜测最后验证的确如此:
      在这里插入图片描述
    5. 接下来的操作,比较重要,毕竟传来的是一堆视频流,总不可能全部下载下来,这不实际。事实上,在请求头中,有一个Range参数,管控了bytes字节传输的大小。
      在这里插入图片描述
      只要改成下面这种格式就可以下载完整的视频或音频:
      在这里插入图片描述
      xxxxxx-一般指的是最大的字节量,只不过去掉这行就无法下载。
      那么,最大的字节量该怎么得到呢?可以在响应头查看到最大字节。
      在这里插入图片描述
      那么,到这里理论上就可以爬取视频或音频。

    三、视频和音频下载 ↶

    接下来就实际操作下载的流程,当然具体爬取方法有很多,可以自行选择,这里就用我认为最方便的爬取方法,缺点爬取文件不能太大。

    依旧使用强大的Fiddler神器:

    1. 抓包
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
    2. Composer构造请求
      在这里插入图片描述
      在这里插入图片描述
    3. Execute执行
      在这里插入图片描述
    4. 导出
      在这里插入图片描述
    5. 保存
      在这里插入图片描述
    6. 结果
      在这里插入图片描述

    四、转换和混流 ↶

    目前仍然有两个问题:

    1. 下载的文件,一般情况来说,没办法打开(除非有我不知道的东西可以打开),就必须对它进行转换格式
    2. 视频是无声的,音频是无画面的,还是没有良好的体验,就必须对它进行混流操作,将两者结合起来
      这里,我采用的是用户友好型的软件 —— 格式工厂,无脑操作即可。
      那么,接下来简单演示一下:
      m4s -> mp4
      在这里插入图片描述
      m4s -> mp3
      在这里插入图片描述
      混流 = MP3 + MP4
      在这里插入图片描述
      最后的成品:
      完美,既有声音又有画面。
      在这里插入图片描述

    五、总结 ↶

    比较具体的写了m4s文件的相关内容,加上之前那一篇爬取B站flv视频的博文,基本上B站大部分的视频(非会员),都能爬取下来。B站视频爬取的相关博文就差不多结束了,除非B站视频又有大改动。当然,在这个过程中,感悟心得也是挺多的,那么就继续加油吧!

    后记

    原来把 m4s 直接改成 mp4 或者 mp3 就能直接播放,ლ(′◉❥◉`ლ)。。。,不过还是需要合并成一个视频才行。

    ————————————————
    版权声明:本文为CSDN博主「小黑LLB」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/Enderman_xiaohei/article/details/94718494

    展开全文
  • 首先,我们先试着实现爬取一个视频保存本地,随便在哔哩哔哩网站找一个视频,如我找的一个链接:https://www.bilibili.com/video/BV1Sz4y1Z7g9?from=search&seid=7693898795687978846 右键检查,点击network抓...

    初级版本

    首先,我们先试着实现爬取一个视频保存到本地,随便在哔哩哔哩网站找一个视频,如我找的一个链接:https://www.bilibili.com/video/BV1Sz4y1Z7g9?from=search&seid=7693898795687978846

    右键检查,点击network抓包,点击播放:
    在这里插入图片描述
    我们会看到很多的数据包,经过尝试分析我们点开带30280,会看到response响应部分就是很多我们看不懂的编码二进制数据,实际上30280数据包就是是一个纯音频文件(没有画面),而30080数据包是一个纯视频文件(没有声音),那么现在思路就有了,我们想办法把视频和音频文件都爬取下来,然后再想办法合成不就行了?
    在这里插入图片描述
    效率较低的方式,便是利用第三方库moviepy合成,准备工作需要安装moviepy,安装命令:pip install moviepy -i http://pypi.douban.com/simple/
    代码实现如下:

    import requests
    from moviepy.editor import *
    if __name__ == '__main__':
        # 1.确认url
        url_30080 = 'https://cn-jxnc-cmcc-bcache-06.bilivideo.com/upgcxcode/91/22/237582291/237582291_nb2-1-30080.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEqxTEto8BTrNvN0GvT90W5JZMkX_YN0MvXg8gNEV4NC8xNEV4N03eN0B5tZlqNxTEto8BTrNvNeZVuJ10Kj_g2UB02J0mN0B5tZlqNCNEto8BTrNvNC7MTX502C8f2jmMQJ6mqF2fka1mqx6gqj0eN0B599M=&uipk=5&nbs=1&deadline=1605200882&gen=playurl&os=bcache&oi=3719332261&trid=aa176f00ecf448b294d69b0cf06670f8u&platform=pc&upsig=efa32de99996e526857889b34eca24a1&uparams=e,uipk,nbs,deadline,gen,os,oi,trid,platform&cdnid=4205&mid=440047762&orderid=0,3&agrr=0&logo=80000000'
        url_30280 = 'https://upos-sz-mirrorcos.bilivideo.com/upgcxcode/91/22/237582291/237582291_nb2-1-30280.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEqxTEto8BTrNvN0GvT90W5JZMkX_YN0MvXg8gNEV4NC8xNEV4N03eN0B5tZlqNxTEto8BTrNvNeZVuJ10Kj_g2UB02J0mN0B5tZlqNCNEto8BTrNvNC7MTX502C8f2jmMQJ6mqF2fka1mqx6gqj0eN0B599M=&uipk=5&nbs=1&deadline=1605200882&gen=playurl&os=cosbv&oi=3719332261&trid=aa176f00ecf448b294d69b0cf06670f8u&platform=pc&upsig=2ae2924502e57ee4ab092da37af359ba&uparams=e,uipk,nbs,deadline,gen,os,oi,trid,platform&mid=440047762&orderid=0,3&agrr=0&logo=80000000'
        # 设置用户代理
        headers_ = {
            'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36',
            'Referer':'https://www.bilibili.com/video/BV1CT4y1w7Ed?from=search&seid=6176037271681914381'
        }
    
        # 2.发送请求得到响应
        response_30080 = requests.get(url_30080,headers=headers_)
        response_30280 = requests.get(url_30280,headers=headers_)
    
        data_30080 = response_30080.content
        data_30280 = response_30280.content
    
        # 保存
        with open('斗罗大陆_30080.mp4','wb') as f:
            f.write(data_30080)
    
        with open('斗罗大陆_30280.mp3','wb') as f:
            f.write(data_30280)
    
        """
        在拥有了一个纯视频文件,跟一个纯音频文件的情况下......
        利用第三方库moviepy合成():速度很慢  
        """
    
        # 选择一个已经拥有的纯视频文件
        video_obj = VideoFileClip('斗罗大陆_30080.mp4')
    
        # 选一个对应已拥有的纯音频文件
        audio_obj = AudioFileClip('斗罗大陆_30280.mp3')
    
        # 往视频对象里面添加音频
        movie_ = video_obj.set_audio(audio_obj)
    
        # 保存
        movie_.write_videofile('斗罗大陆_.mp4')
    
    

    过程(效率极低,贼慢(大概5-10分钟),提前打招呼。。。建议趁这段时间听听音乐看看小视频打发一下时间~):
    在这里插入图片描述
    废了老大时间,终于跑完了,控制台结果是这样的:
    在这里插入图片描述
    在当前路径下,打开合成后的mp4文件,播放效果如下:
    在这里插入图片描述

    有声音有画面,证明我们已经成功实现了一个视频的爬取,但是使用moviepy合成音视频文件是不是太慢了,这么费时间怎么让人受的了?有没有更高效的方法?当然有,下面介绍一款强大的视频合成利器。

    改进版本

    准备工作:安装配置ffmpeg
    那什么是ffmpeg呢?百度上给出了这样的定义:FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。我们只需要知道ffmpeg是一款非常好用处理音视频的工具包就行了,如果想深入了解大家可以自行在网上找一些学习资料,我们今天的目的只有一个:合成音视频!
    ffmpeg功能强大,但我们首先得学会对其进安装(windows下安装),很简单的,下载解压后配置好环境变量就OK了。
    安装参考链接:Windows安装配置ffmpeg

    安装好之后我们就可以用代码控制ffmpeg合成音视频文件了,代码编写如下:

    import requests
    import os
    if __name__ == '__main__':
        # 1.确认url
        url_30080 = 'https://cn-jxnc-cmcc-bcache-06.bilivideo.com/upgcxcode/91/22/237582291/237582291_nb2-1-30080.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEqxTEto8BTrNvN0GvT90W5JZMkX_YN0MvXg8gNEV4NC8xNEV4N03eN0B5tZlqNxTEto8BTrNvNeZVuJ10Kj_g2UB02J0mN0B5tZlqNCNEto8BTrNvNC7MTX502C8f2jmMQJ6mqF2fka1mqx6gqj0eN0B599M=&uipk=5&nbs=1&deadline=1605200882&gen=playurl&os=bcache&oi=3719332261&trid=aa176f00ecf448b294d69b0cf06670f8u&platform=pc&upsig=efa32de99996e526857889b34eca24a1&uparams=e,uipk,nbs,deadline,gen,os,oi,trid,platform&cdnid=4205&mid=440047762&orderid=0,3&agrr=0&logo=80000000'
        url_30280 = 'https://upos-sz-mirrorcos.bilivideo.com/upgcxcode/91/22/237582291/237582291_nb2-1-30280.m4s?e=ig8euxZM2rNcNbdlhoNvNC8BqJIzNbfqXBvEqxTEto8BTrNvN0GvT90W5JZMkX_YN0MvXg8gNEV4NC8xNEV4N03eN0B5tZlqNxTEto8BTrNvNeZVuJ10Kj_g2UB02J0mN0B5tZlqNCNEto8BTrNvNC7MTX502C8f2jmMQJ6mqF2fka1mqx6gqj0eN0B599M=&uipk=5&nbs=1&deadline=1605200882&gen=playurl&os=cosbv&oi=3719332261&trid=aa176f00ecf448b294d69b0cf06670f8u&platform=pc&upsig=2ae2924502e57ee4ab092da37af359ba&uparams=e,uipk,nbs,deadline,gen,os,oi,trid,platform&mid=440047762&orderid=0,3&agrr=0&logo=80000000'
        # 设置用户代理
        headers_ = {
            'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36',
            'Referer':'https://www.bilibili.com/video/BV1CT4y1w7Ed?from=search&seid=6176037271681914381'
        }
    
        # 2.发送请求得到响应
        response_30080 = requests.get(url_30080,headers=headers_)
        response_30280 = requests.get(url_30280,headers=headers_)
    
        data_30080 = response_30080.content
        data_30280 = response_30280.content
    
        # 保存
        with open('斗罗大陆30080.mp4','wb') as f:
            f.write(data_30080)
            print('纯视频文件下载完毕......')
        with open('斗罗大陆30280.mp3','wb') as f:
            f.write(data_30280)
            print('纯音频文件下载完毕......')
        # 利用第三方工具ffmpeg 合成视频, 需要执行终端命令
        os.system('ffmpeg -i 斗罗大陆30280.mp3 -i 斗罗大陆30080.mp4 -c copy 斗罗大陆.mp4 -loglevel quiet')
        # 后面的-loglevel quiet加不加无所谓,不加控制台会出现红色的log日志但不影响代码功能。
        print('视频合成成功......')
    

    可以看到瞬间就合成成功了,打开看看效果,完全不差:
    在这里插入图片描述
    我们再比较一下内存大小,同样的音视频文件使用moviepy合成的mp4文件大小为120404KB

    在这里插入图片描述
    而使用ffnpeg合成的mp4文件大小为74273KB,接近音视频大小加起来的总和,合成后的画质音质也是无损的,所以无论是从时间效率还是从空间损耗方便来讲,可以说ffmpeg完虐moviepy!
    在这里插入图片描述
    仔细想想我们只想要合成后的视频文件,分开的音视频文件没啥用,白白的占用了内存,想到这里代码还可以再优化一下,在合成后删除音视频文件即可,那我们只需要在以上代码最后加上两行删除指令的代码即可:

     os.system('del 音频名称.mp3')
     os.system('del 视频名称.mp4')
    
    

    这两行代码调用的是操作系统的指令删除的,也可以用remove删除,即os.remove(‘音频名称.mp3’),这个无所谓,只要能达到删除目的就行。

    升级版本

    到目前为止,我们已经能爬取指定的视频了,但是爬一个视频我们就要解析30080,30280的数据包获取相关url对我们来说是非常不便的。我们想要达到的效果是输入目标视频的url直接就能下载视频。
    开始尝试解决,

    1. 复制纯视频url进行全局搜索,右上角三个点,菜单栏选择search
      在这里插入图片描述

    2. 把https删掉s 进行搜索,找到了该文件(存有我们纯视频url)

    在这里插入图片描述
    3. 点开那条搜索数据,点击pretty-print 格式化输出
    在这里插入图片描述
    4.点击文件区域,ctrl + f 继续搜索
    在这里插入图片描述

    发现纯视频文件的url 和纯音频文件的url都在同一个文件当中, 如果我们能够获取到这个文件的response,那么就能够提取出url进行请求,保存,合成…

    该文件实际为url地址栏的url请求对应的response,那解析出视频音频文件url就简单了,我们可以使用用正则提取,其实仔细分析可以发现我们还可以指定清晰度版本,就是那个id,80,64,32等等就是对应的版本,我们这里不再赘述,直接爬取最高画质,要搞就搞最好的,编写代码如下:

    import re
    import os
    
    if __name__ == '__main__':
        url  = input('请输入要下载的视频url:')
    
        headers ={
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36",
            "cookie": "_uuid=425019D2-6E06-C2BA-320C-989D73E268D379095infoc; buvid3=A7BFF32C-6475-484D-AD68-D6B1633AD9CE53937infoc; LIVE_BUVID=AUTO3815878009223382; rpdid=|(J~R~kuRY)l0J'ul)~)||mkJ; DedeUserID=440047762; DedeUserID__ckMd5=ad5ddee3544a770f; SESSDATA=d392227d%2C1604025506%2C3577b*51; bili_jct=883303557689d9fa49b97229f5837edd; CURRENT_QUALITY=64; PVID=1; CURRENT_FNVAL=80; blackside_state=1; bsource=search_baidu; sid=kjvz5hpk"
        }
    
        res = requests.get(url,headers =headers).text
        html = etree.HTML(res)
        str_url_list = html.xpath('//script[contains(text(),"window.__playinfo__")]/text()')[0]
        audio_str = re.findall(r'"audio":\[{"id":30280,"baseUrl":"(.*?)"', str_url_list)[0]
        vidio_str = re.findall(r'"video":\[{"id":80,"baseUrl":"(.*?)"',str_url_list)[0]
    
        # print("音频:",audio_str)
        # print("视频:", vidio_str)
        headers = {
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36",
            "referer":url
        }
        audio_response = requests.get( audio_str,headers=headers).content
        vidio_response = requests.get(vidio_str, headers=headers).content
    
        with open('音频.mp3','wb') as f:
            f.write(audio_response)
    
        with open('视频.mp4','wb')as f:
            f.write(vidio_response)
    
        os.system('ffmpeg -i 音频.mp3 -i 视频.mp4 -c copy 合成后的视频.mp4 -loglevel quiet')
        time.sleep(2)
        os.system('del 音频.mp3')
        os.system('del 视频.mp4')
    

    随便找一个视频复制url尝试一下,我用的这个url(斗罗大陆小姐姐):

    https://www.bilibili.com/video/BV19C4y147GK?from=search&seid=7693898795687978846

    下载成功:在这里插入图片描述
    打开合成好的视频,效果:
    在这里插入图片描述

    最终加强版本

    优化:

    • 问题1:我们下载下来的视频名称是否能够改成网页视频原名?

    可行性分析: 网页里面的视频名称,已知网页为html数据,名称也可以使用xpath调试拿到。

    • 问题2: 这个视频可以利用//span[@class=“tit”]/text() 取到视频名称
    • 在这里插入图片描述

    其他视频有的,xpath语法并不通用,改xpath取视频名称通用 //title/text()
    在这里插入图片描述

    需要切割后面多余的部分,可以通过xpath语法提取到名称,再进行一个切片,正则提取就可以了

    • 问题3: 视频的名称中,如果包含 空格 / & 都会影响到视频的合成
      解决办法, 去掉名称中的 空格 / & 等特殊字符

    • 问题4:title_ = 斗罗大陆
      纯视频文件: 斗罗大陆!.mp4
      纯音频文件: 斗罗大陆!.mp3
      合成的文件: 斗罗大陆.mp4
      为了避免因为重名造成的问题,可以添加一个字符,改变一下视频名称,避免重名。

    • 问题5:如何在控制台想显示文件的大小.
      –1,发送请求的时候,参数添加stream=True
      –2.获取大小

    参考代码如下:

    
    import requests
    import os
    from lxml import etree
    import re
    
    if __name__ == '__main__':
        # 输入网页的url
        url_ = input('请输入一个网址:')
    
        # 设置用户代理,cookie
        headers_ = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36',
            'Cookie': "INTVER=1; _uuid=09E58359-9210-BAEE-1A60-4EE46A2B82C655513infoc; sid=5ytmp0pi; LIVE_BUVID=AUTO6515760552512495; stardustvideo=1; laboratory=1-1; rpdid=|(umuum~uku|0J'ul~Y|llkl); buvid3=684E90B9-B796-4512-AE61-CED715ED0D2B53931infoc; stardustpgcv=0606; finger=158939783; DedeUserID=246639322; DedeUserID__ckMd5=0de51babcf36bfe1; SESSDATA=0453e7c3%2C1613286482%2C848b7*81; bili_jct=05a501d5099630a42cb271cebdbc3470; blackside_state=1; CURRENT_FNVAL=80; CURRENT_QUALITY=80; bsource=search_baidu; PVID=4"
        }
    
        # 发送请求,得到响应对象
        response_ = requests.get(url_, headers=headers_)
    
        str_data = response_.text  # 视频主页的html代码,类型是字符串
    
        # 使用xpath解析html代码,,得到想要的url
        html_obj = etree.HTML(str_data)  # 转换格式类型
    
        # 获取视频的名称
        res_ = html_obj.xpath('//title/text()')[0]
        # 视频名称的获取
        title_ = re.findall(r'(.*?)_哔哩哔哩', res_)[0]
        # 影响视频合成的特殊字符的处理,目前就遇到过这三个,实际上很有可能不止这三个,遇到了就用同样的方法处理就好了
        title_ = title_.replace('/', '')
        title_ = title_.replace(' ', '')
        title_ = title_.replace('&', '')
    
        # 使用xpath语法获取数据,取到数据为列表,索引[0]取值取出里面的字符串,即包含视频音频文件的url字符串
        url_list_str = html_obj.xpath('//script[contains(text(),"window.__playinfo__")]/text()')[0]
    
        # 纯视频的url
        video_url = re.findall(r'"video":\[{"id":\d+,"baseUrl":"(.*?)"', url_list_str)[0]
    
        # 纯音频的url
        audio_url = re.findall(r'"audio":\[{"id":\d+,"baseUrl":"(.*?)"', url_list_str)[0]
    
        # 设置跳转字段的headers
        headers_ = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36',
            'Referer': url_
        }
    
        # 获取纯视频的数据
        response_video = requests.get(video_url, headers=headers_, stream=True)
        bytes_video = response_video.content
        # 获取纯音频的数据
        response_audio = requests.get(audio_url, headers=headers_, stream=True)
        bytes_audio = response_audio.content
    
        # 获取文件大小, 单位为KB
        video_size = int(int(response_video.headers['content-length']) / 1024)
        audio_size = int(int(response_audio.headers['content-length']) / 1024)
    
        # 保存纯视频的文件
        title_1 = title_ + '!'  # 名称进行修改,避免重名
        with open(f'{title_1}.mp4', 'wb') as f:
            f.write(bytes_video)
            print(f'{title_1}纯视频文件下载完毕...,大小为:{video_size}KB, {int(video_size/1024)}MB')
    
        with open(f'{title_1}.mp3', 'wb') as f:
            f.write(bytes_audio)
            print(f'{title_1}纯音频文件下载完毕...,大小为:{audio_size}KB, {int(audio_size/1024)}MB')
    
            # 利用第三方工具ffmpeg 合成视频, 需要执行终端命令
        os.system(f'ffmpeg -i {title_1}.mp3 -i {title_1}.mp4 -c copy {title_}.mp4 -loglevel quiet')
    
        # 显示合成文件的大小
        res_ = int(os.stat(f'{title_}.mp4').st_size / 1024)
        print(f'{title_}视频合成成功...,大小为{res_}KB, {int(res_/1024)}MB......')
    
        # 移除纯视频文件,
        os.remove(f'{title_1}.mp4')
        # 移除纯音频文件,
        os.remove(f'{title_1}.mp3')
    

    再随便找一个url 测试,https://www.bilibili.com/video/BV1kp4y1v7QM?from=search&seid=7693898795687978846
    成功!
    在这里插入图片描述
    播放效果:
    在这里插入图片描述
    感谢各位小伙伴的阅读,如有任何问题可在评论区留言或者csdn app发私信给我,看到了一定知无不言言无不尽。。。

    最后送出一些福利,感兴趣的自取:C++及Python人工智能500G+学习资源

    展开全文
  • 064《浮图秀》优雅查看B站视频封面 063《Picviewer CE+》功能丰富的网页看图神器 062《彩云小译》一键实现网页中英文对照的翻译工具 061《ImageAssistant》图片助手批量图片下载器 060《Tabagotchi》为减缓...
  • BiliBiliTool 是一个 B 自动执行任务的工具,当我们忘记做 B 的某项任务时,它会像一个小助手一样,按照我们预先吩咐她的命令,在指定时间、按照指定频率,帮助我们自动完成计划的任务。 比如,当我们忘记领取...
  • 超文本笔记本,可以支持文字,图片,动态图混排,做便签十分方便,注意高清图片会压缩,目前笔记是保存本地 技术分享部分(鸿洋玩Android,还有代码家的干活集中营等等),关于flutter版本的极致体验玩Android客户端 ...
  • 推荐B站上的一个up主的视频,莫烦·Matplotlib中文视频教程——基于python3,看完差不多就OK了 Scipy 因为还不怎么用,所以以后再说吧。。。 Scipy Doc 杂文汇集 Python读取文件以及读取大文件 gensim之Word2...
  • 主要还差一个预览视频与弹幕的功能尚未完成,希望能把B站首页写完,并且会持续更新中,后面可能会加上直播等功能。 相关截图: 首页: 轮播: 直播: 排行: 游戏: 拖拽排序与滚动效果:
  • 实例071 如何将字节单位B转换成GB、MB 和KB 108 实例072 身份证号从15位升到18位算法 109 第3章 面向对象编程思想 111 3.1 面向对象家族核心——类与类成员 112 实例073 面向对象编程核心——类、对象和引用 112 ...
  • 实例071 如何将字节单位B转换成GB、MB 和KB 108 实例072 身份证号从15位升到18位算法 109 第3章 面向对象编程思想 111 3.1 面向对象家族核心——类与类成员 112 实例073 面向对象编程核心——类、对象和引用 112 ...
  • 实例071 如何将字节单位B转换成GB、MB 和KB 108 实例072 身份证号从15位升到18位算法 109 第3章 面向对象编程思想 111 3.1 面向对象家族核心——类与类成员 112 实例073 面向对象编程核心——类、对象和引用 112 ...
  • 网络组建域管理课件2

    2009-02-08 22:29:19
    Web服务把各种形式的信息,如文本、图像、声音和视频等无缝隙地集成在—起,用户只需要通过浏览器提出自己的查询要求,Web服务器自动完成查询结果,并将与查询条件相关的文件取回并显示在屏幕上,用户无需关心这些...
  • 优越感:编辑器全通用单文件控制上传系统,编辑器支持各种类型的图片、动画、音频、视频等格式的上传,完善的订单系统,完整无限制、无误的后台操作平台,支持一级分类打开,横幅、广告图片后台直接覆盖式上传更新...
  • 如何将屏幕左下角设置为屏保。当需要离开座位时,只需将鼠标(或触摸触控板)划至屏幕左下角即可开启屏保功能。 <p><img alt="图:配置 Hot corners" src=...
  • 实例110 使用Process组件访问本地进程 159 3.7 Timer组件 161 实例111 使用Timer组件制作计时器 161 实例112 使用Timer组件显示当前系统时间 165 实例113 使用Timer组件制作左右飘动的窗体 166 实例114 使用Timer...
  • C#程序开发范例宝典(第2版).part02

    热门讨论 2012-11-12 07:55:11
    实例110 使用Process组件访问本地进程 159 3.7 Timer组件 161 实例111 使用Timer组件制作计时器 161 实例112 使用Timer组件显示当前系统时间 165 实例113 使用Timer组件制作左右飘动的窗体 166 实例114 使用...
  • C#程序开发范例宝典(第2版).part13

    热门讨论 2012-11-12 20:17:14
    实例110 使用Process组件访问本地进程 159 3.7 Timer组件 161 实例111 使用Timer组件制作计时器 161 实例112 使用Timer组件显示当前系统时间 165 实例113 使用Timer组件制作左右飘动的窗体 166 实例114 使用...
  • 实例110 使用Process组件访问本地进程 159 3.7 Timer组件 161 实例111 使用Timer组件制作计时器 161 实例112 使用Timer组件显示当前系统时间 165 实例113 使用Timer组件制作左右飘动的窗体 166 实例114 使用...
  • 实例110 使用Process组件访问本地进程 159 3.7 Timer组件 161 实例111 使用Timer组件制作计时器 161 实例112 使用Timer组件显示当前系统时间 165 实例113 使用Timer组件制作左右飘动的窗体 166 实例114 使用...
  • 实例110 使用Process组件访问本地进程 159 3.7 Timer组件 161 实例111 使用Timer组件制作计时器 161 实例112 使用Timer组件显示当前系统时间 165 实例113 使用Timer组件制作左右飘动的窗体 166 实例114 使用...
  • 实例110 使用Process组件访问本地进程 159 3.7 Timer组件 161 实例111 使用Timer组件制作计时器 161 实例112 使用Timer组件显示当前系统时间 165 实例113 使用Timer组件制作左右飘动的窗体 166 实例114 使用...
  • 实例110 使用Process组件访问本地进程 159 3.7 Timer组件 161 实例111 使用Timer组件制作计时器 161 实例112 使用Timer组件显示当前系统时间 165 实例113 使用Timer组件制作左右飘动的窗体 166 实例114 使用...
  • 实例110 使用Process组件访问本地进程 159 3.7 Timer组件 161 实例111 使用Timer组件制作计时器 161 实例112 使用Timer组件显示当前系统时间 165 实例113 使用Timer组件制作左右飘动的窗体 166 实例114 使用...
  • 实例110 使用Process组件访问本地进程 159 3.7 Timer组件 161 实例111 使用Timer组件制作计时器 161 实例112 使用Timer组件显示当前系统时间 165 实例113 使用Timer组件制作左右飘动的窗体 166 实例114 使用...
  • 实例110 使用Process组件访问本地进程 159 3.7 Timer组件 161 实例111 使用Timer组件制作计时器 161 实例112 使用Timer组件显示当前系统时间 165 实例113 使用Timer组件制作左右飘动的窗体 166 实例114 使用...
  • 实例110 使用Process组件访问本地进程 159 3.7 Timer组件 161 实例111 使用Timer组件制作计时器 161 实例112 使用Timer组件显示当前系统时间 165 实例113 使用Timer组件制作左右飘动的窗体 166 实例114 使用...
  • 实例110 使用Process组件访问本地进程 159 3.7 Timer组件 161 实例111 使用Timer组件制作计时器 161 实例112 使用Timer组件显示当前系统时间 165 实例113 使用Timer组件制作左右飘动的窗体 166 实例114 使用...
  • 程序开发范例宝典>>

    2012-10-24 10:41:28
    实例110 使用Process组件访问本地进程 159 3.7 Timer组件 161 实例111 使用Timer组件制作计时器 161 实例112 使用Timer组件显示当前系统时间 165 实例113 使用Timer组件制作左右飘动的窗体 166 实例...

空空如也

空空如也

1 2 3
收藏数 45
精华内容 18
关键字:

b站视频如何保存本地