背景
笔者最近在做个小工具,需要爬一些数据。这种场景显然用 FaaS 是最划算的,于是有了这篇《不用爬虫,用 FaaS 来获取股票期权数据》。
有些数据没法通过接口直接获得,必须得爬网页的数据,然后从页面里读数据。这个也还好说,只要能够爬到页面的源代码,然后在本地用 cheerio 之类的库解一下,然后像用 jQuery 一样读取想要的元素即可。
但是,最近碰到了个新问题。有的数据是需要登录后才能展示全的,也就是说爬数据的时候需要带上 cookie。登录接口又做了加密算法,没法直接调接口。这种情况要怎么办呢?
嘿嘿,当然难不倒我这个老司机了。我们有 Puppeteer(以下简称 pptr)啊,有了 pptr,任何场景都难不倒我们。
不知道 pptr 的同学可以自己查一下,简单说就是一个 headless 浏览器,理论上我们可以用它模拟任何人为操作,比如点点点,敲敲敲,划划划。
那么问题来了,FaaS 里面能用 pptr 吗?答案当然是肯定的,要不我写这篇干什么
正文
新建 pptr 函数
这里以阿里云的「函数计算 FC」为例。有 2 种方法:
第一种是按照它给的模板(强烈推荐),直接生成有 pptr 的函数。
第二种是自己创建,然后给函数加个 pptr 的层。还需要注意版本是否匹配,很麻烦的(别问我怎么知道的)。
这里我们只说第一种。创建完函数之后,它会有个示例代码,很清晰(就是这 ES6 和 ES5 混用的语法......):
js
'use strict';
const puppeteer = require('puppeteer');
function autoScroll(page) {
return page.evaluate(() => {
return new Promise((resolve, reject) => {
var totalHeight = 0;
var distance = 100;
var timer = setInterval(() => {
var scrollHeight = document.body.scrollHeight;
window.scrollBy(0, distance);
totalHeight += distance;
if (totalHeight >= scrollHeight) {
clearInterval(timer);
resolve();
}
}, 100);
})
});
}
exports.handler = (event, context, callback) => {
(async () => {
const browser = await puppeteer.launch({
headless: true,
args: [
'--disable-gpu',
'--disable-dev-shm-usage',
'--disable-setuid-sandbox',
'--no-first-run',
'--no-zygote',
'--no-sandbox',
'--single-process'
]
});
let url = 'https://www.serverless-devs.com';
const page = await browser.newPage();
await page.emulateTimezone('Asia/Shanghai');
await page.goto(url, {
'waitUntil': 'networkidle2'
});
await page.setViewport({
width: 1200,
height: 800
});
await autoScroll(page)
let path = '/tmp/example';
await page.screenshot({ path: path, fullPage: true, type: 'png' });
await browser.close();
callback(null, "success!")
})().catch(err => {
callback(err.message, null);
});
}
直接点击「测试函数」就能看到效果了。这里要强调一下,puppeteer.launch
方法里的 args
参数,一定要写全了,否则极大可能会报错。
代码实现
好了,接下来就是实现我们自己的登录逻辑了。其实到了这里就没什么难度了,直接上代码:
js
'use strict';
const puppeteer = require('puppeteer');
const getJiSiLuCookie = async () => {
const browser = await puppeteer.launch({
headless: true,
args: [
'--disable-gpu',
'--disable-dev-shm-usage',
'--disable-setuid-sandbox',
'--no-first-run',
'--no-zygote',
'--no-sandbox'
]
});
const page = await browser.newPage();
await page.goto('https://www.jisilu.cn/account/login/');
await page.waitForSelector('input[name=user_name]');
await page.type('input[name=user_name]', 'your user name');
await page.type('input[name=password]', 'your password');
await page.click('.user_agree input[type=checkbox]');
await page.click('.btn-jisilu');
await page.waitForNavigation({ waitUntil: 'networkidle2' });
const cookie = await page.evaluate(() => document.cookie);
await browser.close();
return cookie;
};
exports.handler = async (event, context, callback) => {
try {
const cookie = await getJiSiLuCookie();
callback(null, cookie);
} catch (e) {
console.log(e);
callback(e, null)
}
}
这里用的是登录 集思录 的例子,好在它不需要验证码,如果需要验证码,那就是另一个故事了。大概需要用到截屏和存储,我们以后再聊。
更多 pptr 调试开发的技巧,可以看这一篇《如何用 puppeteer 爬取「飞书」wiki 知识库文档的数据?》,相信我,看完你一定会有收获。
结语
FaaS 是各大云厂商都有的服务,只不过叫的名字不同。对于小流量的场景来说,比买一个服务器划算多了。
说实话,之前真没想到 FaaS 里面竟然能用 pptr。直到碰到问题之后一查才发现,纳尼?!这么高级,这么方便了吗?
云计算其实没有多数人想的那么神秘,只要自己工程方面的基本功扎实,这些服务用起来真的很方便,很顺手,也很经济。推荐大家多多关注,学习和应用哦。
PS:最近整理电脑,才想起来之前在腾讯云工作的时候,还考了个腾讯云架构师的证书,哈哈,赶紧加到简历里。