小虾虎鱼

小虾虎鱼

使用async和await控制爬虫执行

作者 禾惠 发表于 2016/11/09 22:34 ,最后修改于 2016/11/10 10:32

为了解决js的回调嵌套问题(金字塔),ES6新增了PromiseGenerator来解决此问题。但我个人觉得Promise需要不断then,虽然没有出现金字塔现象,但总觉得还不够直观,而Generator也需要next依然不够直观易懂。随着Nodejs 7.0的发布,是时候玩玩Async函数了。 今天刚好用Async函数来做了一个爬虫,个人觉得代码的易读性比PromiseGenerator好。如果你还不会Async,可以看看阮一峰写的文章

Nodejs 7.0开启async/await功能

默认Nodejs 7.0并没有开启该功能,需要我们在启动程序时传入参数开启,启动方法:

node --harmony_async_await index.js

爬虫执行的步骤

  1. 获取邀请码
  2. 通过邀请码进行注册账号
  3. 登陆网站
  4. 获取需要的信息

使用回调的写法

// 获取邀请码
console.log("正在获取邀请码...");
request(inviteUrl, function (error, response, body) {
    if (!error && response.statusCode == 200) {
        /// ...
        let code;
        // 注册
        request(registerUrl, function (error, response, body) {
            if (!error && response.statusCode == 200) {
                // 登录
                console.log(json, "正在登录...");
                request(loginUrl, function (error, response, body) {
                    if (!error && response.statusCode == 200) {
                        /// 获取信息
                        request(anyUrl, function (error, response, body) {
                            if (!error && response.statusCode == 200) {
                                console.log(body, "获取信息成功");
                            } else {
                                console.log("获取信息:", error.message);
                            }
                        });
                    } else {
                        console.log("登录:", error.message);
                    }
                });
            } else {
                console.log("注册账号:" + error.message);
            }
        });
    } else {
        console.log("获取邀请码失败:" + error.message);
    }
});

这种多层嵌套,我相信你已经看的很恶心了。

使用async/await改写

获取邀请码

function getInvite() {
    return new Promise((resolve, reject) => {
        console.log("正在获取邀请码...");
        request(inviteUrl, function (error, response, body) {
            if (!error && response.statusCode == 200) {
                /// ...
                resolve(code);
            } else {
                reject("获取邀请码失败:" + error.message);
            }
        });
    });
}

注册账号

function registry(){
    console.log("正在注册账号...");
    return new Promise((resolve, reject) => {
        request(registerUrl, function (error, response, body) {
            if (!error && response.statusCode == 200) {
                let json = JSON.parse(body);
                if (json.code === 200 && json.data.error === 0) {
                    console.log(json, "正在登录...");
                    resolve();
                } else {
                    reject(json);
                }
            } else {
                reject("注册账号:" + error.message);
            }
        });
    });
}

登录

function login() {
    let that = this;
    return new Promise((resolve, reject) => {
        request(loginUrl, function (error, response, body) {
            if (!error && response.statusCode == 200) {
                let json = JSON.parse(body);
                if (json.code === 200 && json.data.error === 0) {
                    resolve(6);
                } else {
                    console.log(json.data.message);
                    reject(json.data.message);
                }
            } else {
                reject("登录:", error.message);
            }
        });
    });
}

获取需要的信息或干其他事情

function doSomething(){
    return new Promise((resolve, reject) => {
        request(anyUrl, function (error, response, body) {
            if (!error && response.statusCode == 200) {
                let json = JSON.parse(body);
                if (json.code === 200 && json.data.error === 0) {
                    console.log("获取信息成功");
                    resolve(json);
                } else {
                    console.log(json.data.message);
                    reject(json.data.message);
                }
            } else {
                reject("获取信息:", error.message);
            }
        });
    });
}

按步骤执行代码

async function start(){
    let data;
    try {
        let code = await getInvite();
        await register(code);
        await login();
        data = await doSomething();
        return data;
    } catch (err) {
        console.log(err);
    }
}

start().then(data => console.log(data));

整个代码流程就是这样,是不是觉得使用了Async代码结构清晰很多。如果你对PromiseGenerator熟悉的话,有没有发现在Async中都有它们的身影,如在代码中同样需要用到Promise,再如最后执行代码那步有没有发现关键词asyncGenerator函数中的*awaitGenerator函数中的yeild关键词。

完整的代码实例请移步至 fetch-ss

我欣赏你的好品味~

打开支付宝扫一扫