这几天在家闲得无聊,意外的挖掘到了一个资源网站(你懂得),但是网速慢广告多下载不了种种原因让我突然萌生了爬虫的想法。
下面说说流程:
一、网站分析
首先进入网站,F12检查,本来以为这种低端网站很好爬取,是我太低估了web主。可以看到我刷新网页之后,出现了很多js文件,并且响应获取的代码与源代码不一样,这就不难猜到这个网站是动态加载页面。
目前我知道的动态网页爬取的方法只有这两种:1、从网页响应中找到JS脚本返回的JSON数据;2、使用Selenium对网页进行模拟访问。源代码问题好解决,重要的是我获取的源代码中有没有我需要的东西。我再一次进入网站进行F12检查源代码,点击左上角然后在页面点击一个视频获取一个元素的代码,结果里面没有嵌入的原视频链接(看来我真的是把别人想的太笨了)。
没办法只有进行抓包,去找js请求的接口。再一次F12打开网页调试工具,点击单独的一个视频进行播放,然后在Network中筛选一下,只看HXR响应(HXR全称是XMLHTTPRequest,HMLHTTP是AJAX网页开发技术的重要组成部分。除XML之外,XMLHTTP还能用于获取其它格式的数据,如JSON或者甚至纯文本。)。
然后我一项一项的去检查返回的响应信息,发现当我点击播放的时候有后缀为.m3u8的链接,随后就不断刷新.ts文件的链接。
本来以为这就是原视频的地址,我傻傻的直接从这个m3u8文件的headers中的URL直接进入网站看看,结果傻眼了,获取的是一串串.ts的文件名。
没办法只能百度君了。 科普了一下,也就说我们必须把ts文件都下载下来进行合并之后才能转成视频。
好了,视频原地址弄清楚了,现在我们开始从一个视频扩展到首页的整个页面的视频。再一次进行抓包分析,发现一个API中包含了首页的分类列表,然而里面并没有进入分类的URL地址,只有一个tagid值和图片的地址。
于是我又在主页点一个分类,再次进行抓包,发现了一个API中包含了一个分类的单页所有视频的信息,通过他们的headers中的URL对比发现,关于视频的前一部分都是https:xxxxxxx&c=video,然后m=categories,通过字面意思我们都可以知道是分类,而每个tagid值对应不同的分类。并且还发现每个URL中都追加了时间戳timestamp(这是web主为了确保请求不会在它第一次被发送后即缓存,看来还是有小心机啊)。当m=lists,则是每个分类下的视频列表,这里面我们就可以找到每个视频对应的ID了。
通过id我们可以获取到视频的详细信息,并且还有m3u8文件URL地址的后面一部分。
好了,网站我们解析清楚了,现在开始堆码了。
二、写代码
导入相关模块
import requests from datetime import datetime import re #import json import time import os #视频分类和视频列表URL的前一段 url = "http://xxxxxxx/api/" #m3u8文件和ts文件的URL前一段 m3u8_url ='https://xxxxxxxxxxxxx/videos/cherry-prod/2020/03/01/2dda82de-5b31-11ea-b5ae-1c1b0da2bc3f/hls/480/' #构造请求头信息 header = {"user-agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2"} #创建空列表存放视频信息 vediomassag='' #返回当前时间戳 TimeStamp = int(datetime.timestamp(datetime.now()))
2.定义函数,获取网站首页分类列表信息
#自定义函数获取分类 def get_vediocategory(url, TimeStamp): cgURL = url + "m=categories×tamp=" + str(TimeStamp) + '&' response = requests.get(cgURL, headers=header) category = response.text # strrr='"%s"'%category # return strrr return category
3.定义函数,通过上一个函数返回的分类信息,根据分类对应的id,输入id并传输到当前URL中以便获取分类下的视频列表信息
#获取分类后的视频列表 def get_vedioList(url, TimeStamp, tagID): listURL = url + "m=lists×tamp=" + str(TimeStamp) + '&' + "page=1&tag_id=" + str(tagID) + "&sort_type=&is_vip=0" response = requests.get(listURL, headers=header) vedioLists = response.text return vedioLists
4.在视频列表信息中获取视频对应的id,获取单个视频详细信息的URL
#获取单个视频的详细信息 def get_vediomassages(url, TimeStamp, vedioID): videoURL = url + "m=detail×tamp=" + str(TimeStamp) + '&' + "&id=" + str(vedioID) response = requests.get(videoURL, headers=header) vediomassag = response.text return vediomassag
5.在视频详细信息中找到m3u8文件的下载地址,并将文件保存到创建的文件中
#将下载的m3u8文件放进创建的ts列表文件中 def get_m3u8List(m3u8_url,vediomassag): lasturl = r'"m3u8_720_url":"(.*","download_url' last_url =re.findall(lasturl,vediomassag) lastURL=m3u8_url+str(last_url) response = requests.get(lastURL, headers=header) tsList = response.text cur_path='E:\\files' #在指定路径建立文件夹 try: if not os.path.isdir(cur_path): #确认文件夹是否存在 os.makedirs(cur_path) #不存在则新建 except: print("文件夹存在") filename=cur_path+'\\t2.txt' #在文件夹中存放txt文件 f = open(filename,'a', encoding="utf-8") f.write(tsList) f.close print('创建%s文件成功'%(filename)) return filename
6.将m3u8文件中的ts单个提取出来放进列表中。
# 提取ts列表文件的内容,逐个拼接ts的url,形成list def get_tsList(filename): ls = [] with open(filename, "r") as file: line = f.readlines() for line in lines: if line.endswith(".ts\n"): ls.append(line[:-1]) return ls
7.遍历列表获取单个ts地址,请求下载ts文件放进创建的文件夹中
# 批量下载ts文件 def DownloadTs(ls): length = len(ls) root='E:\\mp4' try: if not os.path.exists(root): os.mkdir(root) except: print("文件夹创建失败") try: for i in range(length): tsname = ls[i][:-3] ts_URL=url+ls[i] print(ts_URL) r = requests.get(ts_URL) with open(root, 'a') as f: f.write(r.content) f.close() print('\r' + tsname + " -->OK ({}/{}){:.2f}%".format(i, length, i * 100 / length), end='') print("下载完毕") except: print("下载失败")
代码整合
import requests from datetime import datetime import re #import json import time import os url = "http://xxxxxxxx/api/" m3u8_url ='https://xxxxxxxxxxxxxxx/videos/cherry-prod/2020/03/01/2dda82de-5b31-11ea-b5ae-1c1b0da2bc3f/hls/480/' header = {"user-agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2"} vediomassag='' TimeStamp = int(datetime.timestamp(datetime.now())) #自定义函数获取分类 def get_vediocategory(url, TimeStamp): cgURL = url + "m=categories×tamp=" + str(TimeStamp) + '&' response = requests.get(cgURL, headers=header) category = response.text # strrr='"%s"'%category # return strrr return category #获取分类后的视频列表 def get_vedioList(url, TimeStamp, tagID): listURL = url + "m=lists×tamp=" + str(TimeStamp) + '&' + "page=1&tag_id=" + str(tagID) + "&sort_type=&is_vip=0" response = requests.get(listURL, headers=header) vedioLists = response.text return vedioLists #获取单个视频的详细信息 def get_vediomassages(url, TimeStamp, vedioID): videoURL = url + "m=detail×tamp=" + str(TimeStamp) + '&' + "&id=" + str(vedioID) response = requests.get(videoURL, headers=header) vediomassag = response.text return vediomassag #将下载的m3u8文件放进创建的ts列表文件中 def get_m3u8List(m3u8_url,vediomassag): lasturl = r'"m3u8_720_url":"(.*","download_url' last_url =re.findall(lasturl,vediomassag) lastURL=m3u8_url+str(last_url) response = requests.get(lastURL, headers=header) tsList = response.text cur_path='E:\\files' #在指定路径建立文件夹 try: if not os.path.isdir(cur_path): #确认文件夹是否存在 os.makedirs(cur_path) #不存在则新建 except: print("文件夹存在") filename=cur_path+'\\t2.txt' #在文件夹中存放txt文件 f = open(filename,'a', encoding="utf-8") f.write(tsList) f.close print('创建%s文件成功'%(filename)) return filename # 提取ts列表文件的内容,逐个拼接ts的url,形成list def get_tsList(filename): ls = [] with open(filename, "r") as file: line = f.readlines() for line in lines: if line.endswith(".ts\n"): ls.append(line[:-1]) return ls # 批量下载ts文件 def DownloadTs(ls): length = len(ls) root='E:\\mp4' try: if not os.path.exists(root): os.mkdir(root) except: print("文件夹创建失败") try: for i in range(length): tsname = ls[i][:-3] ts_URL=url+ls[i] print(ts_URL) r = requests.get(ts_URL) with open(root, 'a') as f: f.write(r.content) f.close() print('\r' + tsname + " -->OK ({}/{}){:.2f}%".format(i, length, i * 100 / length), end='') print("下载完毕") except: print("下载失败") '''# 整合所有ts文件,保存为mp4格式(此处函数复制而来未做实验,本人直接在根目录 命令行输入copy/b*.ts 文件名.mp4,意思是将所有ts文件合并转换成自己命名的MP4格式 文件。) def MergeMp4(): print("开始合并") path = "E://mp4//" outdir = "output" os.chdir(root) if not os.path.exists(outdir): os.mkdir(outdir) os.system("copy /b *.ts new.mp4") os.system("move new.mp4 {}".format(outdir)) print("结束合并")''' if __name__ == '__main__': # 将获取的分类信息解码显示出来 # print(json.loads(get_vediocategory(url, TimeStamp))) print(get_vediocategory(url, TimeStamp)) tagID = input("请输入分类对应的id") print(get_vedioList(url, TimeStamp, tagID)) vedioID = input("请输入视频对应的id") get_vediomassages(url, TimeStamp, vedioID) get_m3u8List(m3u8_url,vediomassag) get_tsList(filename) DownloadTs(ls) # MergeMp4()
此时正在下载
三、问题:
首先对于这种网站采取的爬取方法有很多,而我的方法相对来说有点太低端了,并且我也 是第一次写博客,第一次写爬虫这类程序,在格式上命名上存在着很多问题,函数的用法不全面。并且在运行的时候效率低速度太慢。在获取分类列表和视频列表时,因为是JSON文件,需要转码,过程太多加上程序不够稳定我就注释掉了。还有就是对于这种动态网页了解不够,所以学爬虫的小伙伴一定要把网页的基础搞好。希望各位大佬多指正多批评,让我们这些小白一起努力学好Python。
注意:里面所有的链接我的给打码了,怕被和谐了哈哈
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新动态
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]