认识puppeteer ##一步一步认识puppeteer### 了解puppeteer1. Puppeteer是一个node库,他提供了一组用来操纵Chrome的API2. 默认headless也就是无UI的chrome,也可以配置为有UI### puppeteer可以做什么1. 屏幕快
##一步一步认识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();