1. 程式人生 > >node爬蟲(轉)

node爬蟲(轉)

優化 獨立 urn 4.3 rap agent request 線程 spi

我們先來看看今天的目標: mmjpg.com的美腿頻道下的圖片

一、實現步驟

使用superagent庫來獲取頁面
分析頁面結構,使用cheerio 獲取有效信息
保存圖片到本地
開擼
不斷優化

這兒我們用到了superagent cheerio fs-extra這三個庫

$ npm i superagent cheerio fs-extra --save

1.superagent 是nodejs裏一個非常方便的客戶端請求代理模塊
2.cheerio:為服務器特別定制的,快速、靈活、實施的jQuery核心實現
3.fs-extra: 豐富了fs模塊,同時支持async/await

二.請求URL獲取HTML

app.js 使用superagent發起請求並打印出頁面內容

const request = require(‘superagent‘)
const cheerio = require(‘cheerio‘)
const fs = require(‘fs-extra‘)

let url = ‘http://www.mmjpg.com/tag/meitui/‘

request.get(url + ‘1‘).then(function (res) {
    console.log(res.text)
})
// 你就可以看見HTML內容打印到了控制臺

三.分析頁面結構

使用cheerio來操作了,cheerio語法和jQuery基本一樣。

找到class為pic那個div下的列表中,現在我們就可以使用cheerio來獲取

async function getUrl() {
    const res = await request.get(url + 1)
    const $ = cheerio.load(res.text)
    $(‘.pic li‘).each(function(i, elem) {
        const href = $(this).find(‘a‘).attr(‘href‘)
        const title = $(this).find(‘.title‘).text()
        console.log(title, href)
    })
}

getUrl()

/*
$ node app.js
長腿美女白一晗巨胸絲襪寫真精美圖片 http://www.mmjpg.com/mm/1255
大美女尹菲開檔網襪寫真令人眼花繚亂 http://www.mmjpg.com/mm/1230
宅男女神豐滿誘人的胴體令人想入非非 http://www.mmjpg.com/mm/1164
性感美女浴室寫真高聳的酥胸誘惑十足 http://www.mmjpg.com/mm/1162
長相清純甜美的97年妹子苗條美腿圖片 http://www.mmjpg.com/mm/1157
麗質美女柔美修長美腿帶給你曼妙感受 http://www.mmjpg.com/mm/1153
容貌似楊冪的美女馨怡美腿極致誘惑圖 http://www.mmjpg.com/mm/1148
絲襪美腿誘惑!甜美女神楊晨晨私房套圖 http://www.mmjpg.com/mm/1130
性感美女劉鈺兒透視內衣私密照真撩人 http://www.mmjpg.com/mm/1127
膚白貌美的模特李晨晨十分惹人憐愛 http://www.mmjpg.com/mm/1126
萌妹林美惠子穿黑絲浴室私房寫真福利 http://www.mmjpg.com/mm/1124
美女趙小米修長雙腿絲襪寫真能玩幾年 http://www.mmjpg.com/mm/1111
微博高顏值美胸萌妹子少女映畫寫真集 http://www.mmjpg.com/mm/1107
性感妹子修長的雙腿真是讓人愛不釋目 http://www.mmjpg.com/mm/1106
翹臀妹子綺裏嘉飽滿胸部美的奪人心目 http://www.mmjpg.com/mm/1103
*/

四.分析URL地址

在很多時候我們都需要分析URL,就像點擊不同的頁碼觀察URL變化 http://www.mmjpg.com/home/2,我們可以很容易發現頁碼對應為URL最後的數字。查看mmjpg.com的美腿頻道我們可以發現它一共有10頁內容,我們就不寫代碼判斷頁數了直接寫死為10。當然了這兒你可以自己實現動態判斷總頁數,就當是留的小練習吧。

async function getUrl() {
    let linkArr = []
    for (let i = 1; i <= 30; i++) {
        const res = await request.get(url + i)
        const $ = cheerio.load(res.text)
        $(‘.pic li‘).each(function(i, elem) {
            let link = $(this).find(‘a‘).attr(‘href‘)
            linkArr.push(link)
        })
    }
    console.log(linkArr);
    return linkArr;
}

  

五.獲取圖片地址

async function getPic(url) {
  const res = await request.get(url)
  const $ = cheerio.load(res.text)
  // 以圖集名稱來分目錄
  const dir = $(‘.article h2‘).text()
  console.log(`創建${title}文件夾`)
  await fs.mkdir(path.join(__dirname, ‘/mm‘, title))
  const pageCount = parseInt($(‘#page .ch.all‘).prev().text())
  for (let i = 1; i <= pageCount; i++) {
    let pageUrl = url + ‘/‘ + i
    const data = await request.get(pageUrl)
    const _$ = cheerio.load(data.text)
    // 獲取圖片的真實地址
    const imgUrl = _$(‘#content img‘).attr(‘src‘)
    download(dir, imgUrl) // TODO
  }
}

六.保存圖片到本地

現在我們就來實現下載保存圖片的方法,這兒我們使用了stream(流) 來保存圖片

function download(dir, imgUrl) {
  console.log(`正在下載${imgUrl}`)
  const filename = imgUrl.split(‘/‘).pop()  
  const req = request.get(imgUrl)
    .set({ ‘Referer‘: ‘http://www.mmjpg.com‘ }) // mmjpg.com根據Referer來限制訪問
  req.pipe(fs.createWriteStream(path.join(__dirname, ‘mm‘, dir, filename)))
}
ok,現在我們就來把之前寫的各個功能的函數連起來

async function init(){
  let urls = await getUrl()
  for (let url of urls) {
    await getPic(url)
  }
}

init()

 

代碼:

const request = require(‘superagent‘)
const cheerio = require(‘cheerio‘)
const fs = require(‘fs-extra‘)
const path = require(‘path‘)

let url = "http://www.u-cpc.com/product/list.html";

// http://www.u-cpc.com/Product/List.html?page=3&cid=0&bid=0

// request.get(url).then(function(res){
//   console.log(res.text);
// })

// async function getUrl(){
//     const res = await request.get(url);
//     const $ = cheerio.load(res.text);
//     $(".product_ul li").each(function(i, elem){
//         const href = $(this).find("img").attr("data-original")
//         const title = $(this).find(".productlist_title").text();
//         console.log("標題是: " + title)
//         console.log("地址是: " + href)
//     })
// }
// getUrl();

/**
 * 獲取圖集的URL
 */
async function getUrl(){
    let linkArr = [];
    for(let i = 0; i <= 10; i++){
      const res = await request.get(url);
      const $ = cheerio.load(res.text);

      $(".product_ul li").each(function(i, elem){
          const href = $(this).find("img").attr("data-original")
          const title = $(this).find(".productlist_title").text();
          linkArr.push(href)
      })
    }
}
async function getPic(url) {
  const res = await request.get(url)
  const $ = cheerio.load(res.text)
  // 以圖集名稱來分目錄  
  const dir = $(‘.curr‘).text()
  console.log(`創建${dir}文件夾`)
  await fs.mkdir(path.join(__dirname, ‘/images‘, dir))
  for(let i = 1; i <= 10; i++){
    let pageUrl = url + ‘?page=‘ + i + ‘&cid=0&bid=0‘;
    const data = await request.get(pageUrl)
    const _$ = cheerio.load(data.text)
    _$(".product_ul li").each(function(i, elem){
      const imgUrl = $(this).find("img").attr("data-original");
      download(dir, imgUrl)
    })
  }
}

// 下載圖片
function download(dir, imgUrl) {
  console.log(`正在下載${imgUrl}`)
  const filename = imgUrl.split(‘/‘).pop()
  const req = request.get(imgUrl)
      .set({
          ‘Referer‘: ‘http://www.u-cpc.com/product/list.html‘
      })
  req.pipe(fs.createWriteStream(path.join(__dirname, ‘images‘, dir, filename)))
}

async function init() {
  getUrl();
  getPic(url)
}
// init();
download();
function download() {
  const url2 = "https://codeload.github.com/cheeriojs/cheerio/zip/master"
  const filename = url2.split(‘/‘).pop() + ".zip"
  const req = request.get(url2)
  req.pipe(fs.createWriteStream(path.join(__dirname, ‘images‘, filename)))
}

七:註意並發的,畢竟爬取頻率會有限制

問: err:Error: connect ETIMEDOUT 博主做爬蟲的時候有沒有遇到報這個錯的,我按你的代碼寫爬我們的網站,好多頁面都報這個錯誤

答: 並發爬取的數量太高 或者爬的太快。你爬的網站有做爬蟲保護限制。把並發量調低 把 延遲調大 就可以了。


PHP, Python, Node.js 哪個比較適合寫爬蟲?
1.PHP對多線程、異步支持較差,不建議采用。PHP 4.3.0以後引入的PHP Command Line特性,實現了讓PHP脫離Web服務器,和Phthon一樣獨立運行。因此用來寫爬蟲也是非常方便的。
2.NodeJS:對一些垂直網站爬取倒可以,但由於分布式爬取、消息通訊等支持較弱,根據自己情況判斷。
3.Python:強烈建議,對以上問題都有較好支持。尤其是Scrapy框架值得作為第一選擇, 專門用來做爬蟲的一個框架。優點諸多:支持xpath;基於twisted,性能不錯;有較好的調試工具;
4.C、C++雖然性能不錯,但不推薦,尤其是考慮到成本等諸多因素;

 

參考: https://github.com/ogilhinn/mm-spider

node爬蟲(轉)