python之短视频资讯平台

短视频资讯平台

一、软件需求

  • 有video.csv视频库文件,其中有999条短视频数据,格式:id, title, url

  • 项目的核心功能有:查看、搜索、下载

    • 分页看新闻(每页显示10条),提示用户输入页码,根据页码显示指定页面的数据。

      • 提示用户输入页码,根据页码显示指定页面的数据。
      • 当用户输入的页码不存在时,默认显示第1页。
    • 搜索专区

      • 用户输入关键字,根据关键词筛选出所有匹配成功的短视频资讯。
      • 支持的搜索两种搜索格式:
        • id=1715025,筛选出id等于1715025的视频(video.csv的第一列)。
        • key=文本,模糊搜索,筛选包含关键字的所有新闻(video.csv的第二列)。
    • 下载专区

      • 用户输入视频id,根据id找到对应的mp4视频下载地址,然后下载视频到项目的files目录。

        • 视频的文件名为:视频id-年-月-日-时-分-秒.mp4

        • 视频下载代码示例

          import requests
          
          res = requests.get(
              url='https://video.pearvideo.com/mp4/adshort/20210105/cont-1715046-15562045_adpkg-ad_hd.mp4'
          )
          
          # 视频总大小(字节)
          file_size = int(res.headers['Content-Length'])
          
          download_size = 0
          with open('xxx.mp4', mode='wb') as file_object:
              # 分块读取下载的视频文件(最多一次读128字节),并逐一写入到文件中。 len(chunk)表示实际读取到每块的视频文件大小。
              for chunk in res.iter_content(128):
                  download_size += len(chunk)
                  file_object.write(chunk)
                  file_object.flush()
                  message = "视频总大小为:{}字节,已下载{}字节。".format(file_size, download_size)
                  print(message)
              file_object.close()
          
          res.close()
          
        • 下载的过程中,输出已下载的百分比,示例代码如下:

          import time
          
          print("正在下载中...")
          
          for i in range(101):
              text = "\r{}%".format(i)  # \r:覆盖显示
              print(text, end="")
              time.sleep(0.2)
          
          print("\n下载完成")
          

二、目录结构

short_video
├── db                  文件夹,存放数据库的数据
│   └── video.csv
│
├── files               文件夹,存放用户下载的文件
│   └── video_id------.mp4
│
├── src                 包,业务代码
│   ├── service         	包,三大功能
│   	├── download.py     	下载新闻
│   	├── page.py             查看新闻
│   	├── search.py           搜索新闻
│	└── handler.py         逻辑处理文件
│    
├── app.py              启动文件
│
└── config.py           配置文件

三、代码实现

1、config.py

"""
配置文件:保存一些全局变量(大写)
"""
import os

# 当前文件的上级目录:项目根目录
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# 路径拼接:video.csv视频库文件
VIDEO_FILE_PATH = os.path.join(BASE_DIR, 'db', 'video.csv')

2、page.py

"""
分页看新闻(每页显示10条):
    - 提示用户输入页码,根据页码显示指定页面的数据。
    - 当用户输入的页码不存在时,默认显示第1页
"""
import config


def get_page_data(page_num, per_page_count):
    """
    获取一页新闻:根据页码,获取对应页码的新闻列表(每页有10条新闻)
    :param page_num: 页码
    :param per_page_count: 每页数据量
    :return: 数据列表
    """
    # 每页的起始索引
    start_index = (page_num - 1) * per_page_count
    end_index = page_num * per_page_count

    data_list = []      # 每页新闻的数据列表
    read_row_count = 0  # 读取行数的计数:循环控制变量
    with open(config.VIDEO_FILE_PATH, mode='r', encoding='utf-8') as file_object:
        for line in file_object:
            # line:1715046,河北大学取消考试学生紧急离校,老师:回不了家的到老师家过年,https://video...mp4
            if start_index <= read_row_count < end_index:
                data_list.append(line.strip())  # 保存本页数据
            if read_row_count >= end_index:
                break
            read_row_count += 1
    return data_list


def show_table(page_num, per_page_count, data_list):
    """
    展示一页新闻
    :param page_num:页码
    :param per_page_count:每页数据量
    :param data_list:一页的新闻列表
    :return:None
    """
    index = (page_num - 1) * per_page_count + 1  # 一页数据的起始索引
    for num, line in enumerate(data_list, index):
        # line:1715046,河北大学取消考试学生紧急离校,老师:回不了家的到老师家过年,https://video...mp4
        row_list = line.split(',')  # 英文逗号
        # title = row_list[1]             # 索引取值:若标题内有逗号,会显示不全
        title = ",".join(row_list[1:-1])  # 列表切片:排除第一个元素和最后一个元素,剩下的列表元素都是标题,再做拼接
        print(num, ")", title)


def execute():
    """
    查看新闻的执行函数
    """
    print('分页看新闻(每页显示10条新闻)'.center(24, '*'))

    # 每页显示10条、总计999条
    per_page_count, total_count = 10, 999
    # 计算页码最大值(此处是100)
    max_page_num, remainder = divmod(total_count, per_page_count)
    if remainder:
        max_page_num += 1

    while True:
        num = input('请输入页码[范围{}-{}](Q/q退出):'.format(1, max_page_num))
        if num.upper() == 'Q':
            break

        if not num.isdecimal():  # 输入的页码得是十进制整数
            print('页码格式错误,请重新输入!')
            continue

        num = int(num)
        if num < 1 or num > max_page_num:
            # 页码不存在,展示第1页
            num = 1

        page_string = '第{}页'.format(num).center(13, "*")
        print(page_string)

        data_list = get_page_data(num, per_page_count)  # 调用获取一页新闻函数
        show_table(num, per_page_count, data_list)      # 调用展示一页新闻数据函数

3、search.py

"""
搜索专区:
    - 用户输入关键字,根据关键字筛选出所有匹配成功的短视频资讯。
    - 支持两种搜索格式:
      - `id=1715025`,模糊搜索,筛选id等于1715025的新闻(video.csv的第一列)。
      - `key=文本`,模糊搜索,筛选包含关键字的所有新闻(video.csv的第二列)。
"""
import re
import config


def search_by_id(value):
    """
    根据ID精确搜索(一条新闻)
    :param value: 新闻ID
    :return: 一条新闻的数据列表
    """
    datalist = []  # 一条新闻的数据列表
    with open(config.VIDEO_FILE_PATH, mode='r', encoding='utf-8') as file_object:
        for line in file_object:
            # line:1715046,河北大学取消考试学生紧急离校,老师:回不了家的到老师家过年,https://video...mp4
            line = line.strip()
            if value == line.split(',')[0]:  # 1715046
                datalist.append(line)
    return datalist


def search_by_text(value):
    """
    根据文本模糊搜索(一条或多条)
    :param value: 新闻的部分标题文本
    :return: 一条或多条新闻的数据列表
    """
    data_list = []  # 一条或多条新闻的数据列表
    with open(config.VIDEO_FILE_PATH, mode='r', encoding='utf-8') as file_object:
        for line in file_object:
            # line:1715046,河北大学取消考试学生紧急离校,老师:回不了家的到老师家过年,https://video...mp4
            line = line.strip()
            # if value in line.split(',')[1]:             #  索引取值
            if value in ",".join(line.split(',')[1:-1]):  # 列表切片
                data_list.append(line)
    return data_list


def show_table(data_list):
    """
    展示搜索到的新闻
    :param data_list: 新闻的数据列表
    :return: None
    """
    if not data_list:
        print("未搜索到相关信息,换个关键词再试试看!")
    for num, line in enumerate(data_list, 1):
        # line:1715046,河北大学取消考试学生紧急离校,老师:回不了家的到老师家过年,https://video...mp4
        row_list = line.split(',')
        # title = row_list[1]             #  索引取值
        title = ",".join(row_list[1:-1])  # 列表切片
        print(num, ")", title)


def execute():
    """
    搜索新闻的执行函数
    """
    print('搜索专区'.center(12, '*'))

    while True:
        text = input('请输入搜索条件,支持[id=1711349 或 key=文本](Q/q退出):')
        if text.upper() == 'Q':
            break

        match_object = re.match("(id|key)=(\w+)", text.strip())
        if not match_object:
            print("输入格式错误,请重新输入!")
            continue

        name, value = match_object.groups()
        # 函数名的字典:按键取值,先获取函数名,再加括号执行
        mapping = {
            "id": search_by_id,
            "key": search_by_text,
        }

        data_list = mapping[name](value)  # 调用搜索新闻函数
        show_table(data_list)             # 调用展示新闻函数

4、download.py

"""
下载专区:
    - 用户输入视频id,根据id找到对应的mp4视频下载地址,然后下载视频到项目的files目录
    - 视频的文件名为:`视频id-年-月-日-时-分-秒.mp4`
    - 在下载视频的过程中,显示已下载的百分比
"""
import re
import os
import time
from datetime import datetime
import requests
import config


def get_mp4_url(video_id):
    """
    根据视频ID,获取其视频链接
    :param video_id: 视频ID
    :return: 视频链接
    """
    with open(config.VIDEO_FILE_PATH, mode='r', encoding='utf-8') as file_object:
        for line in file_object:
            row_list = line.strip().split(',')
            vid = row_list[0]   # 视频ID
            url = row_list[-1]  # 视频链接
            if video_id == vid:
                return url


def download_mp4(video_id, video_url):
    """
    根据视频ID、视频链接,下载对应的视频
    :param video_id: 视频ID
    :param video_url: 视频链接
    :return: None
    """
    current_datetime = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
    file_path = os.path.join(config.BASE_DIR, 'files', '{}-{}.mp4'.format(video_id, current_datetime))
    res = requests.get(url=video_url)
    print("正在下载中...")

    # 视频总大小(字节)
    file_size = int(res.headers['Content-Length'])
    download_size = 0
    with open(file_path, mode='wb') as file_object:
        # 分块读取下载的视频文件(最多一次读128字节),并逐一写入到文件中。
        for chunk in res.iter_content(128):
            download_size += len(chunk)
            file_object.write(chunk)  # 写入内存
            file_object.flush()       # 刷到硬盘
            # 已下载的百分比
            percent = "\r{}%".format(int(round(download_size / file_size, 2) * 100))  # \r:回车
            print(percent, end="")                                                    # end="":不换行
            # time.sleep(0.2)
        file_object.close()
    print("\n下载完成")
    res.close()


def execute():
    """
    下载新闻的执行函数
    """
    print("下载专区".center(12, '*'))

    while True:
        video_id = input("请输入要下载的视频ID(Q/q退出):")
        if video_id.upper() == 'Q':
            break

        match_group = re.match("\d{7}", video_id.strip())
        if not match_group:
            print("ID格式错误,请重新输入!")
            continue

        video_url = get_mp4_url(video_id)  # 调用获取新闻函数:url
        if not video_url:
            print('视频不存在,请重新输入!')
            continue

        download_mp4(video_id, video_url)  # 调用下载新闻函数

5、handler.py

"""
逻辑处理文件
"""
from src.service import page, search, download  # 导入功能模块


def run():
    func_dict = {
        '1': {'title': "分页看新闻", 'func': page.execute},
        '2': {'title': "搜索专区", 'func': search.execute},
        '3': {'title': "下载专区", 'func': download.execute},
    }
    # tips = ";".join(["{}.{}".format(k, v['title']) for k, v in func_dict.items()]).center(29, '*')  # 功能菜单
    tips = ["{}、{}".format(k, v['title']) for k, v in func_dict.items()]

    while True:
        print("******************************")
        print("功能菜单:")
        for tip in tips:
            print(tip)
        print("******************************")
        choice = input("请输入序号(Q/q退出):")
        if choice.upper() == 'Q':
            break

        data_dict = func_dict.get(choice)  # {'title': "分页看新闻", 'func': page.execute}
        if not data_dict:
            print("序号不存在,请重新输入!")
            continue

        data_dict['func']()  # page.execute():调用功能的执行函数

6、app.py

"""
项目启动文件
"""
from src.handler import run

if __name__ == '__main__':
    run()
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值