Python君,快给朕来一部电影~


目 标

今天的目标很简单,就是想下载一些「微电影」回家过年。
正则表达式

以国内微电影活跃度最高的社区,「新片场」为例,爬取站内全部的高清电影信息保存到 MongoDB 数据库,并使用异步函数下载到本地。
数据库


准 备 工 做

首先,须要下载并配置好 MongoDB 数据库,并安装「mongoengine」库。
api

因为下载文件是一个 IO 密集型操做,这里用到了协程搭配异部请求,须要安装「aiohttp」 库。bash


# 更方便管理 Monogodb
pip3 install mongoengine

# 异步http
pip3 install aiohttp复制代码


分 析 思 路

首先咱们打开新片场的影视做品首页,发现默认是按热门度排序的。
session


「http://www.xinpianchang.com/channel/index/sort-like?from=tabArticle」app



因为页面元素比较简单,使用「xpath」能够很快的定位到每一条影片的基本数据,包含「影片名称、类型、播放量、点赞量、封面图」等。异步


# 电影标题
title = film_element.xpath('.//div[@class="video-con-top"]/a/p/text()')[0]

# 电影类型
type = remove_space('/'.join(
                film_element.xpath('.//div[@class="new-cate"]/span[@class="fs_12 fw_300 c_b_9"]/text()')))

# 播放量和点赞数
play_num = film_element.xpath('.//span[@class="fw_300 icon-play-volume"]/text()')[0]

like_num = film_element.xpath('.//span[@class="fw_300 c_b_9 icon-like"]/text()')[0]

# 封面图片
img_cover = film_element.xpath('.//a[@class="video-cover"]/img/@_src')[0]
复制代码


经过分析,能够发现影片的播放地址中的变量就是影片的 id,被放置在 li 标签的「data-articleid」属性下。async


最后就是要获取到影片的下载地址。ide

当咱们使用 Chrome 插件「Toggle JavaScript」禁用 JS 后,发现影片无法正常播放,说明影片播放页面关键数据是动态加载的。函数

打开 Network Tab,刷新当前页面。


经过观察,发现页面的部分关键数据是经过下面的一个地址发送的 GET 请求。


「https://openapi-vtom.vmovier.com/v3/video/5C4A8377173CE?expand=resource,resource_origin?」


另外,请求地址中包含的一个动态字符串「5C4A8377173CE」,隐藏于源码中的JS 模块中。



这里能够经过正则表达式匹配到「vid」后面的字符串,就能够组装成咱们须要的地址,经过这个地址就能够获取影片的下载地址。


# 请求地址
download_url_pre = 'https://openapi-vtom.vmovier.com/v3/video/{}?expand=resource,resource_origin?'

req = requests.get(play_address, headers=self.headers)

# 获取vid
vid_pre = re.findall(r'vid: "(.*)",', req.text)

# 获取到真实的请求地址
download_url_pre = "" if len(vid_pre) == 0 else self.download_url_pre.format(vid_pre[0])
复制代码


获取到数据以后,定义好一个 Model,而后就能够插入到数据库中了。


film_data = {
    'title': title,
    'type': type,
    'play_num': play_num,
    'like_num': like_num,
    'img_cover': img_cover,
    'play_address': play_address,
    'download_address': download_address
}

model = FilmModel(**film_data)
try:
     model.save()
     print('插入一条电影数据成功')
     self.films.append(film_data)
except Exception as e:
     print('插入数据异常')
     print(e)
复制代码



待爬取到的影片数据以后,就能够使用「asyncio + aiohttp」异步函数下载影片数据到本地。


async def download_a_film(title, download_address):
    """ 下载一部电影 :param title: :param download_address: :return: """
    print('下载标题:%s,下载地址:%s' % (title, download_address))
    if not download_address:
        return

    async with aiohttp.ClientSession() as session:
        async with session.get(download_address) as response:
            # 注意:因为标题中包含空格、/等特殊符号,这里要作一些处理
            file_full_path = file_path + title.replace(" ", "").replace("/", "") + ".mp4"
            video = await response.read()
            with open(file_full_path, 'wb') as file:
                file.write(video)
                print('电影:%s下载成功' % title)

loop = asyncio.get_event_loop()
# 任务列表
tasks = []
for film in filmSpider.films:
     tasks.append(download_a_film(film.get('title'), film.get('download_address')))

loop.run_until_complete(asyncio.gather(*tasks))
loop.close()
复制代码


喝一杯咖啡回来,Python 君已经将几千部微电影下载到本地了。



本文首发于公众号「 AirPython 」,后台回复「 新片场 」便可获取完整代码。

相关文章
相关标签/搜索