node 爬虫:送你一大波美腿图

作者: 刘星
日期: 2018年2月08日

决定送大家一套美图。但是授之以鱼不如授之以渔,我们就来使用 node 实现个小爬虫去爬取各种美女

来吧,我们先来看看今天的目标: mmjpg.com 的美腿频道下的图片

在开始之前先来科普科普

美腿是形容女性美丽、性感、修长的腿形美。美腿可以分为白璧无瑕的大腿美、晶莹剔透的小腿美、细微的美足、健康明朗的腿形美。所谓腿健美,是指腿部的线条美。腿的长短与肥瘦是决定腿部美丑的两大因素。

一、实现步骤

  1. 确定目标页面
  2. 使用 superagent 库来获取页面
  3. 分析页面结构,使用 cheerio 获取有效信息
  4. 保存图片到本地
  5. 开撸
  6. 不断优化

二、开始编写爬取妹子图的爬虫

下载这个小项目需要使用的库

npm i superagent cheerio fs-extra --save

这儿我们用到了superagent cheerio fs-extra这三个库

  • superagent 是 nodejs 里一个非常方便的客户端请求代理模块
  • cheerio:为服务器特别定制的,快速、灵活、实施的 jQuery 核心实现
  • fs-extra: 丰富了 fs 模块,同时支持 async/await

2.1 请求 URL 获取 HTML

使用 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内容打印到了控制台

2.2 分析页面结构

现在我们就需要分析页面结构,然后使用 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()

/* console
$ node app.js
大美女尹菲开档网袜写真令人眼花缭乱 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
*/

2.3 分析 URL 地址

在很多时候我们都需要分析 URL,就像点击不同的页码观察 URL 变化 http://www.mmjpg.com/tag/meitui/2,我们可以很容易发现页码对应为 URL 最后的数字。查看 mmjpg.com 的美腿频道我们可以发现它一共有 10 页内容,我们就不写代码判断页数了直接写死为 10。当然了这儿你可以自己实现动态判断总页数,就当是留的小练习吧。

async function getUrl() {
  let linkArr = []
  for (let i = 1; i <= 10; 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)
    })
  }
  return linkArr
}

2.4 获取图片地址

现在我们已经能获取到图集的 URL 了。在上一步我们获取图集 URL 的时候是把页码写死了的,这是因为那个页码不是动态的,然而每个图集的图片页数是不一样的,这儿我们就需要动态判断了。进入图集后,切换图片的页码 URL 也会跟着变,现在这个 URL 就是每张图片页面的 URL。我们只需要获取最后一个页面的页码, 从 1 开始历遍,和我们上面获取的 URL 拼接在一起就是每张图片的页面地址啦!

获取到单个图片 URL 后,我们可以通过图片的src属性去拿到真实的图片地址,然后实现下载保存

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
  }
}

2.5 保存图片到本地

现在我们就来实现下载保存图片的方法,这儿我们使用了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()

运行该文件,你就可以看终端打印出入下信息,你的文件夹中也多了好多美女图哟!开不开心?嗨不嗨皮?

前方高能

一大波美女来袭

好吧~不删掉通过不了

源码:https://github.com/ogilhinn/mm-spider

到此这个小爬虫就算写完了,但是这只是一个很简陋的爬虫,还有很多需要改进的地方

你还可以加入很多东西让它更健壮,如:

  • 使用多个 userAgent
  • 不断更换代理 ip
  • 降低爬虫的速度,加个sleep()
  • ……

如何让它更健壮、如何应对反爬虫策略这些留着以后再讲吧

三、参考链接

  • 源码:https://github.com/liuxing/mm-spider
  • superagent: http://visionmedia.github.io/superagent/
  • cheerio:https://github.com/cheeriojs/cheerio
  • fs-extra:https://github.com/jprichardson/node-fs-extra
文档信息

版权声明:署名-非商业性使用-禁止演绎 4.0 国际(CC BY-NC-ND 4.0)

原文链接:https://www.liuxing.io/blog/node-spider/

发表日期:2018年02月08日


相关文章

Node 命令行工具开发【看段子】

Node 命令行工具开发【看段子】 你有没有上班想看笑话却又怕领导发现的经历?现在我们就用几十行代码写一个命令行看笑话段子的小程序,从此无需担心领导的视察。这篇文章和上一篇差不多都是命令行小工具开发,不过本篇更偏向于小爬虫的开发

2017年3月18日

Node.js 使用 Nodemailer 发送邮件

电子邮件是—种用电子手段提供信息交换的通信方式,是互联网应用最广的服务。通过网络的电子邮件系统,用户可以以非常低廉的价格(不管发送到哪里,都只需负担网费)、非常快速的方式(几秒钟之内可以发送到世界上任何指定的目的地),与世界上任何一个角落的网络用户联系。 在很多项目中,我们都会遇到邮件注册,邮件反馈等需求。在 node 中收发电子邮件也非常简单,因为强大的社区有各种各样的包可以供我么直接使用。Nodemailer包就可以帮助我们快速实现发送邮件的功能。

2017年12月02日

Koa 快速入门教程(一)

Koa 是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的 Web 框架,采用了async和await的方式执行异步操作。

2017年11月18日

JSON 入门教程

JSON 的全称是”JavaScript Object Notation”,意思是 JavaScript 对象表示法,它是一种基于文本,独立于语言的轻量级数据交换格式,类似 XML 但比 XML 更小、更快,更易解析

2017年4月05日

最近更新

Curl 使用指南

Curl 是一个常用的命令行数据传输工具, 可以方便的从命令行创建网络请求

2021年5月04日

JavaScript 中的分号

JavaScript 代码到底加不加分号。本文带你了解 JavaScript 的分号自动插入机制,以及哪些情况必须加分号

2021年5月02日