使用Puppeteer爬取微信文章的實(shí)現(xiàn)
一朋友在群里問有沒有什么辦法能夠一次性把這個(gè)鏈接 里的文章保存下來(lái)。點(diǎn)開可以看到,其實(shí)就是一個(gè)文章合集。所以需求就是,把這個(gè)文檔中的鏈接里的文章挨個(gè)保存下來(lái)。保存形式可以有很多種,可以是圖片,也可以是網(wǎng)頁(yè)。這里因?yàn)槭褂?puppeteer 庫(kù)的原因,故選擇保存格式格式為PDF。
需求解構(gòu)
完成整個(gè)動(dòng)作,主要分為這兩個(gè)部分。獲取文檔內(nèi)所有文章的鏈接;把每個(gè)鏈接里的內(nèi)容保存為PDF文件。
對(duì)于獲取鏈接,有兩條路,一是使用request模塊請(qǐng)求該網(wǎng)址獲取文檔;二是把網(wǎng)頁(yè)保存到本地使用fs模塊獲取文檔內(nèi)容。拿到文檔也就是整個(gè)HTML文檔后,一開始沒想到什么好法子來(lái)拿到全部文章鏈接。如果直接在網(wǎng)頁(yè)那就好辦,直接DOM的 quertSelectorAll
API配合CSS選擇器就可以非常方便地拿到所有 a
鏈接中的 href
屬性。但這里是Node,是DOM外之地。又想到的是直接使用正則匹配,后來(lái)還是放棄了這個(gè)做法。在google搜了下才發(fā)現(xiàn)竟然忘了 cheerio
這個(gè)好東西。 cheerio
是一個(gè)專門為服務(wù)端設(shè)計(jì)的快速靈活而簡(jiǎn)潔得jQuery實(shí)現(xiàn)。
對(duì)于保存網(wǎng)頁(yè)內(nèi)容,我所知道的常規(guī)操作是保存為PDF文件,恰巧之前剛知道的 puppeteer
滿足這樣的需求。 puppeteer
是一個(gè)由 chrome devtools
團(tuán)隊(duì)維護(hù)的提供了控制chrome瀏覽器高級(jí)API的一個(gè)Node庫(kù)。除去爬取網(wǎng)頁(yè)內(nèi)容保存為PDF文件外,它還可以作為服務(wù)端渲染的一個(gè)方案以及實(shí)現(xiàn)自動(dòng)化測(cè)試的一個(gè)方案。
需求實(shí)現(xiàn)
獲取鏈接
先上這部分代碼
const getHref = function () { let file = fs.readFileSync('./index.html').toString() const $ = cheerio.load(file) let hrefs = $('#sam').find('a') for (e in hrefs) { if (hrefs[e].attribs && hrefs[e].attribs['href']) { hrefArr.push({ index: e, href: hrefs[e].attribs['href'] }) } } fs.writeFileSync('hrefJson.json', JSON.stringify(hrefArr)) }
因?yàn)楹竺娴拇a都依賴到讀取的文件,所以這里用的是readFileSync方法。如果沒有聲明返回內(nèi)容的格式,那默認(rèn)是Buffer格式。可以選擇填寫 utf8
格式,或者直接在該方法后面使用 toString
方法。
兩行代碼用cheerio拿到所有所有鏈接的DOM元素后,挨個(gè)將其處理為方便后面要用到的格式??紤]到可能存在a標(biāo)簽沒有href屬性的情況,這里還對(duì)其進(jìn)行了判斷,不過這也是后面調(diào)試程序時(shí)才發(fā)現(xiàn)的bug。
如果需要將所有的鏈接另外保存起來(lái),使用 writeFile
方法。
存為PDF
同樣,先上這部分代碼。
const saveToPdf = function () { async () => { const browser = await puppeteer.launch({ executablePath: './chrome-win/chrome.exe', }); // 鏈接計(jì)數(shù) let i = 0 async function getPage() { const page = await browser.newPage(); await page.goto(hrefArr[i]['href'], { waitUntil: 'domcontentloaded' }); // 網(wǎng)頁(yè)標(biāo)題 let pageTitle if (hrefArr[i]['href'].includes('weixin')) { pageTitle = await page.$eval('meta[property="og:title"]', el => el.content) } else { pageTitle = await page.$eval('title', el => el.innerHTML) } let title = pageTitle.trim() // 去掉斜桿 let titlea = title.replace(/\s*/g, "") // 去掉豎線 let titleb = titlea.replace(/\|/g, ""); await page.pdf({ path: `${i}${titleb}.pdf` }); i++ if (i < hrefArr.length) { getPage() } else { await browser.close(); } } getPage() } }
因?yàn)樾枰却齝hrome瀏覽器的打開,以及其他可能的異步請(qǐng)求。最外層使用了async 配合箭頭函數(shù)將真正的執(zhí)行代碼包住。
在用 npm 安裝 puppetter
時(shí),因?yàn)槟J(rèn)會(huì)下載chrome瀏覽器,而服務(wù)器在國(guó)外,一般都無(wú)法下載成功。當(dāng)然也有相應(yīng)的解決方案,這里我就不展開了。如果安裝 puppeteer
,可以參開 這篇文章 或者直接谷歌搜下。
在前一部分說(shuō)到,我們需要把不止一個(gè)鏈接里的內(nèi)容保存為PDF,所以使用了變量 i
來(lái)標(biāo)識(shí)每一次需要訪問的鏈接。
對(duì)于獲取網(wǎng)頁(yè)標(biāo)題,當(dāng)時(shí)確實(shí)費(fèi)了點(diǎn)時(shí)間才處理好拿到已有鏈接的網(wǎng)頁(yè)標(biāo)題。所以鏈接中主要有兩種網(wǎng)站的鏈接,一類是微信公眾號(hào)文章,另一類是新浪財(cái)新這種網(wǎng)站。微信文章里頭沒有像新浪這樣直接給出 title
內(nèi)容。
這個(gè)時(shí)候就要用到 page 類中的 $eval
方法, $eval
方法主要有兩個(gè)參數(shù),一是選擇器,二是在瀏覽器上下文中執(zhí)行的函數(shù)。$eval方法會(huì)頁(yè)面中運(yùn)行document.querySelector方法,并將其返回值傳遞給第二個(gè)參數(shù),也就是我們寫好的方法中。以獲取新浪網(wǎng)頁(yè)文章title為例, title
為傳入選擇器,我們需要的是其標(biāo)簽內(nèi)容。
pageTitle = await page.$eval('title', el => el.innerHTML)
在產(chǎn)生文件名的過程中,由于文件夾還是文件路徑的一部分。此時(shí)還需要考慮到windows文件路徑規(guī)范。但網(wǎng)頁(yè)中的標(biāo)題并不受此規(guī)范限制,由此產(chǎn)生矛盾。這個(gè)問題也是后面調(diào)試的時(shí)候才發(fā)現(xiàn),一開始寫代碼并沒有想到這個(gè)問題。即需要去除標(biāo)題中的斜杠豎桿還有空格等字符。
每獲取完一個(gè)鏈接的內(nèi)容后,就將鏈接位置標(biāo)識(shí) i
+ 1,知道所有鏈接內(nèi)容保存完畢,關(guān)閉打開的網(wǎng)頁(yè)。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python super( )函數(shù)用法總結(jié)
今天給大家?guī)?lái)的知識(shí)是關(guān)于Python的相關(guān)知識(shí),文章圍繞著super( )函數(shù)展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06Python漏洞驗(yàn)證程序Poc利用入門到實(shí)戰(zhàn)編寫
這篇文章主要為大家介紹了Python?Poc利用入門到實(shí)戰(zhàn)編寫實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-02-02Python學(xué)習(xí)筆記之While循環(huán)用法分析
這篇文章主要介紹了Python學(xué)習(xí)筆記之While循環(huán)用法,結(jié)合具體實(shí)例形式分析了while循環(huán)的原理、用法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2019-08-08python如何通過閉包實(shí)現(xiàn)計(jì)算器的功能
這篇文章主要介紹了python如何通過閉包實(shí)現(xiàn)計(jì)算器的功能,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02Django 權(quán)限管理(permissions)與用戶組(group)詳解
這篇文章主要介紹了Django 權(quán)限管理(permissions)與用戶組(group)詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11python深度學(xué)習(xí)TensorFlow神經(jīng)網(wǎng)絡(luò)模型的保存和讀取
這篇文章主要為大家介紹了python深度學(xué)習(xí)TensorFlow神經(jīng)網(wǎng)絡(luò)如何將訓(xùn)練得到的模型保存下來(lái)方便下次直接使用。為了讓訓(xùn)練結(jié)果可以復(fù)用,需要將訓(xùn)練好的神經(jīng)網(wǎng)絡(luò)模型持久化2021-11-11pip 安裝庫(kù)比較慢的解決方法(國(guó)內(nèi)鏡像)
對(duì)于Python開發(fā)用戶來(lái)講,PIP安裝軟件包是家常便飯。但國(guó)外的源下載速度實(shí)在太慢,浪費(fèi)時(shí)間。而且經(jīng)常出現(xiàn)下載后安裝出錯(cuò)問題,所以把PIP安裝源替換成國(guó)內(nèi)鏡像,可以大幅提升下載速度,還可以提高安裝成功率2019-10-10Python代碼庫(kù)之Tuple如何append添加元素問題
這篇文章主要介紹了Python代碼庫(kù)之Tuple如何append添加元素問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01