第一彈:puppeteer爬蟲小demo —— 網易雲音樂

aloha66發表於2018-05-27

上一篇文章主要介紹了一些puppeteer爬蟲api,本文是實戰篇第一彈,爬取網易雲音樂某個頁皮膚塊

出發點

  1. 首先我不是要爬歌詞,我只是想結合上一篇文章寫一個練手小demo,內容隨意。
  2. 這個demo最好可以涉及多媒體儲存。
  3. 儘可能簡單,不涉及資料庫操作、刪除檔案操作。
  4. 限定網站是傳統非同步獲取分頁資料,沒有分頁引數在位址列url上。

解決點

  1. 圖片下載

    之前寫專案的時候習慣用axios,本文也是使用axios。axios(url, {responseType: "stream"})這樣初始化axios就可以下載圖片了。

  2. 圖片位置

    新建一個image資料夾來儲存下載的圖片 fs.mkdirSync("image");

  3. 分析網站結構

    第一彈:puppeteer爬蟲小demo —— 網易雲音樂

    • 網易雲音樂的主體由一個iframe包裹,iframe有name和id,用iframe.name()Array.find可以匹配單個Frame物件。
    • 每一行都是由一個tr組成
    • 獲取新資料可以模擬點選下一頁實現

下面直接放程式碼

const fs = require("fs");
const puppeteer = require("puppeteer");
const axios = require("axios");
console.time("ssr"); //開始計時
if (!fs.existsSync("image")) {
//新建image資料夾
  fs.mkdirSync("image");
}

(async () => {
  const browser = await puppeteer.launch({
    headless: false,
    devtools: true
  });
  const page = (await browser.pages())[0];
  await page.setViewport({
    width: 1280,
    height: 800
  });
  //為了簡化,我直接跳到想爬的地址了。當然你也可以開啟網易雲一步一步操作,注意規律就好了。
  await page.goto(
    "http://music.163.com/#/search/m/?id=9605&s=%E5%8D%AB%E5%85%B0&type=1000"
  );
  //Frame物件有一個獲取name的方法
  let iframe = await page.frames().find(f => f.name() === "contentFrame");
  //這裡我只獲取前五頁的資料,當然你也可以獲取下一頁的前一個元素的innerText來確認總數
  for (let i = 1; i <= 5; i++) {
    fs.mkdirSync(`image/${i}`); //頁碼作為資料夾名
    // await iframe.waitFor(".m-table td .s-fc3");
    // 等待分頁資料。本來想通過上面的方式來等待的,但是貌似是因為上一個頁面".m-table td .s-fc3"的節點已經載入
    //按下一頁的時候這個選擇器的節點還在,導致這個方式失效?請大佬解惑
    await iframe.waitFor(2000) //ps:少於2s,有時會出現圖片重複,原因是dom仍未更新導致
    const te = await iframe.$$eval(".m-table tbody tr", list => {
    //請注意已經進入瀏覽器環境了
      return new Promise(resolve => {
        let arr = [];
        list.map((item, index) => {
          let temp = {};
          const str = item.querySelector(".w7 img").src;
          temp.img = str.slice(0, str.lastIndexOf("?")); //獲取最大尺寸的圖片
          temp.title = item.querySelector(".txt").innerText;
          temp.author = item.querySelector(".w4 a.s-fc3").title;
          temp.count = item.querySelector(".w6.s-fc4").innerText;
          //因為這是瀏覽器的環境,我在node依賴的axios是無法在這裡下載檔案的,只能先儲存資料再回到node中下載
          // axios(temp.img,{responseType:'stream'}).then(response => response.data.pipe(fs.createWriteStream(`./image/${temp.author.jpg}`)))
          arr.push(temp);
        });
        resolve(arr);
      });
    });
    //回到node的環境,可以放心下載了。
    te.map(async (item, index) => {
      const result = await axios(item.img, {
        responseType: "stream"
      });
      result.data.pipe(fs.createWriteStream(`./image/${i}/${item.author}.jpg`)); //管道真好使
    });
    // 下載完圖片進入下一頁,如果有頁碼直接用goto跳轉
    iframe.click('.u-page a:last-child')
  }

  console.timeEnd("ssr"); //計時結束
  })();
複製程式碼

本文內容不多,把傳統非同步分頁的爬取流程以程式碼形式寫了一遍。小弟不才,第一次接觸爬蟲,並不瞭解其他工具是怎樣爬取,如有錯希望大家指正。

另外想問個問題,為什麼<div tabindex="0"></div>這樣寫,點選div的時候:focus會生效。

起因:在一個div上,藉助f12除錯勾選:focus:focus會生效,用滑鼠點選就沒效果。But在div加上tabindex="0"後,滑鼠點選:focus生效


小弟不才,17年軟體工程畢業生,熟悉vue寫過兩個公司專案。目前已離職,座標廣州,求大佬們收留。

相關文章