介紹
爬蟲就是自動化瀏覽網(wǎng)站程序判哥,收集我們所需要的數(shù)據(jù)信息,不需要人為頻繁的執(zhí)行一些操作挺身。
什么是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只能爬取服務(wù)端渲染的頁面翻诉,而且只能是靜態(tài)頁面。而Puppeteer是模擬一個瀏覽器剑令,請求網(wǎng)站數(shù)據(jù)信息拄查,并能夠進行任何模擬的操作(點擊、滑動等),并且支持跳轉(zhuǎn)頁面碍脏,動態(tài)的獲取頁面內(nèi)的數(shù)據(jù)。就是模擬人瀏覽網(wǎng)站獲取數(shù)據(jù)役拴。
官方介紹: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, // 使無頭瀏覽器可見髓考,便于開發(fā)過程當(dāng)中觀察
executablePath: chromePaths.chrome, //可執(zhí)行文件的路勁,默認是使用它自帶的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)') // 等待爬取內(nèi)容加載完成
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()
接下來看看我們打印出來的爬取到的數(shù)據(jù)- 爬蟲解決登錄問題
做過爬蟲的小伙伴應(yīng)該都知道奶是,很多電商網(wǎng)站都會做反爬,分類商品頁秆麸,詳情頁及汉,訂單頁等需要我們登錄之后才可以瀏覽坷随,在登錄頁會做一系列檢測判斷是否為爬蟲。我們試著正常去登錄缸匪。
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, // 使無頭瀏覽器可見类溢,便于開發(fā)過程當(dāng)中觀察
executablePath: chromePaths.chrome, //可執(zhí)行文件的路勁露懒,默認是使用它自帶的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可設(shè)置隨機數(shù)坎弯,(大于滑動條-滑動框)就好
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()
自信滿滿去跑這段代碼,結(jié)果出現(xiàn):
無論刷新幾次,滑塊都無法驗證通過@省L吠!只能臥槽感慨一下劫乱。再去看看是嘛問題锥涕,本來以為因為多次刷新层坠,導(dǎo)致ip被識別出來為爬蟲。但是在正常的瀏覽器打開淘寶登錄頁破花,使用滑塊驗證還是無法通過W俊!舰绘!再次使用臥槽感慨一下。沒辦法叉橱,只好再去百度者蠕,谷歌‘爸爸’那里求答案。發(fā)現(xiàn)是因為被淘寶反爬機制識別出了chrome webdriver粪小,那我們只需要把無頭瀏覽器偽裝一下就可以了抡句。
在前往頁面前插入這段代碼,把無頭瀏覽器偽裝一下逞壁。
await page.evaluateOnNewDocument(() => { //在每個新頁面打開前執(zhí)行以下腳本锐锣,否則會被識別出為chrome webdriver
const newProto = navigator.__proto__;
delete newProto.webdriver; //刪除navigator.webdriver字段
navigator.__proto__ = newProto;
window.chrome = {}; //添加window.chrome字段雕憔,為增加真實性還需向內(nèi)部填充一些值
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
小技巧
爬蟲頁面時拜马,需要選中需要部分的標(biāo)簽俩莽,中間有一個標(biāo)簽錯誤,就會出問題取刃,獲取不到信息,然后小編寫出的:
#page>div:nth-child(2)>div:nth-child(3)>div>div>div>.login-content>.login-password>form
……
……
……
原來是我無知了却音,希望能幫到小伙伴們。
小總結(jié)
以上是小編使用Puppeteer初次爬蟲的經(jīng)歷(興趣使然)系瓢。以前只了解python爬蟲夷陋,原來大Node也可以。因為是初次嘗試清蚀,所以還有很多不足爹谭,如果有什么問題榛搔,可以在評論區(qū)討論一下践惑,有什么錯誤,歡迎各位大佬指出凉袱,小弟一定更正侦铜。希望可以幫到大家,爬蟲雖好涤躲,不要過度哦贡未!