亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

實例:使用puppeteer headless方式抓取JS網

發布時間:2020-03-12 01:11:43 來源:網絡 閱讀:5120 作者:caiyongji 欄目:移動開發

puppeteer

google chrome團隊出品的puppeteer 是依賴nodejs和chromium的自動化測試庫,它的最大優點就是可以處理網頁中的動態內容,如JavaScript,能夠更好的模擬用戶。
有些網站的反爬蟲手段是將部分內容隱藏于某些javascript/ajax請求中,致使直接獲取a標簽的方式不奏效。甚至有些網站會設置隱藏元素“陷阱”,對用戶不可見,腳本觸發則認為是機器。這種情況下,puppeteer的優勢就凸顯出來了。
它可實現如下功能:

  1. 生成頁面的屏幕截圖和PDF。
  2. 抓取SPA并生成預先呈現的內容(即“×××”)。
  3. 自動表單提交,UI測試,鍵盤輸入等。
  4. 創建一個最新的自動化測試環境。使用最新的JavaScript和瀏覽器功能,直接在最新版本的Chrome中運行測試。
  5. 捕獲跟蹤您網站的時間線,以幫助診斷性能問題。

開源地址:[https://github.com/GoogleChrome/puppeteer/][1]

安裝
npm i puppeteer

注意先安裝nodejs, 并在nodejs文件根目錄下執行(npm文件同級)。
安裝過程中會下載chromium,大約120M。

用兩天(大約10小時)摸索,繞過了相當多的異步的坑,筆者對puppeteer和nodejs有了一定的掌握。
一張長圖,抓取blog文章列表:
實例:使用puppeteer headless方式抓取JS網

抓取blog文章

以csdn blog為例,文章內容需要點擊“閱讀全文”來獲取,這就導致只能讀取dom的腳本失效。

/**
* load blog.csdn.net article to local files
**/
const puppeteer = require('puppeteer');
//emulate iphone
const userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1';
const workPath = './contents';
const fs = require("fs");
if (!fs.existsSync(workPath)) {
        fs.mkdirSync(workPath)
}
//base url
const rootUrl = 'https://blog.csdn.net/';
//max wait milliseconds
const maxWait = 100;
//max loop scroll times
const makLoop = 10;
(async () => {
    let url;
    let countUrl=0;
    const browser = await puppeteer.launch({headless: false});//set headless: true will hide chromium UI
    const page = await browser.newPage();
    await page.setUserAgent(userAgent);
    await page.setViewport({width:414, height:736});
    await page.setRequestInterception(true);
    //filter to block images
    page.on('request', request => {
    if (request.resourceType() === 'image')
      request.abort();
    else
      request.continue();
    });
    await page.goto(rootUrl);

    for(let i= 0; i<makLoop;i++){
        try{
            await page.evaluate(()=>window.scrollTo(0, document.body.scrollHeight));
            await page.waitForNavigation({timeout:maxWait,waitUntil: ['networkidle0']});
        }catch(err){
            console.log('scroll to bottom and then wait '+maxWait+'ms.');
        }
    }
    await page.screenshot({path: workPath+'/screenshot.png',fullPage: true, quality :100, type :'jpeg'});
    //#feedlist_id li[data-type="blog"] a
    const sel = '#feedlist_id li[data-type="blog"] h3 a';
    const hrefs = await page.evaluate((sel) => {
        let elements = Array.from(document.querySelectorAll(sel));
        let links = elements.map(element => {
            return element.href
        })
        return links;
    }, sel);
    console.log('total links: '+hrefs.length);
    process();
  async function process(){
    if(countUrl<hrefs.length){
        url = hrefs[countUrl];
        countUrl++;
    }else{
        browser.close();
        return;
    }
    console.log('processing url: '+url);
    try{
        const tab = await browser.newPage();
        await tab.setUserAgent(userAgent);
        await tab.setViewport({width:414, height:736});
        await tab.setRequestInterception(true);
        //filter to block images
        tab.on('request', request => {
        if (request.resourceType() === 'image')
          request.abort();
        else
          request.continue();
        });
        await tab.goto(url);
        //execute tap request
        try{
            await tab.tap('.read_more_btn');
        }catch(err){
            console.log('there\'s none read more button. No need to TAP');
        }
        let title = await tab.evaluate(() => document.querySelector('#article .article_title').innerText);
        let contents = await tab.evaluate(() => document.querySelector('#article .article_content').innerText);
        contents = 'TITLE: '+title+'\nURL: '+url+'\nCONTENTS: \n'+contents;
        const fs = require("fs");
        fs.writeFileSync(workPath+'/'+tab.url().substring(tab.url().lastIndexOf('/'),tab.url().length)+'.txt',contents);
        console.log(title + " has been downloaded to local.");
        await tab.close();
    }catch(err){
        console.log('url: '+tab.url()+' \n'+err.toString());
    }finally{
        process();
    }

  }
})();

執行過程

錄屏可以在我公眾號查看,下邊是截圖:

實例:使用puppeteer headless方式抓取JS網

執行結果

文章內容列表:

實例:使用puppeteer headless方式抓取JS網

文章內容:

實例:使用puppeteer headless方式抓取JS網

結束語

以前就想過既然nodejs是使用JavaScript腳本語言,那么它肯定能處理網頁的JavaScript內容,但并沒有發現合適的/高效率的庫。直到發現puppeteer,才下定決心試水。
話說回來,nodejs的異步真的是很頭疼的一件事,這上百行代碼我竟然折騰了10個小時。
大家可拓展下代碼中process()方法,使用async.eachSeries,我使用的遞歸方式并不是最優解。
事實上,逐一處理并不高效,原本我寫了一個異步的關閉browser方法:

let tryCloseBrowser = setInterval(function(){
        console.log("check if any process running...")
        if(countDown<=0){
          clearInterval(tryCloseBrowser);
          console.log("none process running, close.")
          browser.close();
        }
    },3000);

按照這個思路,代碼的最初版本是同時打開多個tab頁,效率很高,但容錯率很低,大家可以試著自己寫一下。

題外話

看過我的文章的人都知道,我寫文章更強調處理問題的方式/方法,給大家一些思維上的建議。
對于nodejs和puppeteer我是完全陌生的(當然,我知道他們適合做什么,僅此而已)。如果大家還記得《10倍速程序員》里提到的按需記憶的理念,那么你就會理解我刻意的去系統的學習新技術。
我說說我接觸puppeteer到完成我需要功能的所有思維邏輯:

  1. 了解puppeteer功能/特性,結合目的判斷是否滿足要求。
  2. 快速實現getStart中的所有demo
  3. 二次判斷puppeteer的特性,從設計者角度出發,推測puppeteer的架構。
  4. 驗證架構。
  5. 通讀api,了解puppeteer細節。
  6. 搜索puppeteer前置學習內容(以及前置學習內容所依賴的前置學習內容)。整理學習內容,回到1。
  7. 設計/分析/調試/……

2018年5月9日02點13分

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

怀仁县| 大化| 连山| 泸西县| 武陟县| 高要市| 辽中县| 岚皋县| 增城市| 曲松县| 长汀县| 壤塘县| 晋中市| 东台市| 鄢陵县| 赤水市| 平果县| 舟曲县| 苗栗县| 通化市| 苏尼特左旗| 罗田县| 安福县| 益阳市| 克东县| 石家庄市| 太仓市| 兴化市| 长岭县| 平顶山市| 博爱县| 油尖旺区| 攀枝花市| 临桂县| 临西县| 高陵县| 宁波市| 商南县| 读书| 洛宁县| 北碚区|