吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 3397|回复: 20
上一主题 下一主题
收起左侧

[Python 原创] 梨视频网站视频爬取-初探索

  [复制链接]
跳转到指定楼层
楼主
ymk2004 发表于 2023-10-17 19:33 回帖奖励
本帖最后由 ymk2004 于 2023-10-17 20:29 编辑

本人小白一枚,最近刚开始学习python爬虫相关的内容,于是稍微做了一个实例尝试下,做的很多地方都不好,还望大家多多包涵!!!

前言

最近学了一部分网络爬虫的基础知识,于是就拿梨视频网站上面的视频做了一次尝试,起初觉得有一点简单,但是真正到了请求下载视频链接时,又发现无法下载。于是对比了我第一次拿到的url跟真正的视频url比较,存在不同的地方,最后发现了梨视频官方对自己的视频进行了链接的伪造以防止爬取。
最终,感觉梨视频的爬取难度还是适中的,对我这样的新手在理解网络爬虫方面还是有很大帮助的。

python环境

Python版本-3.11.5
import requests  # 用于发送HTTP请求
from lxml import etree  # 用于解析HTML
import random  # 用于生成随机数
import os  # 用于文件操作
from multiprocessing.dummy import Pool  # 使用多线程池提高爬取效率

对相关页面的观察分析

首先,打开梨视频的官网链接:

梨视频官网-有故事的短视频-Pear Video

通过一些观察,我准备从视频量比较多的地方进行爬取,于是便找到了主页的 人物、万象 两个页面进行爬取。


-->人物页面所对应的URL地址:

人物热点短视频_-梨视频官网-Pear Video

-->万象页面所对应的URL地址:

万象热点资讯_万象热点新闻-梨视频官网-Pear Video


返老还童?重庆百岁老人白发变青丝,最爱《封神榜》_身体-梨视频官网-Pear Video为例

在人物界面,鼠标拖拽到一个图片上面,在浏览器左下角位置,我们可以看到其所对应URL链接,以返老还童?重庆百岁老人白发变青丝,最爱《封神榜》_身体-梨视频官网-Pear Video为例,我们可以看到例子中的1686640应该具有某种作用,这里猜测为视频所对应的一个ID。
返老还童?重庆百岁老人白发变青丝,最爱《封神榜》_身体-梨视频官网-Pear Video

inner_url 所对应的 Refererhost_url

随便点击一个视频页面进入,我们打开开发者工具,找到视频对应的URL,可以发现请求表头里面包括Referer:https://www.pearvideo.com/category_1

检查页面元素代码,找到 inner_video 所对应的 src 链接

通过开发者工具,查看网页代码,我们可以看到element中的视频部分标签:
src="https://video.pearvideo.com/mp4/adshort/20200717/cont-1686640-15272298_adpkg-ad_hd.mp4"
https://video.pearvideo.com/mp4/adshort/20200717/cont-1686640-15272298_adpkg-ad_hd.mp4


分析页面源代码,发现 inner_video 是动态加载出来的,开始分析 ajax 文件

通过分析,我们可以发现视频的inner_url详情页源代码中是不含有视频链接的,也就是说详情页中的视频是动态加载出来的,这时候就需要我们去分析ajax文件了。

找到Fetch/XHR中的网址请求

通过抓包工具,我们可以看到Fetch/XHR中存在这样一个请求:https://www.pearvideo.com/videoStatus.jsp?contId=1686640&mrd=0.17203231944534259

打开请求网址,发现问题,证明视频链接进行了伪装,即设置了反爬机制

但是打开这个链接,发现并不是我们想要的视频,而是这样的页面:

使用到的反爬机制--->防盗链(Referer
    其实这是网站使用的一种反爬机制,即——防盗链(`Referer`)。所以,我们所得到的这个https://www.pearvideo.com/videoStatus.jsp?contId=1686640&mrd=0.17203231944534259链接是一个伪装过的链接,不是真正的视频链接。

分析网址请求后的相应内容,对systemTimesrcUrl进行分析

紧接着,通过抓包工具,点击查看请求响应内容:

{
        "resultCode":"1",
        "resultMsg":"success", "reqId":"250bf9cf-31cc-492c-a71a-4f844e1b9acb",
        "systemTime": "1697377523473",
        "videoInfo":{
              "playSta":"1",
             "video_image":"https://image.pearvideo.com/cont/20200717/cont-1686640-12430737.png",
             "videos":
             {
                      "hdUrl":"",
                      "hdflvUrl":"",
                      "sdUrl":"",
                      "sdflvUrl":"",
                      "srcUrl":"https://video.pearvideo.com/mp4/adshort/20200717/1697377523473-15272298_adpkg-ad_hd.mp4"
             }
                     }
}

打开这个"srcUrl":"https://video.pearvideo.com/mp4/adshort/20200717/1697377523473-15272298_adpkg-ad_hd.mp4" 会发现报错,证明这个也不是真正的视频链接。


我们之前在检查网页的元素代码时找到了src="https://video.pearvideo.com/mp4/adshort/20200717/cont-1686640-15272298_adpkg-ad_hd.mp4"
我们在浏览器中打开这个视频链接,会发现这个链接可以正常打开,证明这个链接所对应的内容就是i我们的视频。

对比下我们目前拿到的两个URL,不难发现其中的参数存在差异性,这里的1697377523473其实就是我们在相应内容中所获得到的"systemTime": "1697377523473" ,而1686640就是视频所对应的contId

对比srcUrl 和video_url,分析差异性,分析参数的具体含义
"srcUrl":"https://video.pearvideo.com/mp4/adshort/20200717/1697377523473-15272298_adpkg-ad_hd.mp4"
"video_url":"https://video.pearvideo.com/mp4/adshort/20200717/cont-1686640-15272298_adpkg-ad_hd.mp4"

那么我们要拿到真正的视频链接video_url,只需要提取出相应内容json文件里的srcUrl,然后通过字符串的替换操作,将systemTime替换成cont-contId即可拿到真正的视频链接。


分析请求头中的防盗链Referer,同时分析请求参数中 mrd 的具体含义

通过抓包工具,我们可以看到该请求的Referer是:https://www.pearvideo.com/video_1686640,不难看出这个Referer地址就是我们的网页详情页面的URL


Fetch/XHR中存在这样一个请求:https://www.pearvideo.com/videoStatus.jsp?contId=1686640&mrd=0.17203231944534259,我们不难猜测出视频链接前面的https://www.pearvideo.com/videoStatus.jsp?应该是一致的,而链接后面所对应的是相关的参数(contId和mrd)。参数contId就是视频独有的ID,而参数mrd 是一个随机的浮点数,这个浮点数范围是0-1之间。

导入相应的模块

import requests  # 用于发送HTTP请求
from lxml import etree  # 用于解析HTML
import random  # 用于生成随机数
import os  # 用于文件操作
from multiprocessing.dummy import Pool  # 使用多线程池提高爬取效率
    为了提高视频爬取的效率,我采用了多线程的方法来下载视频。

创建视频的存储路径

# 检查视频存储目录是否存在,如果不存在则创建
if not os.path.exists('./梨视频'):
    os.mkdir('./梨视频')
save_path = './梨视频/'

检查当前工作目录下是否存在名为"梨视频"的目录,如果不存在则创建它,然后将目录路径存储在save_path变量中,以便后续操作可以使用这个路径。

实例--->主要操作

在页面的详情页面代码中进行下列操作:

1.构建用户可以选择某视频进行下载的页面:

# URL列表
host_url_list = ['https://www.pearvideo.com/category_1', 'https://www.pearvideo.com/panorama']
# 设置host_headers请求头
host_headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.63"
}
# 获取网站标题信息
site_titles = []
for host_url in host_url_list:
    page_text = requests.get(host_url, headers=host_headers).text
    tree = etree.HTML(page_text)
    site_title = tree.xpath('//title/text()')[0]
    site_titles.append(site_title)

# 用户选择URL
print("欢迎使用梨视频下载工具")
print("请选择要爬取的网站:")

for i, (url, title) in enumerate(zip(host_url_list, site_titles), 1):
    print(f"{i}. {title}")

while True:
    try:
        choice = int(input("请输入数字 1 或 2 来选择: "))
        if 1 <= choice <= 2:
            break
        else:
            print("请输入有效的选择 (1 或 2) ")
    except ValueError:
        print("请输入有效的选择 (1 或 2)")

selected_url = host_url_list[choice - 1]
# 获取用户选择的URL
host_url = selected_url

# 发送GET请求获取主页host_url的HTML内容
page_text = requests.get(url=host_url, headers=host_headers).text
tree = etree.HTML(page_text)
# 提取host主页中的inner视频链接
inner_href_list = tree.xpath('//div[@class="vervideo-bd"]/a/@href')
# 输出inner_href链接对应的标题
print("\n以下是可供下载的视频标题:")
for i, inner_href in enumerate(inner_href_list, 1):
    inner_url = 'https://www.pearvideo.com/' + inner_href
    inner_text = requests.get(url=inner_url, headers=host_headers).text
    title = etree.HTML(inner_text).xpath('//h1[@class="video-tt"]/text()')[0]
    print(f"{i}. {title}")

# 用户选择要下载的inner_href视频
selected_indices = input("输入要下载的视频序号(用逗号分隔,如1,3,5),或者直接按回车下载所有视频:")
if selected_indices:
    selected_indices = [int(i) - 1 for i in selected_indices.split(",")]
else:
    selected_indices = range(len(inner_href_list))

2.提取出inner_href视频对应的标题title---->xpath路径如下:

//h1[@class="video-tt"]/text()

3.提取inner_href视频所对应的contId---->xpath路径如下:

//div[@id="poster"]/@data-cid

4.通过python代码生成一个mrd随机浮点数

# 生成一个随机的mrd参数
mrd = random.random()

通过上面的操作,我们便可以得到视频所对应的两个参数contIdmrd
构造出用于获取视频真实链接的ajax请求url

# 构造用于获取视频真实链接的ajax请求url
ajax_url = 'https://www.pearvideo.com/videoStatus.jsp?'
params = {
    "contId": contId,
    "mrd": mrd
}
# 设置ajax请求的头部,包括Referer
ajax_headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.63",
    "Referer": inner_url
}

5.发送ajax请求,获取视频信息的JSON数据,提取JSON中的systemTimesrcUrl

# 发送ajax请求,获取视频信息的JSON数据
response = requests.get(url=ajax_url, headers=ajax_headers, params=params)

# 提取JSON中的systemTime和srcUrl
systemTime = response.json()['systemTime']
srcUrl = response.json()['videoInfo']['videos']['srcUrl']

6.替换伪装的视频链接中的systemTime参数,获取真正的视频链接

srcUrl = str(srcUrl).replace(str(systemTime), f'cont-{contId}')

7.将视频内容保存到指定目录下,以视频标题命名

# 发送请求获取视频内容
content = requests.get(url=srcUrl, headers=ajax_headers).content

# 将视频内容保存到指定目录下,以视频标题命名
with open(save_path + title, mode='wb') as fp:
    fp.write(content)
    fp.close()

# 打印提示信息
print(f'{title} 下载完毕!!!')

8.遍历用户选择的视频链接,将每个链接加入到并行下载任务

# 遍历用户选择的视频链接,将每个链接加入到并行下载任务
pool.map(download_video, selected_indices)

# 等待所有任务完成
pool.close()
pool.join()

程序完整的代码

# 1.导包 和 设置视频存储路径
import requests  # 用于发送HTTP请求
from lxml import etree  # 用于解析HTML
import random  # 用于生成随机数
import os  # 用于文件操作
from multiprocessing.dummy import Pool  # 使用多线程池提高爬取效率

# 检查视频存储目录是否存在,如果不存在则创建
if not os.path.exists('./梨视频'):
    os.mkdir('./梨视频')
save_path = './梨视频/'

# 2.指定主页url,设置请求头信息
# URL列表
host_url_list = ['https://www.pearvideo.com/category_1', 'https://www.pearvideo.com/panorama']
# 设置host_headers请求头
host_headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.63"
}
# 获取host网站标题信息
host_site_titles = []
for host_url in host_url_list:
    page_text = requests.get(host_url, headers=host_headers).text
    tree = etree.HTML(page_text)
    host_site_title = tree.xpath('//title/text()')[0]
    host_site_titles.append(host_site_title)

# 用户选择URL
print("欢迎使用梨视频下载工具")
print("请选择要爬取的网站:")

for i, (url, title) in enumerate(zip(host_url_list, host_site_titles), 1):
    print(f"{i}. {title}")

while True:
    try:
        choice = int(input("请输入数字 1 或 2 来选择: "))
        if 1 <= choice <= 2:
            break
        else:
            print("请输入有效的选择 (1 或 2) ")
    except ValueError:
        print("请输入有效的选择 (1 或 2)")

selected_url = host_url_list[choice - 1]
# 获取用户选择的URL
host_url = selected_url

# 发送GET请求获取主页的HTML内容
page_text = requests.get(url=host_url, headers=host_headers).text
tree = etree.HTML(page_text)
# 提取主页中的视频链接
inner_href_list = tree.xpath('//div[@class="vervideo-bd"]/a/@href')
# 输出链接对应的标题
print("\n以下是可供下载的视频标题:")
inner_url_list = []
for i, inner_href in enumerate(inner_href_list, 1):
    inner_url = 'https://www.pearvideo.com/' + inner_href
    inner_url_list.append(inner_url)
    inner_text = requests.get(url=inner_url, headers=host_headers).text
    title = etree.HTML(inner_text).xpath('//h1[@class="video-tt"]/text()')[0]
    print(f"{i}. {title}")

# 用户选择要下载的视频
selected_indices = input("输入要下载的视频序号(用逗号分隔,如1,3,5),或者直接按回车下载所有视频:")
if selected_indices:
    selected_indices = [int(i) - 1 for i in selected_indices.split(",")]
else:
    selected_indices = range(len(inner_href_list))

# 使用多线程池提高爬取效率
pool = Pool(6)

# 定义一个下载视频的函数
def download_video(index):
    inner_url = inner_url_list[index]
    # 4.对详情页源代码进行分析,找出视频链接。
    #   但是通过分析,我们可以发现视频的详情页源代码中是不含有视频链接的,也就是说详情页中的视频 是动态加载出来的,这时候就需要我们去分析ajax文件了。
    #   通过抓包工具,我们可以看到Fetch/XHD中存在这样一个请求:https://www.pearvideo.com/videoStatus.jsp?contId=1156899&mrd=0.13727699405356097。但是打开这个链接,发现并不是我们想要的视频,而是这样的:
    # {
    # "resultCode":"5",
    # "resultMsg":"该文章已经下线!",
    # "systemTime": "1676187693726"
    # }
    #   其实这是网站使用的一种反爬机制,即——防盗链(Referer)
    #   通过抓包工具,我们可以看到该请求的Referer是:https://www.pearvideo.com/video_1156899 这个链接就是我们的inner_url

    # 5.找出ajax文件发出请求url,并找到参数 contId 和 mrd
    #   经常分析,我们可以看出参数 mrd 是一个随机的浮点数,这个浮点数范围是0-1之间

    # 获取详情页的HTML内容
    inner_text = requests.get(url=inner_url, headers=host_headers).text
    # 提取视频标题和contId
    title = etree.HTML(inner_text).xpath('//h1[@class="video-tt"]/text()')[0] + '.mp4'
    contId = etree.HTML(inner_text).xpath('//div[@id="poster"]/@data-cid')[0]

    # 生成一个随机的mrd参数
    mrd = random.random()

    # 构造用于获取视频真实链接的ajax请求url
    ajax_url = 'https://www.pearvideo.com/videoStatus.jsp?'
    params = {
        "contId": contId,
        "mrd": mrd
    }

    # 6.设置ajax请求的头部,包括Referer
    ajax_headers = {
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.63",
        "Referer": inner_url
    }

    # 发送ajax请求,获取视频信息的JSON数据
    response = requests.get(url=ajax_url, headers=ajax_headers, params=params)

    # 提取JSON中的systemTime和srcUrl
    systemTime = response.json()['systemTime']
    srcUrl = response.json()['videoInfo']['videos']['srcUrl']

    # print(srcUrl)

    # 7.此时我们找到了json文件中包含的视频url,但是我们打开发现网页404报错,这就意味着这个链接其实并不是真正的视频链接;那么,我们开始对视频进行分析,
    # 发现视频的真正链接是:https://video.pearvideo.com/mp4/short/20170915/cont-1156899-10890623-hd.mp4
    # 通过对比分析,可以发现这两个链接只有一处不同的地方(systemTime),那么接下来我们就要把伪装的链接通过字符串替换,拿到真正的视频链接

    # 8.替换伪装的视频链接中的systemTime参数,获取真正的视频链接
    srcUrl = str(srcUrl).replace(str(systemTime), f'cont-{contId}')

    # 发送请求获取视频内容
    content = requests.get(url=srcUrl, headers=ajax_headers).content

    # 9.将视频内容保存到指定目录下,以视频标题命名
    with open(save_path + title, mode='wb') as fp:
        fp.write(content)
        fp.close()

    # 打印提示信息
    print(f'{title} 下载完毕!!!')

# 遍历用户选择的视频链接,将每个链接加入到并行下载任务
pool.map(download_video, selected_indices)

# 等待所有任务完成
pool.close()
pool.join()

image.png (194.56 KB, 下载次数: 1)

image.png

免费评分

参与人数 10吾爱币 +16 热心值 +9 收起 理由
wizarrr + 1 + 1 谢谢@Thanks!
SVIP9大会员 + 1 思路真清晰啊
Bob5230 + 1 + 1 热心回复!
陪初雪去看雪 + 1 用心讨论,共获提升!
canty胖胖 + 1 + 1 用心讨论,共获提升!
jason76wong + 1 + 1 我很赞同!
yjn866y + 1 + 1 谢谢@Thanks!
潇洒超人 + 2 + 1 我很赞同!
ttyylfd + 1 + 1 用心讨论,共获提升!
侃遍天下无二人 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
马到功成 发表于 2023-10-18 09:30
俺也想学如何分析提取 下载网页视频,但不知道这方面的知识是从何开始学,需要学哪些方面的类容。求大佬指点下门路
沙发
逐雅斋 发表于 2023-10-18 07:25
3#
yjn866y 发表于 2023-10-18 08:23
4#
baliao 发表于 2023-10-18 08:25
感谢楼主分享,学习了!
5#
lianliangfo 发表于 2023-10-18 08:37
感谢分享,学习了!
7#
lgblgc 发表于 2023-10-18 09:37
感谢楼主分享!!
8#
ddvvc 发表于 2023-10-18 09:44
感谢楼主干货分享
9#
少年郎向前望 发表于 2023-10-18 10:08
感谢楼主分享 多谢了
10#
yaphoo 发表于 2023-10-18 11:25
谢谢分享!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-22 02:30

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表