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 」,後臺回覆「 新片場 」便可獲取完整代碼。

相關文章
相關標籤/搜索