1. 程式人生 > 程式設計 >Node爬蟲應用的實踐

Node爬蟲應用的實踐

Welcome to nodecrawler ?

     
 
     
 
     
 

node 爬蟲筆記

? Homepage

一、什麼是爬蟲?

爬蟲簡而言之就是爬去網頁上的資訊。而網頁結構就是一個樹形結構,就像一個蜘蛛網一樣。而爬蟲程式就像一個蜘蛛,在這個蜘蛛網上去收取我們感興趣的資訊。

二、開始寫爬蟲前需要確定的兩個東西。

  1. Where to crawler? (要爬那的資訊?)。
  2. What to crawler? (你要爬什麼資訊?)。

工藝利其事必先利器

剛開始找了幾個 node 爬蟲庫,但是效果不是很理想。不過皇天不負有心人,不過最終還是讓我找到了一個:Apify

.

三、使用 Apify 來開始我的爬蟲之旅

1. 首先新建一個工程然後安裝 apify 依賴。

npm i apify -S
複製程式碼

接下來要確定一下爬取那個網站的資訊(以豆瓣電影 Top 250 為例)

2.現在我們已經確定了要爬取的 url(movie.douban.com/top250),現在開始編寫程式碼。

// 引入apify
  const Apify = require('apify');
複製程式碼

3.apify 提供了一個動態佇列(requestQueue)來管理我們要爬取的 url,我們可以使用它來管理我們所有要爬取的 url。

const Apify = require('apify'
); Apify.main(async ()=>{ // 首先建立一個請求佇列 const requestQueue = await Apify.openRequestQueue(); // 將要爬取的url新增到佇列當中 await requestQueue.addRequest('https://movie.douban.com/top250'); }) 複製程式碼

5.已經有了請求佇列,接下來要做的是What to crawler。需要一個方法去解析請求的網頁內容。

定義一個函式來解析網頁內容,該函式之後會傳入apify爬蟲的一個例項當中

async function
handlePageFunction({ request,$ }) { // 是不是對$很熟悉,其實就是node裡的jquery // 先簡單列印下網頁的title. const title = $('title').text(); console.log(`網頁的title:${title}`); } 複製程式碼

6.最後,建立一個CheerioCrawler 爬蟲例項,並將requestQueue,handlePageFunction作為引數傳入。然後啟動爬蟲

const crawler = new Apify.CheerioCrawler({
        requestQueue,handlePageFunction
  })

  // 啟動爬蟲
  await crawler.run();
複製程式碼

我們把程式碼做一下整合,然後啟動爬蟲。

const Apify = require('apify');


  Apify.main(async () => {
      // 建立請求佇列
      const requestQueue = await Apify.openRequestQueue();
      // 將要爬取的url新增到佇列當中
      await requestQueue.addRequest({ url: 'https://movie.douban.com/top250' });

      const handlePageFunction = async ({ request,$ }) => {
          // 是不是對$很熟悉,其實就是node裡的jquery
          // 先簡單列印下網頁的title.
          const title = $('title').text();
          console.log(`網頁的title:${title}`);
      }

      //建立一個CheerioCrawler,將requestQueue,handlePageFunction作為引數傳入
      const crawler = new Apify.CheerioCrawler({
          requestQueue,handlePageFunction
      })
      // 啟動爬蟲
      await crawler.run();
  })
複製程式碼

執行程式碼,頁面的標題成功被爬取

到這裡,就已經實現了一個簡易的爬蟲,但是還沒有實現我們的需求(爬取完整的top250)。我們需要動態的去新增url,才能爬取到完整的250部電影。

8.獲取所有要爬取的頁面

初始url是首頁,我們需要獲取所有頁碼的頁面,通過解析頁面,我們可以通過以apify提供的一個動態新增url到佇列的方法來將我們想要爬去的頁面新增到請求佇列當中。

const {
  utils: { enqueueLinks },} = Apify;
複製程式碼
await enqueueLinks({
            $,requestQueue,selector: '.next > a',// 跳轉到下一頁的a標籤
            baseUrl: request.loadedUrl,//根據baseUrl會將a中的href補全
      });
複製程式碼

9. 接下來需要修改一下handlePageFunction,來解析需要的電影資訊。

/**
 * 解析網頁,獲取電影資訊
 */
function parseMovie($) {
    const movieDoms = $('.grid_view .item');
    const movies = [];
    movieDoms.each((index,item) => {
        const movie = {
            rank: $(item).find('.pic em').text(),// 排名
            name: $(item).find('.title').text(),// 電影名
            score: $(item).find('.rating_num').text(),// 評分
            sketch: $(item).find('.inq').text() // 主題
        }
        movies.push(movie)
    })
    return movies
}
複製程式碼

10. 再把程式碼整合到一起,執行看看結果

const Apify = require('apify');
const {
    utils: { enqueueLinks },} = Apify;
Apify.main(async () => {
    // 首先建立一個請求佇列
    const requestQueue = await Apify.openRequestQueue();
    await requestQueue.addRequest({ url: 'https://movie.douban.com/top250' });
    const crawler = new Apify.CheerioCrawler({
        requestQueue,handlePageFunction
    })
    async function handlePageFunction({ request,$ }) {
        await enqueueLinks({
            $,//根據baseUrl會將a中的href補全
        });
        const movies = parseMovie($);
        movies.forEach((item,i) => {
            console.log(`${item.rank}|${item.name}|${item.score}|${item.sketch}`)
        })
    }
    // 啟動爬蟲
    await crawler.run();
})





/**
 * 解析網頁,獲取電影資訊
 */
function parseMovie($) {
    const movieDoms = $('.grid_view .item');
    const movies = [];
    movieDoms.each((index,// 評分
            sketch: $(item).find('.inq').text() // 主題
        }
        movies.push(movie)
    })
    return movies
}
複製程式碼

⭐️執行下看看結果

現在的執行結果已經滿足我們的需求了,但是會不會覺得上面的程式碼有些麻煩,得找到連結、再轉換、再新增到請求佇列。可不可以給出一個url規則,然後程式自動幫我新增到佇列中呢?

五、本地資料持久化

這裡我們使用sqlite來做本地資料持久化,因為它是一個輕量級的資料庫、而且是不需要服務端的。

  1. 安裝sqlite3依賴
npm i sqlite3 -S
複製程式碼
  1. 初始化資料庫,建立movies表
const sqlite3 = require('sqlite3').verbose();
function initDB(){
    let db = new sqlite3.Database('./db/crawler.db',(err) => {
        if (err) {
          return console.error(err.message,'啊哈');
        }
        console.log('Connected to the crawler database.');
      });
      createTable(db);
      return db;
}

function createTable(db){
    const sql = `CREATE TABLE  IF NOT EXISTS movies(
        rank TEXT,name TEXT,TEXT TEXT,sketch TEXT
     );`
     db.run(sql,[],(err)=>{
         if(err){
             return console.log(err)
         }
         console.log('表建立成功')
     })
}

複製程式碼

3.插入資料

function insertData(db,movie = {}) {
    db.serialize(function () {
        db.run(`INSERT INTO movies(rank,name,score,sketch) VALUES(?,?,?)`,[movie.rank,movie.name,movie.score,movie.sketch],function (err) {
            if (err) {
                return console.log(err.message);
            }
            // get the last insert id
            console.log(`A row has been inserted with rowid ${this.lastID}`);
        });
    })
}
複製程式碼

結尾

到這裡,一個簡單的爬蟲程式算是寫完了,但是這裡還少了ip代理以及請求源偽裝。後面再加上

程式碼地址:github.com/hp0844182/n…