最近在学习python的爬虫,正好有一个需求,要下载一部电影,所以就打算用python爬虫来实现。
本来想起来挺简单的,但是做起来真的挺难的。主要是在西瓜视频代码里找到视频的链接,大概花了半天的时间才慢慢找到方法。
西瓜视频的网页是动态加载的,我们直接使用request请求是没有返回任何有用的信息,所以我们需要使用其他方法。
这里我使用的是pyppeteer这个库,可以模仿浏览器的访问,等待指定资源标签加载完成后,就可以看到我们想要的内容了。
这里我们在西瓜视频随便找一个视频,然后打开Chrome的开发者模式,寻找视频链接。
红框部分就包含我们需要的视频链接,我们把这段代码复制到文本编辑器,查看可以看到有一个
main_url标签,后边是一连串的字符串,是base64加密的,这个就是我们需要获取的,然后在解码就可以看到视频链接了,有了链接就可以下载了。
完整代码如下:
import asyncio
import logging
import sys
import requests
from base64 import b64decode
from pyppeteer import launch
from pyquery import PyQuery as pq
url_list = []
logging.basicConfig(level=logging.INFO)
async def main():
# 启动浏览器
browser = await launch()
# 开启一个新的标签页
page = await browser.newPage()
# 访问url地址
await page.goto("https://www.ixigua.com/7194376404279624203?logTag=894da6bbbe2fd383bdeb")
# 等待指定节点加载完成
await page.waitForSelector('#SSR_HYDRATED_DATA')
# 初始化pyquery
doc = pq(await page.content())
scripts_data = doc('[id*=SSR_HYDRATED_DATA]').text()
# 获取视频title,作为保存文件名
title = doc('title').text()
# 格式化字符串
str = scripts_data.split("=", 1)[1]
str = str.replace("null", "\"null\"").replace("false", "\'false\'"). \
replace("true", "\'true\'").replace("undefined", "\'undefined\'")
# 字符串转换为字典
b = eval(str)
# 迭代获取字典的key,返回一个value的列表
main_urls = get_item(b, "main_url")
# 初始化列表,存储解码后的main_url数据
video_url = ""
for main_url in main_urls:
url = base64_code(main_url)
# 判断url可用性,如果可用则加入列表
if check_url(url):
video_url = url
filename = title + ".mp4"
save_data(filename, video_url)
await browser.close()
# 获取字典内指定key的值
def get_item(it, k):
# 判断对象是否为字典
if isinstance(it, dict):
for d in it:
if isinstance(it[d], (dict, list)):
get_item(it[d], k)
else:
if d == k:
# print(it[d])
url_list.append(it[d])
# 判断对象如果是list
elif isinstance(it, list):
for l in it:
if isinstance(l, (dict, list)):
get_item(l, k)
# 列表去重并返回
urls = list(set(url_list))
return urls
# 保存视频
def save_data(filename, url):
logging.info("正在保存数据...")
data = requests.get(url).content
with open(filename, "wb") as f:
f.write(data)
logging.info("保存完成")
# bs64编码
def base64_code(str):
logging.info("正在进行解码。。。")
str = b64decode(str).decode("utf8")
return str
# 检查url可用性
def check_url(url):
logging.info("正在检查%s的可用性" % url)
response = requests.get(url, timeout=20)
if response.status_code == 200:
return True
else:
return False
asyncio.get_event_loop().run_until_complete(main())