介绍
爬虫就是自动化浏览网站程序,收集我们所需要的数据信息,不需要人为频繁的执行一些操作。
什么是Puppeteer?
Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol. Puppeteer runs headless by default, but can be configured to run full (non-headless) Chrome or Chromium.
Puppeteer是一个Node库,它提供了一个高级API来通过DevTools控制Chrome或Chromium。Puppeteer默认运行无头,但可以配置为(有头)Chrome或Chromium。
Puppeteer是怎么爬的呢?
使用Node爬虫还可以采用cheerio来爬取,但是cheerio只能爬取服务端渲染的页面,而且只能是静态页面。而Puppeteer是模拟一个浏览器,请求网站数据信息,并能够进行任何模拟的操作(点击、滑动等),并且支持跳转页面,动态的获取页面内的数据。就是模拟人浏览网站获取数据。
官方介绍:Puppeteer官方地址
PuppeteerAPI介绍:PuppeteerAPI,这个需要看下。
实践
- 简单爬取一个页面(以淘宝首页为例)
const chromePaths = require('chrome-paths');
const puppeteer = require('puppeteer-core');
//自动滚动请求
async function autoScroll(page) {
await page.evaluate(async () => {
await 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);
});
});
}
async function main() {
const browser = await puppeteer.launch({ //启动配置
headless: false, // 使无头浏览器可见,便于开发过程当中观察
executablePath: chromePaths.chrome, //可执行文件的路劲,默认是使用它自带的chrome webdriver,chrome-paths.chrome会返回本机chrome地址
ignoreDefaultArgs: ["--enable-automation"],
});
const page = await browser.newPage();//打开新的空白页
await page.goto('https://www.taobao.com/')//填写前往页面地址
await page.waitForSelector('.taobao') // 等待首页加载出来
await autoScroll(page); // 滚到到底部(高度可以自己计算),保证爬取部分全部加载
await page.waitForSelector('.taobao>div:nth-child(9)') // 等待爬取内容加载完成
const result = await page.evaluate( () => {
let arrList = [];
const itemList = document.querySelectorAll("body > div.layer.clearfix > div > div > div > ul > a");
for (var element of itemList) {
const List = {};
const title = element.querySelector('.info>h4').innerText
List.title = title;
arrList.push(List);
}
return arrList
});
console.log(result)
}
main()
接下来看看我们打印出来的爬取到的数据- 爬虫解决登录问题
做过爬虫的小伙伴应该都知道,很多电商网站都会做反爬,分类商品页,详情页,订单页等需要我们登录之后才可以浏览,在登录页会做一系列检测判断是否为爬虫。我们试着正常去登录。
const chromePaths = require('chrome-paths');
const puppeteer = require('puppeteer-core');
//滑块滑动方法
async function move(page, initialX, initialY, xlength = 0, ylength = 0) {
const mouse = page.mouse
await mouse.move(initialX, initialY)
await mouse.down()
await mouse.move(initialX + xlength, initialY + ylength, { steps: 20 })
await page.waitForTimeout(2000)
await mouse.up()
}
async function main() {
const browser = await puppeteer.launch({ //启动配置
headless: false, // 使无头浏览器可见,便于开发过程当中观察
executablePath: chromePaths.chrome, //可执行文件的路劲,默认是使用它自带的chrome webdriver,chrome-paths.chrome会返回本机chrome地址
ignoreDefaultArgs: ["--enable-automation"],
});
const page = await browser.newPage();//打开新的空白页
await page.goto('https://login.taobao.com/member/login.jhtml?spm=a21bo.jianhua.754894437.1.5af911d913DtRD&f=top&redirectURL=https%3A%2F%2Fwww.taobao.com%2F')//填写前往页面
//等待登录表单加载出来
await page.waitForSelector("#login-form")
// 填充账号密码
await page.type('#fm-login-id', '*******', { delay: 50 });
await page.type('#fm-login-password', '******', { delay: 50 });
// 判断是否需要滑块验证
const isShowSlider = await page.$eval("#login-form > div.fm-field.baxia-container-wrapper > div.baxia-container.tb-login", el=>window.getComputedStyle(el).display != 'none');
if (isShowSlider) {
// 获取滑块iframe
const frame = await page.frames().find(frame => !!~frame.url().search("login.taobao.com//newlogin/account/check.do/"))
// 获取iframe中的滑块
const verifyBlock = await frame.$('#nc_1_n1z');
if (verifyBlock) {
const box = await verifyBlock.boundingBox(); //boundingBox获取滑块的位置
const initialX = Math.floor(box.x + box.width / 2);
const initialY = Math.floor(box.y + box.height / 2);
for (let i = 0; i < 4; i++) {
await page.waitForTimeout(1000)
move(page, initialX, initialY, 310) //自定义的move方法,310可设置随机数,(大于滑动条-滑动框)就好
await page.waitForTimeout(1000)
const errEl = await frame.$('#nocaptcha > div > span');
if (errEl) {
//出错, 将错误重置
console.log("登录失败")
await frame.click('#nocaptcha > div > span > a')
await frame.waitForSelector('#nc_1_n1z')
} else {
console.log("登录成功")
let slideEl = await frame.$('#nocaptcha > div')
if (!slideEl) {
//即没有错误, 也没有滑块
break
}
}
}
}
}
await page.click('#login-form > div.fm-btn > button', { delay: 50 }) //登录
}
main()
自信满满去跑这段代码,结果出现:
无论刷新几次,滑块都无法验证通过!!!只能卧槽感慨一下。再去看看是嘛问题,本来以为因为多次刷新,导致ip被识别出来为爬虫。但是在正常的浏览器打开淘宝登录页,使用滑块验证还是无法通过!!!再次使用卧槽感慨一下。没办法,只好再去百度,谷歌‘爸爸’那里求答案。发现是因为被淘宝反爬机制识别出了chrome webdriver,那我们只需要把无头浏览器伪装一下就可以了。
在前往页面前插入这段代码,把无头浏览器伪装一下。
await page.evaluateOnNewDocument(() => { //在每个新页面打开前执行以下脚本,否则会被识别出为chrome webdriver
const newProto = navigator.__proto__;
delete newProto.webdriver; //删除navigator.webdriver字段
navigator.__proto__ = newProto;
window.chrome = {}; //添加window.chrome字段,为增加真实性还需向内部填充一些值
window.chrome.app = {"InstallState":"hehe", "RunningState":"haha", "getDetails":"xixi", "getIsInstalled":"ohno"};
window.chrome.csi = function(){};
window.chrome.loadTimes = function(){};
window.chrome.runtime = function(){};
Object.defineProperty(navigator, 'userAgent', { //userAgent在无头模式下有headless字样,所以需覆写
get: () => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36",
});
Object.defineProperty(navigator, 'plugins', { //伪装真实的插件信息
get: () => [{"description": "Portable Document Format",
"filename": "internal-pdf-viewer",
"length": 1,
"name": "Chrome PDF Plugin"}]
});
Object.defineProperty(navigator, 'languages', { //添加语言
get: () => ["zh-CN", "zh", "en"],
});
const originalQuery = window.navigator.permissions.query; //notification伪装
window.navigator.permissions.query = (parameters) => (
parameters.name === 'notifications' ?
Promise.resolve({ state: Notification.permission }) :
originalQuery(parameters)
);
})
再试一下,Nice,不需要滑块验证就可以登录,完全模拟了人为操作。
借鉴地址:https://www.cnblogs.com/qjfoidnh/p/12779265.html
小技巧
爬虫页面时,需要选中需要部分的标签,中间有一个标签错误,就会出问题,获取不到信息,然后小编写出的:
#page>div:nth-child(2)>div:nth-child(3)>div>div>div>.login-content>.login-password>form
……
……
……
原来是我无知了,希望能帮到小伙伴们。
小总结
以上是小编使用Puppeteer初次爬虫的经历(兴趣使然)。以前只了解python爬虫,原来大Node也可以。因为是初次尝试,所以还有很多不足,如果有什么问题,可以在评论区讨论一下,有什么错误,欢迎各位大佬指出,小弟一定更正。希望可以帮到大家,爬虫虽好,不要过度哦!