春暖花开,我见六间房

1. 花开正好,我们也要充满希望

又是一年春暖花开的时候,

image.png

山河温暖,

image.png

万物可爱,


image.png

一切都是那么的生机勃勃,而我们也到了我们该努力勃发的时候了。
今天还谈学习技术,
为避免单调,咱们这里以本地下载保存一个App漂亮小姐姐的视频为例。

接下来咱们进入正题,又到了愉快地学技术的时候啦。

2. 准备环境

工欲善其事必先利其器,我们需要的环境有:fiddler抓包工具、手机模拟器或手机、六间房秀场App,python环境。

这里提一下,六间房秀场App历史版本下载安装,可以本地去豌豆荚网站下载六间房秀场APP的历史版本,地址:https://www.wandoujia.com/apps/7450760/history

打开往下拉,尽量选择较低版本,我下的版本是v7.1.5.0713的,注意下的时候取消勾选优先下载豌豆荚安装,点普通下载就行了。

下载之后直接拖到手机模拟器里点击安装就🆗了。

3. 开始分析

打开fiddler监控请求,并打开六间房秀场App,点开小视频开始查看fiddler:


image.png

成功找到数据包,把url复制粘贴一下,看看

https://v.6.cn/coop/mobile/index.php?act=recommend&padapi=minivideo-getlist.php&page=1

看着url,估计翻页只需要变一下page就行了。

模拟器里视频再往下翻翻看,验证一下猜想,
先清理一下fiddler会话,再往下翻视频:


image.png

把url复制粘贴一下,再看看:

https://v.6.cn/coop/mobile/index.php?act=recommend&padapi=minivideo-getlist.php&page=2

两个放一块对比:

https://v.6.cn/coop/mobile/index.php?act=recommend&padapi=minivideo-getlist.php&page=1
https://v.6.cn/coop/mobile/index.php?act=recommend&padapi=minivideo-getlist.php&page=2

可以看到就page变了,每次翻页加1,证明我们的猜想正确,接下来我们就尝试写代码发请求了。

4. 初次测试

先用requests测试一下看看能不能用:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author  : 冰履踏青云
# @File    : 01.py
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning


#关闭安全请求警告
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
urls = 'https://v.6.cn/coop/mobile/index.php?act=recommend&padapi=minivideo-getlist.php&page=1'
headers = {
    'User-Agent': 'Xc27CgIxEEbhJ3L5ZyaZXDorG8FCEKyWJDvRFdZOsMjDq62c4ivPe321e3netvJYy3w9z35Kk46oAnWClMK3NC6nw25)JAwGMw)5CSgTBa)Ou8hMi4XqakiCYh1dG2MxKm0RAyGKt27OOtXqR8zIHLLWXChr)P99AA@@'
}

response = requests.get(urls, headers=headers, verify=False).json()
print(response)

结果:


image.png

成功返回json数据包,接下来我们用jsonpath直接提取视频标题和播放地址:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author  : 冰履踏青云
# @File    : 01.py


import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
import jsonpath



#关闭安全请求警告
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
urls = 'https://v.6.cn/coop/mobile/index.php?act=recommend&padapi=minivideo-getlist.php&page=1'
headers = {
    'User-Agent': 'Xc27CgIxEEbhJ3L5ZyaZXDorG8FCEKyWJDvRFdZOsMjDq62c4ivPe321e3netvJYy3w9z35Kk46oAnWClMK3NC6nw25)JAwGMw)5CSgTBa)Ou8hMi4XqakiCYh1dG2MxKm0RAyGKt27OOtXqR8zIHLLWXChr)P99AA@@'
}

response = requests.get(urls, headers=headers, verify=False).json()
# print(response)
title_list = jsonpath.jsonpath(response,'$..title')
playurl_list = jsonpath.jsonpath(response,'$..playurl')

print(title_list,len(title_list))
print(playurl_list,len(playurl_list))

image.png

一页视频标题和播放地址都是20个,没啥问题。接下来我们就只需要给播放地址playurl发请求保存视频就🆗了。

5. 第一版 ——requests版本

我们还是先对上面的程序稍微改造一下使其更具有可读性再保存,先下3页看看效果:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author  : 冰履踏青云
# @File    : 02.py


import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
import jsonpath
import os
import time


#关闭安全请求警告
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

def get_url(url,headers):
    '''获取视频标题和播放地址'''
    response = requests.get(url, headers=headers, verify=False).json()
    # print(response)
    title_list = jsonpath.jsonpath(response,'$..title')
    playurl_list = jsonpath.jsonpath(response,'$..playurl')

    # print(title_list,len(title_list))
    # print(playurl_list,len(playurl_list))
    return (title_list,playurl_list)


def save_videos(url):
    '''保存视频'''
    res = get_url(url, headers)
    # print(res)
    print(res[0])
    for i in range(len(res[0])):
        content = requests.get(res[1][i],headers=headers).content
        path = './Video/'
        if not os.path.exists(path):
            os.makedirs(path)
        title = res[0][i].replace('/','_') # 有的标题带表情的是这样的:我们意念合一/大笑/  “/”会影响文件存储,用_替换掉
        with open(path + title + '.mp4', 'ab') as f:
            f.write(content)
        print(title + '.mp4' + '已经下载完成!')


if __name__ == '__main__':
    url = 'https://v.6.cn/coop/mobile/index.php?act=recommend&padapi=minivideo-getlist.php&page={}'

    headers = {
        'User-Agent': 'Xc27CgIxEEbhJ3L5ZyaZXDorG8FCEKyWJDvRFdZOsMjDq62c4ivPe321e3netvJYy3w9z35Kk46oAnWClMK3NC6nw25)JAwGMw)5CSgTBa)Ou8hMi4XqakiCYh1dG2MxKm0RAyGKt27OOtXqR8zIHLLWXChr)P99AA@@'
    }
    start_time = time.time()
    # save_videos()
    for i in range(1,4):
        save_videos(url.format(str(i)))

    end_time = time.time()
    print('全部下载完成,用时:%s'%(end_time-start_time))


运行结果:


image.png

看一下视频文件:

image.png

具体里面的内容我就不展示了,其实就是正常的小姐姐小视频而已,
三页,一页20个视频,总共60个视频也是没问题的。

唯一有点不美的是用了114秒,用的时间看着有点长,下面我们改进一下。

6. 第二版——requests版升级

我们这里为了少改动代码,直接用ThreadPoolExecutor ,代码示例:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author  : 冰履踏青云
# @File    : 02.py

import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
import jsonpath
import os
import time
from concurrent.futures import ThreadPoolExecutor



#关闭安全请求警告
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

def get_url(url,headers):
    '''获取视频标题和播放地址'''
    response = requests.get(url, headers=headers, verify=False).json()
    # print(response)
    title_list = jsonpath.jsonpath(response,'$..title')
    playurl_list = jsonpath.jsonpath(response,'$..playurl')

    # print(title_list,len(title_list))
    # print(playurl_list,len(playurl_list))
    return (title_list,playurl_list)

    # for i in range(len(title_list)):



def save_videos(url):
    '''保存视频'''
    res = get_url(url, headers)
    # print(res)
    # print(res[0])
    for i in range(len(res[0])):
        content = requests.get(res[1][i],headers=headers).content
        path = './Video/'
        if not os.path.exists(path):
            os.makedirs(path)
        title = res[0][i].replace('/','_') # 有的标题带表情的是这样的:我们意念合一/大笑/  用_替换掉
        with open(path + title + '.mp4', 'ab') as f:
            f.write(content)
        print(title + '.mp4' + '已经下载完成!')


if __name__ == '__main__':
    url0 = 'https://v.6.cn/coop/mobile/index.php?act=recommend&padapi=minivideo-getlist.php&page={}'

    headers = {
        'User-Agent': 'Xc27CgIxEEbhJ3L5ZyaZXDorG8FCEKyWJDvRFdZOsMjDq62c4ivPe321e3netvJYy3w9z35Kk46oAnWClMK3NC6nw25)JAwGMw)5CSgTBa)Ou8hMi4XqakiCYh1dG2MxKm0RAyGKt27OOtXqR8zIHLLWXChr)P99AA@@'
    }
    start_time = time.time()
    with ThreadPoolExecutor(3) as t:
        for i in range(1,4):
            url = url0.format(i)
            t.submit(save_videos,url)
    end_time = time.time()
    print('全部下载完成,共用时:%s'%(end_time-start_time))


image.png

稍微好了一些,在翻页数比较少的情况下requests开线程池效率提升并不是很明显(我嫌耗时太长,没有设置很大的页数对比),我们试着再优化一下,再换一种方案。

7. 第三版 ——异步版

接下来我们不用requests了,用支持异步的asyncio,aiohttp开整:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author  : 冰履踏青云
# @File    : 3.py
import os
import time

import requests
import aiohttp
import asyncio
import jsonpath
import aiofiles
from requests.packages.urllib3.exceptions import InsecureRequestWarning

#关闭安全请求警告
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

# 先用requests把前三页视频地址拿到,也可以用async 
# 我这边懒省事儿,直接复制粘贴,反正就三个请求对时间影响不大,主要耗时的是视频流的下载
def get_url():
    '''获取视频标题和播放地址'''
    url = 'https://v.6.cn/coop/mobile/index.php?act=recommend&padapi=minivideo-getlist.php&page={}'
    ls = []
    title_lists = []
    playurl_lists = []

    for i in range(1,4):
        response = requests.get(url.format(str(i)), headers=headers, verify=False).json()
        # print(response)
        title_list = jsonpath.jsonpath(response,'$..title')
        playurl_list = jsonpath.jsonpath(response,'$..playurl')
        title_lists.extend(title_list) # 在原基础上扩展列表
        playurl_lists.extend(playurl_list)
    # print(len(title_lists),len(playurl_lists))
    return (title_lists,playurl_lists)

async def save_video(title,url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url,headers=headers) as resp:
            async with aiofiles.open(f"Video/{title.replace('/','_')+'.mp4'}", mode="wb") as f:
                await f.write(await resp.content.read())  # 把下载到的内容写入到文件中
        print(f"{title.replace('/','_')+'.mp4'}下载完毕")


if __name__ == '__main__':
    headers = {
        'User-Agent': 'Xc27CgIxEEbhJ3L5ZyaZXDorG8FCEKyWJDvRFdZOsMjDq62c4ivPe321e3netvJYy3w9z35Kk46oAnWClMK3NC6nw25)JAwGMw)5CSgTBa)Ou8hMi4XqakiCYh1dG2MxKm0RAyGKt27OOtXqR8zIHLLWXChr)P99AA@@'
    }

    start = time.time()
    path = './Video/'
    if not os.path.exists(path):
        os.makedirs(path)
    res = get_url()
    tasks = []
    for i in range(len(res[0])):
        title = res[0][i]
        url = res[1][i]
        c = save_video(title,url)
        task = asyncio.ensure_future(c)
        tasks.append(task)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))
    end = time.time()
    print('全部下载完成,总用时:%s'%(end-start))



运行结果:


image.png

好了一些,二三百兆的资源下83秒应该是正常的,像这种可能就是受限于网速吧。

本来还想再写个scrapy版本的,仔细想想也没必要,感兴趣的朋友可以自己写一下看看,这里我主要提两个需要注意的点:

  1. 第一点就是scrapy保存文件的逻辑可以在管道端写,不想写管道的也可以直接在主爬虫程序里面(不过这样感觉这个框架也是没咋利用好,不提倡哈)。
  2. 第二点就是要注意scrapy响应接收视频字节流用response.body,相当于requests的response.content和异步的response.content.read()。

其他的应该没啥需要注意的了,如果你写了遇到了问题欢迎来砸我,我最喜欢炒bug吃,嘎嘣脆,还是鸡肉味,咳咳咳。

贫瘠的荒漠会开满鲜花,尽头的街角,也会有人等你回家

本文改动了好多,试了稍微改一丢丢文章就审核不通过了,真难呀。

文章到此结束,欢迎三连,点个赞,收个藏啥的,有问题的尽管砸来,我有故事你有酒,好好交流不分手!哈哈哈!下次见!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容