P站 视频下载 JS加密URL 【JS逆向】

P站,你懂的网站,黄黑风格的。
它的真实下载地址是隐藏在JS加密当中的。
 
接下来我们看看如何找到它的真实地址。
 
首先随便打开一个视频:
我就找一个python学习的视频(什么鬼,上面还有python学习? 是的有的,还有很多数学题目在上面讲解的呢)

chrome_cID7nwLJtU.png

 
然后按F12
找到一个疑似的下载地址

chrome_d6YqqHw23u.png


试下拷贝直接去打开,发现无法打开,显示403 fobiden。
但是看url,应该就是最终的下载url的格式,通过最后的随机数控制播放权限。
 
然后打开页面的源码
 
chrome_TkTA0Gu2mZ.png



chrome_xQ9PuglQfb.png



 
在里面找下有没有一些mp4等的字符, 然后发现有个720p,1080p不同分辨率格式的字段,我们把这个JavaScript的代码扣下来,然后保存为p_hub.js
 
用vs code 或者其他编辑器打开

sublime_text_fYK2l4s4NA.png

看到了他们生成过程了吗? 
 
然后尝试用nodejs运行一下。
什么都没有输出。
 
因为上面代码并没有任何输出语句,我们在最后加一个 console.log(quality_720p); 就会有输出的了。

cmd_HJhTndtvh8.png

看到了吗?
然后拿这个地址去试试,看能否播放和下载。
果然,浏览器里面出现了一个, 额, python学习的页面,一个单独的视频页面,所以可以直接右键,弹出一个保存视频的菜单,然后可以直接下载了。
 
用代码requesets.get(url) 保存text.content 写入文件,就可以把视频保存到本地了。
 
源码:
 
#!/usr/bin/env python
# http://30daydo.com
import os
import re
import js2py
import requests
from lxml import etree
from clint.textui import progress
import fire
from loguru import logger

file='crawler'
logger.add(
"logs/%s.log" % file,
format="{time:MM-DD HH:mm:ss} {level} {message}",
)

headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36",
}
proxies = {}

# 如果代理不稳定,不推荐使用
# local proxy service
# proxies example:
# proxies = {
# "http": "socks5://127.0.0.1:1080",
# "https": "socks5://127.0.0.1:1080",
# }

def list_page(url):
logger.info("crawling : %s" % url)
resp = requests.get(url, headers=headers, proxies=proxies, verify=False)
html = etree.HTML(resp.text)

buff = '//*[@class="phimage"]/a/'
names = html.xpath(f"{buff}@href")
urls = html.xpath(f"{buff}img/@data-mediabook")
for i in range(len(urls)):
try:
url = urls[i]
name = re.findall("=ph(\w+)", names[i])[-1]
logger.info(f"{url} {name}")
download(url, name, "webm")
except Exception as err:
logger.error(err)


def detail_page(url):
s = requests.Session()
resp = s.get(url, headers=headers, proxies=proxies, verify=False)
html = etree.HTML(resp.content)

title = "".join(html.xpath("//h1//text()")).strip()
logger.info(title)

js_temp = html.xpath("//script/text()")
for j in js_temp:
if "flashvars" in j:
videoUrl = exeJs(j)

download(videoUrl, title, "mp4")
continue


def exeJs(js):
flashvars = re.findall("flashvars_\d+", js)[0]
js = "\n\t".join(js.split("\n\t")[:-5]).strip()

js = js.replace("// var nextVideoObject = flashvars_['nextVideo'];",'')
js+=flashvars
res = js2py.eval_js(js)

if res.quality_720p:
return res.quality_720p
elif res.quality_480p:
return res.quality_480p
elif res.quality_240p:
return res.quality_240p
else:
logger.error("parse url error")


def download(url, name, filetype):
logger.info(f"{url} {name} {filetype}")
filepath = "%s/%s.%s" % (filetype, name, filetype)
if os.path.exists(filepath):
logger.info("this file had been downloaded :: %s" % filepath)
return
else:
response = requests.get(url, headers=headers, proxies=proxies, stream=True)
with open(filepath, "wb") as file:
total_length = int(response.headers.get("content-length"))
for ch in progress.bar(
response.iter_content(chunk_size=2391975),
expected_size=(total_length / 1024) + 1,
):
if ch:
file.write(ch)

logger.info("download success :: %s" % filepath)


def run(_arg=None):
paths = ["webm", "mp4"]
for path in paths:
if not os.path.exists(path):
os.mkdir(path)
if _arg == "webm":
# https://www.pornhub.com/categories
urls = [
# "https://www.pornhub.com/video?o=tr",
# "https://www.pornhub.com/video?o=ht",
# "https://www.pornhub.com/video?o=mv",
"https://www.pornhub.com/video",
]
for url in urls:
list_page(url)
elif _arg == "mp4":
with open("download.txt", "r") as file:
keys = list(set(file.readlines()))
logger.info(keys)
keys += [d.strip(".webm") for d in os.listdir("webm/")]
for key in keys:
if not key.strip():
continue
url = "https://www.pornhub.com/view_v ... ot%3B % key.strip()
logger.info("url: {}", url)
detail_page(url)
else:
_str = """
tips:
python crawler.py webm
- 下载热门页面的缩略图,路径为webm文件夹下

python crawler.py mp4
- 该命令会下载webm文件下对应的mp4文件
- 也可以将目标地址写入download.txt中
"""
logger.info(_str)
return
logger.info("finish !")


if __name__ == "__main__":
fire.Fire(run)


原创文章,
转载请注明出处:
http://30daydo.com/article/44115 

 

0 个评论

要回复文章请先登录注册