认识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();
