实战:异步爬取之异步的简单使用

作者: 渔父歌 | 来源:发表于2018-08-17 15:43 被阅读26次

一、使用异步的注意事项

  1. 异步代码中不能有耗时的 I/O操作,像文件读写、网络请求、数据库读写等操作都需要使用对应的异步库来代替。
  2. 异步代码要尽可能短小,短小的意思就是功能要尽可能细分,前面讲过异步在任务量较少的时候性能并不能达到最优,我们可以通过合理地拆分代码来增加任务量,从而达到提高性能的目的。

二、使用异步需要了解的两个重要的类

  1. AbstractEventLoop,我们可以把它简称为 EventLoop类或者事件循环。事件循环是整个异步的基础,所有的异步操作都在事件循环里完成。

    这里我们需要了解并学会使用它的如下几个方法:

    • run_until_complete(Future) 该方法接受一个或多个 Future对象作为参数,然后运行这些对象直到全部完成并返回它们的结果
    • run_forever() 让事件循环一直运行下去,直到 stop() 方法被调用,当 stop() 方法被调用时,会继续执行完正在执行的任务,但是这些任务的回调和未被执行的任务将不再执行。
    • create_task()create_future() 光看名字可能大家会误以为这两个方法的功能是创建一个 Task类或者 Future类并将其返回,事实上这两个方法的功能确实包括这个,但是除此之外它们还会将创建的对象添加到事件循环中去。
  2. Future,Future对象类似于 JavaScript里的 Promise对象,简单来说就是该对象承诺未来的某个时候会返回一个结果,但是具体的时间是不确定的。

    所以我们一般在回调函数里使用 Feture对象,因为这时候 Feture对象一定有返回结果。

    • add_done_callback(func) 这个方法为 Future对象添加一个回调函数,该函数接收一个 Future对象作为第一个参数,在函数里我们可以通过这个对象来取得其执行结果。
  3. 使用过 asyncio库的朋友可能会疑惑为什么没有 Task类,这是因为 Task 类是 Future 类的子类,我们可以将它们视作具有相同功能的两个类

三、使用异步的基本方法

首先,对于少量的请求(几百)我们不推荐使用异步,一般是成千上万的请求我们才使用异步,比如说爬取全站。

在同步代码中我们爬取的一般步骤是:请求页面---->解析页面---->获取结果---->保存结果

异步中也是类似的顺序,不过我们需要使用回调来确保它们按顺序执行,像下面这样:

请求页面---->回调:解析页面---->获取结果---->保存页面(异步)

比如我们要获取简书用户的关注列表,我们的代码顺序应该是:

请求页面---->回调:处理页面---->获取结果并打印,代码如下:

#-*- coding: utf-8 -*
import asyncio
import aiohttp
import random

from lxml import etree


PER_NUM = 9

async def get_response(url, **kwargs):
    if 'headers' not in kwargs:
        kwargs['headers'] = {
            'User-Agent': "Mozilla/5.0 (X11; U; Linux x86_64; zh-CN; rv:1.9.2.10) Gecko/20100922 Ubuntu/10.10 (maverick) Firefox/3.6.10",
        }

    async with session.get(url, **kwargs) as response:
        print(response.status)
        return await response.read()

def process_response(future):
    dom = etree.HTML(future.result())

    items = dom.xpath('//ul/li//div[@class="info"]')

    for item in items:
        user = {}

        user['uid'] = item.xpath('./a/@href')[0].split('/')[2]
        user['follow_num'] = int(item.xpath('./div/span[1]/text()')[0].replace('关注', '').strip())
        user['fans_num'] = int(item.xpath('./div/span[2]/text()')[0].replace('粉丝', '').strip())
        user['article_num'] = int(item.xpath('./div/span[3]/text()')[0].replace('文章', '').strip())

def entry_point(param):
    if isinstance(param, asyncio.Future):
        users = param.result()
    else:
        users = param

    for user in users:
        uid = user['uid']
        follow_num = user['follow_num']
        max_page = int(follow_num / PER_NUM) if (follow_num % PER_NUM) == 0 else int(follow_num / PER_NUM)+1
        following_urls = ['https://www.jianshu.com/users/{}/following?page={}'.format(uid, i) for i in
                          range(1, max_page+1)]

        for following_url in following_urls:
            task = loop.create_task(get_response(following_url))
            task.add_done_callback(process_response)


loop = asyncio.get_event_loop()
session = aiohttp.ClientSession(loop=loop)

users = [{'uid': 'a3ea268aeb60', 'follow_num': 525, 'fans_num': 2521, 'article_num': 118}]

entry_point(users)

loop.run_forever()

在段代码中我们通过 entry_point 函数来将所有的请求添加到事件循环中,并且为每个请求添加了一个回调函数来获取关注者的信息,示意图如下:

相关文章

  • 实战:异步爬取之异步的简单使用

    一、使用异步的注意事项 异步代码中不能有耗时的 I/O操作,像文件读写、网络请求、数据库读写等操作都需要使用对应的...

  • 实战:异步爬取之初识异步

    一、为什么要用异步? 许多之前没有听说过异步地朋友可能看到标题地第一反应就是:什么是异步?为什么要用异步? 我们先...

  • Dart中的异步支持

    文章参考:《Flutter实战》 使用async和await关键字编写异步程序async :用来表示函数是异步的,...

  • 读书笔记#Java异步编程实战-上

    Java异步编程实战 chap1 认识异步编程 异步编程概念与作用在使用同步编程方式时,由于每个线程同时只能发起一...

  • 2-2 异步调用

    使用 异步调用的使用非常简单,只需要如下配置 async="true" 便是异步调用,默认同步。 异步调用指的...

  • promise任务队列串行化执行

    js经常会遇到异步的执行,简单的异步执行可以使用回调,多个异步回调执行可以使用await/async解决。遇到多个...

  • AJAX中

    同步虽然简单,但使用异步调用 才是我们真正常用的手段 。使用异步 调用的时候 需要触发readystatechan...

  • 2018-12-28

    简单爬虫项目(二) 对数据资源使用ajax异步请求网站进行爬取的几种方式 请求分析详见ajax请求分析 Phant...

  • 使用多线程提高REST服务性能

    目录 使用Runnable异步处理rest服务 使用DeferredResult异步处理rest服务 异步处理配置...

  • 零基础小白学python之「爬取贝克街用户」(三)

    话说python爬虫界,有个非常知名的框架Scrapy。异步爬取,使用简单,功能强大。小编学习之,练习之。贝克街,...

网友评论

    本文标题:实战:异步爬取之异步的简单使用

    本文链接:https://www.haomeiwen.com/subject/wemobftx.html