AnnVoV / blog

24 stars 2 forks source link

puppeteer + socket.io 模拟登录并切换账号 #19

Open AnnVoV opened 6 years ago

AnnVoV commented 6 years ago

什么是puppeteer?

puppeteer 可以用来干什么?

puppeteer 可以帮我们做很多事情,比如:UI自动化测试,性能分析等。

puppeteer 模拟登录我遇到的几个问题,以及如何解决的?

例子1: 基础模拟登录,不带socket.io (无滑动验证码)

const puppeteer = require('puppeteer');
async function login() {
    let index = 0;
    const browser = await puppeteer.launch({
        headless: false,
    });
    page = await browser.newPage();
    await page.goto('https://www.kaola.com/login.html');
    await page.click('div[class="name head2 j-tag"]');
    const frame = await page.frames().find(f => {
        index = (f.name().indexOf('x-URS-iframe') !== -1) ? (index + 1) : index;
        if (index === 2) {
            return f; // 这里这么写是因为页面上第二个iframe 才是邮箱登录
        }
    });
    const email = await frame.waitForSelector('input[data-type="email"]');
    // 注意这里用waitForSelector 方法参考了这个issue: Any way to check iframe loaded successfully?? https://github.com/GoogleChrome/puppeteer/issues/1361
    await email.click();
    await email.type(process.argv[2]); // 第二个参数:用户名
    const pass = await frame.$('input[class="j-inputtext dlpwd"]');
    await pass.click();
    await pass.type(process.argv[3]); // 第三个参数:密码
    const loginBtn = await frame.$('#dologin');
    loginBtn.click();
}

login()
.catch((err) => {
    console.log(err);
});

例子2: 模拟登录,有socket.io (无滑动验证码)

// server.js
const Koa = require('Koa');
const app = new Koa();
const server = require('http').createServer(app.callback());
const io = require('socket.io')(server);
const puppeteer = require('puppeteer');
let wsUrl;

async function openBrowser() {
    const browser = await puppeteer.launch({
        headless: false,
    });
    const page = await browser.newPage();
    wsUrl = await browser.wsEndpoint();// websocket url
}

async function login(account, password, url) {
    puppeteer.connect({"browserWSEndpoint": wsUrl})
    .then(async browser => {
        const pageList = await browser.pages();
        const page = pageList[pageList.length - 1];
        let count = 500;
        let frame;
        let email;

        await page.goto('https://m.kaola.com/login.html', {
            waitUntil: 'networkidle2',
            timeout: 3000000,
        });
        await page.setDefaultNavigationTimeout(10000000);
        await page.click('li[class="email"]');
        await page.waitFor(3000); // 先3s 如果不行 不断查找直到ok
        frame = await page.frames().find(f => {
            return f && (f.url().indexOf('index_dl.html') !== -1);
        });
        while(!email) {
            // 注意这里用waitForSelector 方法参考了这个issue: Any way to check iframe loaded successfully?? https://github.com/GoogleChrome/puppeteer/issues/1361
            email = await frame.$('input[data-type="email"]');
        }

        await email.focus();
        await frame.$eval('input[data-type="email"]', input => {
            // 如果input 文本框中有默认的邮箱地址,则清除
            if(input.value) {
                debugger;
                input.value = '';
            }
        });

        await email.type(account); // 第二个参数:用户名
        const pass = await frame.$('input[class="j-inputtext dlpwd"]');
        await pass.click();
        await pass.type(password); // 第三个参数:密码
        const loginBtn = await frame.$('#dologin');
        await page.waitFor(3000);
        await loginBtn.click();
    });
}

io.on('connection', function (socket) {
    console.log('connection');
    socket.on('userInfo', function (data) {
        const account = data.account;
        const pass = data.pass;
        const url = data.url;
        login(account, pass, url);
    });
});

server.listen(3000, '127.0.0.1');
openBrowser();
// client.js
var socket = require('socket.io-client')('http://127.0.0.1:3000');
socket.on('connect', () => {
    socket.emit('userInfo', {
        account: process.argv[2],
        pass: process.argv[3],
        url: process.argv[4],
    });
});

例子3: 模拟登录 (有滑动验证码)

如果遇到有验证码的情况,我们需要使用一个叫resemble.js的库,它可以帮助我们进行图片的diff相关的操作。主要参考了下面这2篇文章, 感觉非常的赞 https://blog.oldj.net/2017/11/01/captcha-trick/ https://juejin.im/post/5a902e76f265da4e7832b2fb

拓展

基于例子2可以再集合Electron 再写点,后面会补充上来...

参考资料: 1.利用UI自动化破解滑动验证码 https://juejin.im/post/5a902e76f265da4e7832b2fb 2.使用 Node.js 模拟滑动验证码操作 https://blog.oldj.net/2017/11/01/captcha-trick/ 3.无头浏览器Puppeteer初探傀儡师 https://zhuanlan.zhihu.com/p/30203613 4.大前端神器安利之 Puppeteer https://juejin.im/entry/5a3aa0e86fb9a045076fd385 5.chrome devtools protocol https://www.wangshaoxing.com/blog/2017-08-24-chrome-devtools-protocol.html 6.puppeteer 中文api https://zhaoqize.github.io/puppeteer-api-zh_CN/#/?id=%E6%A6%82%E8%BF%B0 7.https://stackoverflow.com/questions/51039569/puppeteer-chrome-get-active-visible-tab

mahaoming commented 5 years ago

hello,如果用puppteer 登陆带有验证码的有什么方案,用阿里的函数运算,获取到验证码后再访问原来那个连接就不一样了

AnnVoV commented 5 years ago

hello,如果用puppteer 登陆带有验证码的有什么方案,用阿里的函数运算,获取到验证码后再访问原来那个连接就不一样了

如果是滑动验证码:用这个库:https://github.com/HuddleEng/Resemble.js 可以通过比对出一张完整图片,和待拼图的图片之间的差异,获取到坑位信息,然后再利用puppteer模拟滑动