当前位置 : 主页 > 网络编程 > JavaScript >

认识puppeteer(可以实现高级爬虫)

来源:互联网 收集:自由互联 发布时间:2021-06-28
认识puppeteer ##一步一步认识puppeteer### 了解puppeteer1. Puppeteer是一个node库,他提供了一组用来操纵Chrome的API2. 默认headless也就是无UI的chrome,也可以配置为有UI### puppeteer可以做什么1. 屏幕快
认识puppeteer
##一步一步认识puppeteer

### 了解puppeteer
1. Puppeteer是一个node库,他提供了一组用来操纵Chrome的API
2. 默认headless也就是无UI的chrome,也可以配置为有UI

### puppeteer可以做什么
1. 屏幕快照,打印PDF
2. 高级爬虫(有别于传统爬虫.使用Puppeteer可以拿到渲染后的效果,传统爬虫相当于只能拿到http response)
3. UI自动化测试,使用Puppeteer可以模拟用户操作
4. 页面性能分析(捕获站点的时间线,以便追踪你的网站,帮助分析网站性能问题)

### puppeteer学习
1. 使用puppeteer.launch()运行puppeteer,他会return一个promise,使用then方法获取browser实例


### 使用其爬虫模拟登录github(获取最新文章)

1. 用户名:hjm6666
1. 账 号:hjm10000@sina.com
1. 密 码:hjm10000

参考博文:https://csbun.github.io/blog/2017/09/puppeteer/

持续更新中.....
server.js
const puppeteer = require('puppeteer');
const CREDS = require('./creds.js');
var fs = require('fs');
//将github的首页通过截屏保存到文件中
// async 函数返回一个 Promise,当你需要像同步函数那样调用时,需要使用 await。
// async function run() {
//   const browser = await puppeteer.launch();
//   const page = await browser.newPage();
//   await page.goto('https://github.com');
//   await page.screenshot({path: './data/github.png'});

//   //关闭连接
//   browser.close();
// }
// run();

//利用puppeteer实现登录功能(以非无界面(non headless)模式启动)
async function run() {
    const browser = await puppeteer.launch({ headless: false });
    const page = await browser.newPage();
    await page.goto('https://github.com/login');
    //输入框以及按钮的id值存储 Copy > Copy selector
    const USERNAME_SELECTOR = '#login_field';
    const PASSWORD_SELECTOR = '#password';
    const BUTTON_SELECTOR = '#login > form > div.auth-form-body.mt-3 > input.btn.btn-primary.btn-block';
    //开始登录
    await page.click(USERNAME_SELECTOR); //点击输入框
    await page.type(USERNAME_SELECTOR, CREDS.username);//输入内容  '#kw','puppeteer'
    await page.click(PASSWORD_SELECTOR);
    await page.type(PASSWORD_SELECTOR, CREDS.password);
    await page.click(BUTTON_SELECTOR);
    await page.waitForNavigation();  //提交按钮
    //登陆成功后进行搜索操作
    const userToSearch = 'john';
    const searchUrl = 'https://github.com/search?q=' + userToSearch + '&type=Users&utf8=%E2%9C%93';
    await page.goto(searchUrl);
    await page.waitFor(2 * 1000);

    //搜索到后就开始提取邮箱地址吧 //我们的目的是搜刮用户的 username 和 email

    const USER_LIST_INFO_SELECTOR = '.user-list-item';
    const USER_LIST_USERNAME_SELECTOR = '.user-list-info>a:nth-child(1)';
    const USER_LIST_EMAIL_SELECTOR = '.user-list-info>.user-list-meta .muted-link';
    // const users = await page.evaluate((sInfo, sName, sEmail) => {
    //   return Array.prototype.slice.apply(document.querySelectorAll(sInfo))
    //     .map($userListItem => {
    //       // 用户名
    //       const username = $userListItem.querySelector(sName).innerText;
    //       // 邮箱
    //       const $email = $userListItem.querySelector(sEmail);
    //       const email = $email ? $email.innerText : undefined;
    //       return {
    //         username,
    //         email,
    //       };
    //     })
    //     // 不是所有用户都显示邮箱
    //     .filter(u => !!u.email);
    // }, USER_LIST_INFO_SELECTOR, USER_LIST_USERNAME_SELECTOR, USER_LIST_EMAIL_SELECTOR);

    // fs.writeFile('./train.json',JSON.stringify(users));
    //上面只不过是便利了本页面的数据(现在尝试便利全部页面)
    // 1我们需要知道一共有多少页
    // 1我们可以从看到user的总数以及每页显示多少个
    // 1拿到所有数据后我们将其存放在json文件中
    // fs.writeFile('./data/train.json',JSON.stringify(train));

    // 在搜索结果页底部,如果你把鼠标悬浮在页码按钮上面,可以看到是一个指向下一页的链接。如:第二页的链接是 
    // https://github.com/search?p=2&q=john&type=Users&utf8=%E2%9C%93。
    // 注意到 p=2 是一个 URL 的 query 参数,这将帮助我们跳转到指定的页面。

    const numPages = await getNumPages(page);
    console.log('Numpages: ', numPages);
    for (let h = 1; h <= numPages; h++) {
        // 跳转到指定页码
        await page.goto(`${searchUrl}&p=${h}`);
        // 执行爬取
        const users = await page.evaluate((sInfo, sName, sEmail) => {
            return Array.prototype.slice.apply(document.querySelectorAll(sInfo))
                .map($userListItem => {
                    // 用户名
                    const username = $userListItem.querySelector(sName).innerText;
                    // 邮箱
                    const $email = $userListItem.querySelector(sEmail);
                    const email = $email ? $email.innerText : undefined;
                    return {
                        username,
                        email,
                    };
                })
                // 不是所有用户都显示邮箱
                .filter(u => !!u.email);
        }, USER_LIST_INFO_SELECTOR, USER_LIST_USERNAME_SELECTOR, USER_LIST_EMAIL_SELECTOR);
        users.map(({username, email}) => {
            // TODO: 保存用户信息
            console.log(username, '->', email);
        });
        // 将每一页对应的数据存入到对应的json文件中
        // fs.writeFile('./data/'+h+'.json',JSON.stringify(users));
    }
    // 关闭连接
    await browser.close();
}
// 用来获取页面数。
async function getNumPages(page) {
    const NUM_USER_SELECTOR = '#js-pjax-container > div > div.columns > div.column.three-fourths.codesearch-results > div > div.d-flex.flex-justify-between.border-bottom.pb-3 > h3';
    let inner = await page.evaluate((sel) => {
        return document.querySelector(sel).innerHTML;
    }, NUM_USER_SELECTOR);
    // 格式是: "69,803 users"
    inner = inner.replace(',', '').replace(' users', '');
    const numUsers = parseInt(inner);
    // console.log('numUsers: ', numUsers);
    /*
     * GitHub 每页显示 10 个结果
     */
    const numPages = Math.ceil(numUsers / 10);
    return numPages;
};

run();
网友评论