ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Python爬虫 之 异步 协程 爬虫

2021-06-27 16:02:52  阅读:226  来源: 互联网

标签:pearvideo loc 协程 Python each 爬虫 url mp4 time


异步 协程 爬虫

高性能的异步爬虫

初识异步爬虫方式

  1. 多线程,多进程(不建议):
    - 优点:可以为相关堵塞的操作单独开启线程和进程,堵塞程序就会实现异步执行
    - 缺点:无法限制多进程或多进程
  2. 线程池,进程池:
    - 优点:降低系统对于线程和进程创建和销毁的频率,减小系统开销
    - 缺点:池中线程和进程数量有上限

举个栗子直观地看一下线程的作用吧

import time

def get_text(char):
    print("正在下载",char)
    time.sleep(2)
    print("成功加载",char)
    return char

#单线程运行:
#运行文本
text=['a','b','c','d']
#记录开始时间
start_time=time.time()
for i in text:
    get_text(i)
#记录结束时间
end_time=time.time()
print("单进程共需要时间:",end_time-start_time)


#多线程运行
#导库
from multiprocessing.dummy import Pool
#实例化4线程池
pool=Pool(4)
start_time=time.time()

text_list=pool.map(get_text#进行多线程的目标函数名,没有()
                   ,text#传入数据的列表
                   )
#该函数返回值为函数return值组成的列表,顺序和传入列表相对应
end_time=time.time()
print("多进程共需要时间:",end_time-start_time)
print(text_list)

结果为:
正在下载 a
成功加载 a
正在下载 b
成功加载 b
正在下载 c
成功加载 c
正在下载 d
成功加载 d
单进程共需要时间:8.001578569412231
正在下载 a
正在下载 b
正在下载 c
正在下载 d
成功加载 b成功加载 d
成功加载 c
成功加载 a
多进程共需要时间:2.0006678104400635
['a', 'b', 'c', 'd']
我们发现:多线程输出的顺序结束时间是随机的,也证实了多线程之间运行并不会相互影响

来喽,爬取最新梨视频

梨视频网址

代码和部分讲解

import os
from lxml import etree
import re
import requests
from multiprocessing.dummy import Pool

header = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.5211 SLBChan/25"
}
# 梨视频url
url = 'https://www.pearvideo.com/'
# cookie破解
session = requests.Session()
session.get(url=url, headers=header)
# 获取前台代码并解析目标url  讲解【1】
response = session.get(url=url, headers=header).text
tree = etree.HTML(response).xpath('/html/body/div[2]/div[9]/div[2]/div[2]/ul/li')

# 存储名字和地址的列表
content_name_loc = []
for each_tree in tree:
    # each_tree.xpath('./div/a/@href')[0]解析地址不完整,要完整化   讲解【1】
    each_loc = 'https://www.pearvideo.com/' + each_tree.xpath('./div/a/@href')[0]
    # 确定视频存储名称   讲解【1】
    each_name = each_tree.xpath('./div/a/div[2]/text()')[0] + ".mp4"

    # url_2是each_loc进入界面内部的一个包,我们不能直接从前台界面直接获取包,所以要获取一个新的url
    # 这个url_2是对于所有视频详情界面共有的地址,通过不同的params里的'contId'值实现不同视频的呈现
    # 讲解【2】
    url_2 = 'https://www.pearvideo.com/videoStatus.jsp?'
    header_1 = {
   		 # 讲解【2】
        'Referer': each_loc
        ,
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.5211 SLBChan/25"
    }

    # 我们发现'contId'参数并不是毫无规律,而是我们在主界面获取each_loc的后面的一串数字
    # 栗子:
    # 若each_loc=https://www.pearvideo.com/video_1733139
    # 那么'contId'参数就是‘1733373’,所以我们通过‘_’来进行分割
    params = {
  		 # 这个参数位置在哪见讲解【2】
        'contId': each_loc.split('_')[-1]
    }
    each_response = session.get(url=url_2, params=params, headers=header_1).json()

    # 看下面讲解
    str_1 = each_response["videoInfo"]["videos"]["srcUrl"]
    """
    each_response的json字符串
    {
	"resultCode":"1",
	"resultMsg":"success", "reqId":"9424322a-fe48-48a8-86fd-85070498a1e8",
	"systemTime": "1624770918308",
	"videoInfo":{"playSta":"1","video_image":"https://image1.pearvideo.com/cont/20210624/11429718-143425-1.png",
	"videos":{"hdUrl":"","hdflvUrl":"","sdUrl":"","sdflvUrl":"","srcUrl":"https://video.pearvideo.com/mp4/third/20210624/1624770918308-11429718-143415-hd.mp4"}}
    }

    我们需要提取的是"https://video.pearvideo.com/mp4/third/20210624/1624770918308-11429718-143415-hd.mp4"
    但是我们在网页上打开该网址发现显示:404 Not Found
    这是为什么呢?
    因为真正的网址是这个形式的'https://video.pearvideo.com/mp4/third/20210624/cont-1733139-11429718-143415-hd.mp4'
    所以发现失败了,那么我们想,视频界面是ajax,不能解析出来,用抓包又不是我们想要的
    但是在山重水复时,静下心来发现我们刚才提取的网址和视频网址那么相像
    于是有了一个得到的想法:
    分割已有的提取的网址来组成我们的目标网址!!!
    each_loc='https://www.pearvideo.com/video_1733139'
    str_1="https://video.pearvideo.com/mp4/third/20210624/1624770918308-11429718-143415-hd.mp4"
    new_loc='https://video.pearvideo.com/mp4/third/20210624/cont-1733139-11429718-143415-hd.mp4'
    new_loc就是我们的目标,怎么得到呢?
    就是把str_1的 1624770918308换成cont-1733139
    而cont我想就是参数名,每个视频相同
    对于1733139就是each_loc的后面一串
    于是也就有了下面这一段代码
    那么我们开始一步步剖析它:
    1. a = 'cont-' + each_loc.split('_')[-1]
    each_loc.split('_')结果就是
    ['https://www.pearvideo.com/video''1733139']
    each_loc.split('_')[-1]就是'1733139',在加上'cont-',就是我们想要的结果
    2. re_1 = "(.*)/.*?-(.*)"
       b = re.findall(re_1, str_1)
    这两句就是使用正则表达式提取str_1中的
    'https://video.pearvideo.com/mp4/third/20210624'(因为最后一个/结束,所以用的贪婪匹配)
    和
    '11429718-143415-hd.mp4'
    3. new_loc = b[0][0] + "/" + a + "-" + b[0][1]
    对结果进行拼接得到结果
    不要忘了"/" 和"-"
    这就得到了我们苦苦寻找的视频地址了
    """
    a = 'cont-' + each_loc.split('_')[-1]
    print(str_1)
    re_1 = "(.*)/.*?-(.*)"
    b = re.findall(re_1, str_1)
    new_loc = b[0][0] + "/" + a + "-" + b[0][1]

    print(new_loc)

    # 到这里可能你已经忘了还有多线程的事,嘻嘻嘻
    # 这里为了最后多线程爬取内容更加方便
    # 我们还用字典的格式对数据视频名称each_name和new_loc放于content_name_loc中
    content_name_loc.append({"name": each_name, "loc": new_loc})

# 在这里输出一下看看结果是否符合预期
print(content_name_loc)

# 创建文件夹
if not os.path.exists("./梨视频"):
    os.mkdir("./梨视频")


# 分装线程池
def get_content(dic):
    # 请求数据
    video_data = session.get(url=dic['loc'], headers=header).content
    # 打开文件并写入
    fp = open("./梨视频/" + dic["name"], mode="wb")
    fp.write(video_data)
    fp.close()


# 计算时间(跟网速有关)
start = time.time()
# 实例化Pool,定个数
pool = Pool(len(content_name_loc))
# 多线程运行
pool.map(get_content, content_name_loc)
# 关闭线程
pool.close()
# 等待所有线程结束
pool.join()
end = time.time()
# 输出时间
print(end - start)

看结果:
(提前说明一下,这可不是博主喜欢的内容啊,完全是巧合,要信我,嘻嘻嘻~~~)
在这里插入图片描述

讲解

讲解【1】
在这里插入图片描述
简单的几条线就讲解完了???
对,没错!!!此处无声胜有声
讲解【2】
在这里插入图片描述

蓝色内容就是我们想获取的视频地址!
咦?这是什么吗?我直接爬不得了?还用你的分割?
但是你爬取后就会发现爬去数据里根本找不到这个网址
为什么呢?让我们刷新一下界面

在这里插入图片描述

那个网址就会消失
所以我们怀疑是ajxa,所以我们复制在包里寻找
结果无结果,在XHR中只有一个包。
这个包就是我们提到的合成new_loc的包
另有refer参数需要在headers中
该包的返回值代码中已经提到,这里不再展示

在这里插入图片描述

【持续更新ing】
爱你呦

标签:pearvideo,loc,协程,Python,each,爬虫,url,mp4,time
来源: https://blog.csdn.net/weixin_54884881/article/details/118256529

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有