你沒有碰到過要將網頁轉換爲PDF文件的需求? 圖片呢?
如何保存一個網頁的快照? 截圖? 頁面過長怎辦,系統自帶的截圖工具無法滾屏
海外網頁被牆,經過在香港服部署一PDF生成服務能夠免除無謂的瀏覽其它垃圾/非法網址。
公司管理層須要在公司集成辦公系統上查看其它系統的資料,好比hr系統上員工簡歷,營銷系統上的某報表...html
需求仍是很多的。前端
我的前後使用過 wkhtmltopdf , phantomjs ,puppeteer。
wkhtmltopdf 使用起來最簡單,功能比較單一,看名字就知道了,在windows下直接就是一個exe,可在本身的項目中fork/startProcess 開一個新進程,並傳入網頁和保存的路徑地址,經過 wkhtmltopdf -h 能夠查看各參數和說明。若是你要生成的頁面是集團內部服務,那麼使用它是最方便的。node
phantomjs ,一樣經過名字就知道它和js 結合的很是緊密。它使用webkit內核,同pupp,用戶在可在頁面內注入js,像在瀏覽器上操做頁面和元素同樣操做它,但它已中止更新了。linux
puppeteer 是google 提供的 node 庫用來操做chrome,有些人稱之爲無頭瀏覽器,在linux上使用會配套下載chromium。功能上徹底能夠做爲phantomjs 替代品,正由於它操做的實際是chrome瀏覽器,對於分析頁面數據,模擬和破解前端邏輯很是給力。web
除此以外,其實還有不少工具,網上能搜出一大把,這裏就很少說了。chrome
使用puppeteer實現windows
'use strict' const Service = require("egg").Service; const puppeteer = require('puppeteer'); class pupp extends Service { async Create(tourl, savePath,ops) { ops = ops || {}; //console.log("pupp.js ", tourl, savePath,ops); const browser = await puppeteer.launch({ args : [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-gpu', '--disable-dev-shm-usage', '--no-first-run', '--no-zygote', //'--single-process' ], ignoreHTTPSErrors:true }); const page = await browser.newPage(); // console.log("before go to:"); await page.setUserAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"); /* await page.setExtraHTTPHeaders({ "accept-language":"zh-CN,zh;q=0.9,en;q=0.8", "cookie":"csrfToken=V04e-JSpCtM_BEr_VH2-73N9", "cache-control":"max-age=0" });*/ if(ops.cookies) { console.log("setcookies return :",await page.setCookie(...ops.cookies)); await page.waitFor(200); } await page.goto(tourl, { waitUntil : 'networkidle2', timeout : 60000 }); if(ops.navigation) await page.waitForNavigation({waitUntil:'networkidle2'});//沒有這個,weibo 相關頁面會是空白 //await page.screenshot({path: 'screenshot.png'}); //否則會有href 顯示在頁面 page.emulateMedia('screen'); let scrollEnable = true; let scrollStep = 1000; //每次滾動的步長 let scrollCount = 0; while (scrollEnable) { if (scrollCount++ > 5) //最多容許滾動5次 { console.error("too many scroll, jumpout ", tourl); scrollEnable = false; break; } scrollEnable = await page.evaluate((scrollStep) => { let scrollTop = document.scrollingElement.scrollTop; document.scrollingElement.scrollTop = scrollTop + scrollStep; return document.body.clientHeight > scrollTop + scrollStep ? true : false }, scrollStep); await page.waitFor(200) } page.waitFor(2000); await page.pdf({ path : savePath, width : "1280px", height : "1960px", printBackground:true }); await browser.close(); } /** 將cookie string 轉換爲cookie object 的數組 */ cvtCookie(ck_line) { let arr = fs.readFileSync("./old_cookies.txt").toString().split(";"); let objcks = arr.map(aline=>{ let ind = aline.indexOf("="); return {name:aline.substr(0,ind),value:aline.substr(ind+1)}; }); } } //延時 function waitMs(ms) { if (typeof ms != "number") return Promise.resolve(0); return new Promise((resolve, rej) => { setTimeout(() => { resolve(1); }, ms); }); } module.exports = pupp;
以上是生成pdf文件的核心代碼,使用的是egg框架,不熟悉並不影響閱讀。有以下幾點可留意一下數組
1:有些註釋掉的代碼沒有去掉,有些代碼也能夠註釋,取決於你真實的測試狀況,許多網頁的渲染方式不同,有些還混合着多種js異步渲染。瀏覽器
2:文中的一些具體參數都是通過反覆屢次驗證效果後添加或調整過的,官網上並不會有這些內容,有時一個默認參數就會讓效果迥異。服務器
3:代碼中有段cookie設置,這是由於不少網頁用戶不登錄不能看,因此須要前置的用戶登錄,並獲取登錄成功後的cookie,進而在此步使用。須要留意模擬登錄後的cookie(甚至手動在瀏覽器登錄後保存cookie)使用的瀏覽器請求頭應儘可能保持一致,以避免服務端將它區分爲兩個不一樣用戶。
4:文中有個滾動頁面的邏輯,由於有些頁面僅顯示一屏,當用戶滾動鼠標到文末時纔會繼續加載,就像一些手機app,最多往下拉五次,拉太多沒多大意義還浪費時間。
puppeteer用做生成pdf有些大材小用了,用做分析和操做頁面元素獲取數據都十分方便的。我的認爲它不太適合大批量的爬取數據,效率較低。
另外,要獲取別人的頁面就繞不開須要登錄和驗證碼,若是不是過於頻繁的請求,如上文所述,直接用戶手動在瀏覽器輸入賬密,而後再將瀏覽器的cookie保存下來,交由上面代碼處理就夠了。但若是是將服務部署在服務器,這種辦法就失去了做用。筆者就用過一個網上下載的新浪微博登錄庫,並使用一種很「挫」的方式填充驗證碼,工做良好,有興趣的同窗能夠留言向我瞭解。
下一篇,將講述使用 selinum 獲取股票數據