爬虫-高性能异步爬虫

异步爬虫方式

目的:在爬虫中使用异步实现高性能的数据爬取操作

异步爬虫方式:

  • 多进程,多线程(不建议)

    好处:可以为先关阻塞操作单独开启进程或者线程,阻塞操作就可以异步执行

    坏处:无法无限制开启

  • 线程池,进程池(适当使用)

    好处:可以降低系统对进程或者线程创建和销毁的评率,进而降低系统开销

    坏处:池中线程或进程的数量有上线

  • 单线程+异步协程(推荐)

    event_loop:事件循环,相当于一个无限循环,我们可以把一些函数注册到这个事件循环上,
    当满足某些条件的时候,函数就会被循环执行。

    coroutine:协程对象,我们可以将协程对象注册到事件循环中,它会被事件循环调用。
    我们可以使用 async 关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回
    一个协程对象。
    
    task:任务,它是对协程对象的进一步封装,包含了任务的各个状态。
    
    future:代表将来执行或还没有执行的任务,实际上和 task 没有本质区别。
    
    async 定义一个协程.
    
    await 用来挂起阻塞方法的执行。

线程池基本使用

#使用线程池方式执行
import time
from multiprocessing.dummy import Pool

def get_page(str):
    print("正在下载 :",str)
    time.sleep(2)
    print('下载成功:',str)

start_time = time.time()
name_list =['xiaozi','aa','bb','cc']
#实例化一个线程池对象
pool = Pool(4)
#将列表中每一个列表元素传递给get_page进行处理。
pool.map(get_page,name_list)
pool.close()
pool.join()

print(time.time()-start_time)

线程池实现:爬取梨视频

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

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36"
}

url = "https://www.pearvideo.com/category_4"

page_text = requests.get(url=url, headers=headers).text
tree = etree.HTML(page_text)
li_list = tree.xpath('//*[@id="listvideoListUl"]/li')

video_urls_list = []

for li in li_list:
   detail_url = 'https://www.pearvideo.com/' + li.xpath('./div/a/@href')[0]
   detail_page_text = requests.get(url=detail_url, headers=headers).text
   tree = etree.HTML(detail_page_text)
   video_name = tree.xpath('//*[@id="poster"]/img/@alt')[0] + ".mp4"
   # js动态加载,只能使用正则解析video_url
   ex = 'srcUrl="(.*?)",vdoUrl'
   video_url = re.findall(ex, detail_page_text)[0]
   video_info = {
       "name": video_name,
       "url": video_url
   }
   video_urls_list.append(video_info)

def get_video_data(dic):
    url = dic["url"]
    name = dic["name"]
    print(name, "正在下载...")
    video_data = requests.get(url=url, headers=headers).content
    with open(name, "wb") as fp:
        fp.write(video_data)
        print(name, "正在成功")

pool = Pool(4)
pool.map(get_video_data, video_urls_list)
pool.close()
pool.join()

协程的基本使用

单任务协程使用

import asyncio

async def request(url):
    print('正在请求的url是',url)
    print('请求成功,',url)
    return url

#async修饰的函数,调用之后返回的一个协程对象
c = request('www.baidu.com')

# # 创建一个事件循环对象
# loop = asyncio.get_event_loop()
# # 将协程对象注册到事件循环对象,即loop中
# # 此步骤既注册,又启动了事件循环
# loop.run_until_complete(c)

# task的使用 task是对协程对象的进一步封装
# loop = asyncio.get_event_loop()
# task = loop.create_task(c)
# print(task)
# loop.run_until_complete(task)
# print(task)

# future的使用 future也是协程对象的进一步封装 与task无本质区别
# loop = asyncio.get_event_loop()
# task = asyncio.ensure_future(c)
# print(task)
# loop.run_until_complete(task)
# print(task)

# 绑定回调
def callback_fun(task):
    # result返回的就是任务对象中封装的协程对象对应函数的返回值
    print(task.result())

loop = asyncio.get_event_loop()
task = asyncio.ensure_future(c)

# 任务对象执行前绑定回调函数
task.add_done_callback(callback_fun)

# 执行任务对象
loop.run_until_complete(task)

多任务协程使用

多任务:任务列表注册使用waitloop.run_until_complete(asyncio.wait(tasks))

requests.get是基于同步的请求,必须使用基于异步的网络请求模块进行制定url的请求发送

aiohttp: 基于异步网络请求的模块

# 使用Flask模拟服务器
import asyncio
import requests
import time

start = time.time()
urls = [
    'http://127.0.0.1:5000/bobo',
    'http://127.0.0.1:5000/jay',
    'http://127.0.0.1:5000/tom',
]

async def get_page(url):
    print('正在下载', url)
    #requests.get是基于同步的请求,必须使用基于异步的网络请求模块进行制定url的请求发送
    #aiohttp: 基于异步网络请求的模块
    response = requests.get(url=url)
    print('下载完毕', response.text)
# 将任务添加到任务列表
tasks = [asyncio.ensure_future(get_page(url)) for url in urls]
#将任务列表注册到事件循环对象
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

print('总耗时:', time.time()-start)

多任务异步协程使用

使用模块 aiohttp

获取响应数据操作之前一定要使用await进行手动挂起 await

# 环境安装:pip install aiohttp
# 使用该模块中的ClientSession
import requests
import asyncio
import time
import aiohttp

async def get_page(url):
    async with aiohttp.ClientSession() as session:
        # get()、post():
        # headers,关键字传参
        # params/data,
        # proxy='http://ip:port',不在是字典
        async with await session.get(url) as response:
            # text()返回字符串形式的响应数据
            # read()返回的二进制形式的响应数据
            # json()返回的就是json对象
            # 注意:获取响应数据操作之前一定要使用await进行手动挂起
            page_text = await response.text()
            print(page_text)

start = time.time()
urls = ['http://127.0.0.1:5000/bobo' for i in range(10)]
tasks = [asyncio.ensure_future(get_page(url)) for url in urls]

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

print('总耗时:', time.time()-start)

实战:爬取4k美女图片

知识点:xpath数据解析、多任务异步协程爬取、函数封装

import requests
from lxml import etree
import time, os
import asyncio
import aiohttp

start = time.time()
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36"
}
if not os.path.exists('./libs'):
    os.mkdir('./libs')

def get_img_info(page_url, pic_info_list):
    """
    获取图片信息
    :param page_url: 页面url
    :param pic_info_list: 把图片url和图片名以字典的形式存放在pic_info_list列表中
    :return:
    """
    url = page_url
    page_text = requests.get(url=url, headers=headers).text
    tree = etree.HTML(page_text)
    li_list = tree.xpath('//div[@class="slist"]/ul/li')
    for li in li_list:
        img_src = 'http://pic.netbian.com' + li.xpath('./a/img/@src')[0]
        name = li.xpath('./a/img/@alt')[0].encode('iso-8859-1').decode('gbk')
        pic_info_list.append({"url": img_src, "name": name})

        # 同步爬取
        # data = requests.get(url=img_src).content
        # path = './libs/'+name
        # with open(path,'wb') as fp:
        #     fp.write(data)
        #     print(name,'下载成功')

# 一下是异步爬取的代码
async def down_img(dic):
    """
    多任务异步协程下载图片
    :param dic:
    :return:
    """
    img_url = dic["url"]
    img_name = dic["name"]
    async with aiohttp.ClientSession() as session:
        async with await session.get(url=img_url, headers=headers) as response:
            img_data = await response.read()
            with open(f"libs/{img_name}.jpg", "wb") as fp:
                fp.write(img_data)
                print(f"{img_name}, 下载成功!!!")

url1 = 'http://pic.netbian.com/4kmeinv/index.html'
url2 = 'http://pic.netbian.com/4kmeinv/index_%d.html'

pic_info_list = []

# 第一页图片
get_img_info(url1, pic_info_list)
# 第2-4页图片
for page in range(2,5):
    new_url = format(url2 % page)
    get_img_info(new_url, pic_info_list)

# 多任务异步协程启动
tasks = [asyncio.ensure_future(down_img(dic)) for dic in pic_info_list]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

print('总耗时:', time.time()-start)

原文地址:https://www.cnblogs.com/liuxu2019/p/12112692.html

时间: 2024-10-31 02:35:47

爬虫-高性能异步爬虫的相关文章

高性能异步爬虫

如何提升requests模块爬取数据的效率 多进程或者多线程(不建议) 线程池或者进程池(适当使用) 单线程+异步协程(推荐) 示例爬取梨视频 import requests import re from lxml import etree from multiprocessing.dummy import Pool import random headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebK

高性能异步爬虫02

单线程+异步协程(推荐): -asyncio的一些关键字的说明: event_loop 事件循环:程序开启一个无限循环,把一些函数注册到事件循环上,当满足事件发生的时候,调用相应的协程函数 coroutine 协程:协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象.协程对象需要注册到事件循环,由事件循环调用. task 任务:一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含了任务的各种状态 async:async定义一个协

利用aiohttp制作异步爬虫

简介asyncio可以实现单线程并发IO操作,是Python中常用的异步处理模块.关于asyncio模块的介绍,笔者会在后续的文章中加以介绍,本文将会讲述一个基于asyncio实现的HTTP框架--aiohttp,它可以帮助我们异步地实现HTTP请求,从而使得我们的程序效率大大提高.本文将会介绍aiohttp在爬虫中的一个简单应用.在原来的项目中,我们是利用Python的爬虫框架scrapy来爬取当当网图书畅销榜的图书信息的.在本文中,笔者将会以两种方式来制作爬虫,比较同步爬虫与异步爬虫(利用a

Python实现基于协程的异步爬虫

一.课程介绍 1. 课程来源 本课程核心部分来自<500 lines or less>项目,作者是来自 MongoDB 的工程师 A. Jesse Jiryu Davis 与 Python 之父 Guido van Rossum.项目代码使用 MIT 协议,项目文档使用 http://creativecommons.org/licenses/by/3.0/legalcode 协议. 课程内容在原文档基础上做了稍许修改,增加了部分原理介绍,步骤的拆解分析及源代码注释. 2. 内容简介 传统计算机

(转)新手写爬虫v2.5(使用代理的异步爬虫)

开始 开篇:爬代理ip v2.0(未完待续),实现了获取代理ips,并把这些代理持久化(存在本地).同时使用的是tornado的HTTPClient的库爬取内容. 中篇:开篇主要是获取代理ip:中篇打算使用代理ip,同时优化代码,并且异步爬取内容.所以接下来,就是写一个:异步,使用代理的爬虫.定义为:爬虫 v2.5 为什么使用代理 在开篇中我们爬来的代理ip怎么用? 在需要发送请求的时候,需要把请求,先发送到代理服务器(通过代理ip和端口),再由代理服务器请求目标网站.目标网站返回响应的时候也是

深入理解协程(四):async/await异步爬虫实战

本文目录: 同步方式爬取博客标题 async/await异步爬取博客标题 本片为深入理解协程系列文章的补充. 你将会在从本文中了解到:async/await如何运用的实际的爬虫中. 案例 从CSDN上批量爬取指定文章的标题.文章列表如下: urls = [ 'https://blog.csdn.net/Jmilk/article/details/103218919', 'https://blog.csdn.net/stven_king/article/details/103256724', 'h

爬虫与反爬虫

转自:https://mp.weixin.qq.com/s/-w-yC6PCdTOpfKS8HZEleA 前言 爬虫与反爬虫,是一个很不阳光的行业. 这里说的不阳光,有两个含义. 第一是,这个行业是隐藏在地下的,一般很少被曝光出来.很多公司对外都不会宣称自己有爬虫团队,甚至隐瞒自己有反爬虫团队的事实.这可能是出于公司战略角度来看的,与技术无关. 第二是,这个行业并不是一个很积极向上的行业.很多人在这个行业摸爬滚打了多年,积攒了大量的经验,但是悲哀的发现,这些经验很难兑换成闪光的简历.面试的时候,

Voovan 是一个高性能异步网络框架和 HTTP(Java)

Voovan 是一个高性能异步网络框架和 HTTP 服务器框架,同时支持 HTTP 客户端抓取.动态编译支持.数据库访问封装以及 DateTime.String.Log.反射.对象工具.流操作.文件操作.异步双向通道等功能.旨在提供可靠.方便.可单元测试的代码.它是一个无任何依赖的独立工具包,希望能够方便广大开发者快速的实现应用. 作者:@愚民日记 地址:http://git.oschina.net/helyho/Voovan http://www.oschina.net/news/80909/

python 网络爬虫,python 网络爬虫

# -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' import urllib2 #例子 LOGIN='wesc' PASSWD="you'llNeverGuess" URL='http://localhost' def h1(url): from urlparse import urlparse as  up hdlr=urllib2.HTTPBasicAuthHandler() hdlr.add_pas