• Python爬虫实战第三例【三】(下)


    零.前情提要:

    没有看上一章的小伙伴,建议先去看上一章,避免有些知识点不连贯

    地址:Python爬虫实战第三例【三】【上】-CSDN博客

    在上一章,我们经过分析.m3u8文件和.ts文件后,成功爬取到了所有.ts文件的文件名,并且成功下载了.ts文件,但是在上一节中我们只是下载了一个.ts文件,并没有实现批次的.ts文件下载。

    接下来,我们就要进行批次爬取.ts文件,并且将它们组合在一起!

    准备好了吗?跟随作者一起,走进爬虫的海洋吧!

    一.批次爬取.ts文件

    由于我们现在爬取.ts文件的函数,一次只能爬去一个.ts文件,那我们是不是可以在函数外面放一个for循环来实现批次爬取.ts文件呢?当然可以了!!

    代码如下:

    1. #将ts_list转换为带有序号的列表,方便.ts文件的重命名,用来保持顺序一致!
    2. ts_list = list(enumerate(ts_list))
    3. for ts in ts_list:
    4. down_video(ts)

    效果图:

    但是这样是有一个问题的,那就是爬取完第一个.ts文件后,程序重新构造一大串.get请求并发送,这中间消耗了大量资源,并且可以发现效率很慢!!!如果共有1000个.ts文件,我们需要爬取三十分钟!!这显然不是我们想要看到的!!

    学过线程的小伙伴可能想到了,这不是单线程造成的吗?对的,所以改进的话我们只需要改成多线程就可以啦!!

    为此,我们先要导入线程池

    from multiprocessing.pool import ThreadPool

    代码如下:

    1. #创建线程池
    2. pool = ThreadPool(100)
    3. #利用map函数给线程分配工作
    4. pool.map(down_video,enumerate(ts_list))

    效果图:

     可以看到效率飞起!!效率大概提升了1000%!!!

    (与个人CPU有关,CPU线程数越多效率越高)

    二.重新爬取失败的文件

    不过在爬取过程中,难免会有一些.ts文件因为网络波动的问题,导致超时,从而报错,这显然不是我们想看到的,为此我们该怎么办呢?

    作者的想法是,创建一个检查函数,在执行完爬取.ts文件后,检查是否有文件没有被爬取!

    代码如下:

    1. #漏下的.ts文件列表
    2. fil_list = []
    3. #检查标志
    4. file_flag = False
    5. def down_video(item):
    6. #全局变量标志,用来表示是第一次爬取.ts文件,还是爬取漏下的.ts文件!
    7. global file_flag
    8. #对item进行解包,提取出ts文件和ts文件索引
    9. index,ts = item[0],item[1]
    10. #拼接文件序号
    11. if 0 <= index <=9:
    12. index = "000" + str(index)
    13. elif 10 <= index <= 99:
    14. index = "00" + str(index)
    15. elif 100 <= index <= 999:
    16. index = "0" + str(index)
    17. else:
    18. index = str(index)
    19. #爬取视频URL
    20. URL = "https://s8.fsvod1.com/20230703/J6BHjLy3/1500kb/hls/"
    21. #请求头
    22. headers = {
    23. "authority":"s8.fsvod1.com",
    24. "method":"GET",
    25. "path":f"/20221207/10692_4308abda/2000k/hls/{ts}",
    26. "scheme":"https",
    27. "Accept":r"*/*",
    28. "Accept-Encoding":"gzip,deflate,br,zstd",
    29. "Accept-Language":"zh-CN,zh;q=0.9",
    30. "Origin":"https://test3.gqyy8.com:4438",
    31. "Sec-Ch-Ua":'"Chromium";v="122","Not(A:Brand";v="24","Google Chrome";v="122"',
    32. "Sec-Ch-Ua-Mobile":"?0",
    33. "Sec-Ch-Ua-Platform":"Windows",
    34. "Sec-Fetch-Dest":"empty",
    35. "Sec-Fetch-Mode":"cors",
    36. "Sec-Fetch-Site":"cross-site",
    37. "User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/122.0.0.0Safari/537.36"
    38. }
    39. #拼接视频url
    40. URL = URL + "/" + ts
    41. try:
    42. r = requests.get(url=URL,headers=headers,timeout=10)
    43. with open(f"{os.getcwd()}/爬取数据/" + index + ".ts", "wb") as file:
    44. file.write(r.content)
    45. except Exception as e:
    46. if not file_flag:
    47. fil_list.append([int(index),ts])
    48. print(index,"写入失败,原因",e,sep="->")
    49. return
    50. if file_flag:
    51. fil_list.remove(item)
    52. print(index,"写入成功.",sep="->")
    53. def check():
    54. print("开始检查")
    55. global file_flag
    56. file_flag = True
    57. while fil_list:
    58. pool = ThreadPool(100)
    59. results = pool.map(down_video, fil_list)
    60. pool.close()
    61. pool.join()
    62. print("检查完毕")
    63. if __name__ == "__main__":
    64. ts_list = get_ts_txt()
    65. create_filedir()
    66. #创建线程池
    67. pool = ThreadPool(100)
    68. #利用map函数给线程分配工作
    69. pool.map(down_video,enumerate(ts_list))
    70. #检查函数
    71. check()

     效果图:

    也是成功全部爬取啦!!

    我累个逗啊!居然有2426.ts文件!!

    三.合成.ts文件

    其实将所有.ts文件拼凑在一起,有很多方法,在这里作者给出一种相对简单的方法

    1.首先进入cmd切换到我们的“爬取数据”路径下,如下图所示:

     2.接下来输入指令:

    copy /b *.ts my_video.ts

    结果如下图所示:

    最后,去我们的文件夹里面找“my_video.ts”即可播放啦!!

     

    芜湖,可以看玲芽啦~~ 

    四.全部代码

    1. import requests
    2. import os
    3. import re
    4. from multiprocessing.pool import ThreadPool
    5. #漏下的.ts文件列表
    6. fil_list = []
    7. #检查标志
    8. file_flag = False
    9. def get_ts_txt():
    10. #4请求URL
    11. url = "https://s8.fsvod1.com/20230703/J6BHjLy3/1500kb/hls/index.m3u8"
    12. #请求头
    13. headers = {
    14. "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
    15. }
    16. reponse = requests.get(url=url,headers=headers)
    17. get_txt = reponse.text
    18. #正则匹配出.ts后缀数据
    19. ts_files = re.findall(r"\b\w+\.ts\b",get_txt)
    20. #将.ts数据写入到文件中中
    21. with open("get_ts.txt","w") as file:
    22. for i in ts_files:
    23. i = i + "\n"
    24. file.write(i)
    25. print("获取ts文件成功.")
    26. return ts_files
    27. def create_filedir():
    28. path = os.getcwd() + "/爬取数据"
    29. if os.path.exists(path):
    30. print("\\爬取视频文件夹已存在,本次不创建.")
    31. else:
    32. os.mkdir(path)
    33. print("创建\\爬取文件夹成功.")
    34. def down_video(item):
    35. #全局变量标志,用来表示是第一次爬取.ts文件,还是爬取漏下的.ts文件!
    36. global file_flag
    37. #对item进行解包,提取出ts文件和ts文件索引
    38. index,ts = item[0],item[1]
    39. #拼接文件序号
    40. if 0 <= index <=9:
    41. index = "000" + str(index)
    42. elif 10 <= index <= 99:
    43. index = "00" + str(index)
    44. elif 100 <= index <= 999:
    45. index = "0" + str(index)
    46. else:
    47. index = str(index)
    48. #爬取视频URL
    49. URL = "https://s8.fsvod1.com/20230703/J6BHjLy3/1500kb/hls/"
    50. #请求头
    51. headers = {
    52. "authority":"s8.fsvod1.com",
    53. "method":"GET",
    54. "path":f"/20221207/10692_4308abda/2000k/hls/{ts}",
    55. "scheme":"https",
    56. "Accept":r"*/*",
    57. "Accept-Encoding":"gzip,deflate,br,zstd",
    58. "Accept-Language":"zh-CN,zh;q=0.9",
    59. "Origin":"https://test3.gqyy8.com:4438",
    60. "Sec-Ch-Ua":'"Chromium";v="122","Not(A:Brand";v="24","Google Chrome";v="122"',
    61. "Sec-Ch-Ua-Mobile":"?0",
    62. "Sec-Ch-Ua-Platform":"Windows",
    63. "Sec-Fetch-Dest":"empty",
    64. "Sec-Fetch-Mode":"cors",
    65. "Sec-Fetch-Site":"cross-site",
    66. "User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/122.0.0.0Safari/537.36"
    67. }
    68. #拼接视频url
    69. URL = URL + "/" + ts
    70. try:
    71. r = requests.get(url=URL,headers=headers,timeout=10)
    72. with open(f"{os.getcwd()}/爬取数据/" + index + ".ts", "wb") as file:
    73. file.write(r.content)
    74. except Exception as e:
    75. if not file_flag:
    76. fil_list.append([int(index),ts])
    77. print(index,"写入失败,原因",e,sep="->")
    78. return
    79. if file_flag:
    80. fil_list.remove(item)
    81. print(index,"写入成功.",sep="->")
    82. def check():
    83. print("开始检查")
    84. global file_flag
    85. file_flag = True
    86. while fil_list:
    87. pool = ThreadPool(100)
    88. results = pool.map(down_video, fil_list)
    89. pool.close()
    90. pool.join()
    91. print("检查完毕")
    92. if __name__ == "__main__":
    93. ts_list = get_ts_txt()
    94. create_filedir()
    95. #创建线程池
    96. pool = ThreadPool(100)
    97. #利用map函数给线程分配工作
    98. pool.map(down_video,enumerate(ts_list))
    99. #检查函数
    100. check()

    ps:复制上直接就可以爬取哦~

  • 相关阅读:
    LibOpenCM3(一) Linux下命令行开发环境配置
    《深入浅出Spring》SpringAOP 详解 ProxyFactoryBean
    Pytorch中的torch.index_select对应MindSpore哪个方法
    新品发布 | Cloudpods 3.9.1 版本上线
    MYSQL SEQUENCE方案
    进程环境~
    关于网络协议的若干问题(五)
    应用程序意外变成另外一个应用程序的图标,打开就是另外一个程序!Synaptics.exe到底是什么?
    六款 Linux 常用远程连接工具介绍
    Deno 命令行界面
  • 原文地址:https://blog.csdn.net/zheshiyangyang/article/details/136490042