问题:

n站上的本子,虽然每一本都有下载按钮,但是实测通过其提供的种子文件,下载速度并不理想,甚至有时候会卡在一个地方下不动。可是本子毕竟不同于其他东西,它在实质上只是许多图片的合集。用户打开每一个带有大图的网页时,大图都能顺利加载,那么我们能不能自己写一个脚本,来模拟用户对于每一个网页的点击呢?

一开始我的想法非常简单,就是通过在 Chrome 的开发者工具中运行一段简单的 JavaScript,搜寻每张略缩图的链接,然后再通过某种方式把图片下载下来。当我在一开始就遇到了一个问题:怎么用 JavaScript 来把网页上的资源自动下载到电脑中?一开始我用的是这样的方法:

var link = document.createElement('a');
link.href = 'images.jpg';
link.download = 'Download.jpg';
document.body.appendChild(link);
link.click();
复制代码

但马上我就发现这样会使浏览器弹出一个下载窗口,这可不是我想要的。经过一番搜索之后,我认为只有通过一个正经的爬虫脚本才能把网页上的图片批量下载到本地。说到爬虫,很多人可能立刻就想到了 Python,但是由于我并不是要做什么大项目,更不用爬取多大的数据量,加上对于 Node.js 解析网页的方式相对来说更为熟悉(Cheerio 用起来和 jQuery 很像),于是就选择了使用 Node.js。随后我发现了这个东西,在阅读并使用之后决定以它作为蓝本,来实现我们所需要的脚本。

爬虫这个东西就像变色龙,总是需要适应网站的变化而变化。链接中所提供的 Node.js 脚本虽然好用,但是它毕竟只针对那一个网站而已,换一个就不奏效了。针对n站,我们需要对症下药。通过观察我发现每个本子的首页网址中都带有一个ID,它在略缩图的href中也有出现,然而它并不是通往每张大图的ID,通往大图的本子ID藏在<img>src中。

<div class="thumb-container"><a class="gallerythumb" href="/g/网址中的ID/1/" rel="nofollow"><img is="lazyload-image" class="" width="200" height="288" data-src="https://t.nhentai.net/galleries/通往大图的ID/1t.jpg" src="https://t.nhentai.net/galleries/通往大图的ID/1t.jpg"><noscript><img src="https://t.nhentai.net/galleries/通往大图的ID/1t.jpg" width="200" height="288" /></noscript></a>
</div>
复制代码

我并不确定为何n站要为同一个本子赋与两个不同的ID,但无疑我们需要能够拿到大图的那个ID。这个时候我犯了一个错误,由于每张大图的地址都非常有规律(例如:https://i.nhentai.net/galleries/通往大图的ID/1.jpg),我一开始选择在获取总页面数和大图ID后自动生成所有大图的网址。这在我的第一次测试中没有出现问题,但在第二次测试时无法下载除前两张外的其他图片。排查后发现我默认所有的图片都是 jpg 格式,然而事实并非如此。于是我更改了代码结构,获取每一个大图的网页,进而再获取每一张大图。这无疑降低了效率,却是不得已而为之。之后又加入了从命令行直接传参的功能。

脚本改好了,然而我并不敢将成品放到 GitHub ?,那么就直接放在这篇文章下面吧!(反正一共也没有多少行)

// 'use strict'const request = require('superagent')
const cheerio = require('cheerio')
const fs = require('fs-extra')
const path = require('path')let dir = ''/*** 生成[n, m]随机数* @param {number} min * @param {number} max */
function random(min, max) {let range = max - minlet rand = Math.random()let num = min + Math.round(rand * range)return num
}/*** 获取图集的URL*/
async function getImageUrl(url) {let linkArr = []const res = await request.get(url)let $ = cheerio.load(res.text)dir = $('#info h2').text()dir = dir.split('/').join(' ')dir = path.join(__dirname, '/mm', dir)const exists = await fs.pathExists(dir)if (exists) {await fs.remove(dir)}await fs.mkdir(dir)const pageID = url.split('/')[4]const pageNum = parseInt($('#tags + div').text().split(' ')[0])for (let i = 1; i <= pageNum; i++) {const imagePage = await request.get('https://nhentai.net/g/'+pageID+'/'+i)$ = cheerio.load(imagePage.text)linkArr.push($('#image-container').find('img').attr('src'))}return linkArr
}// 下载图片
function download(dir, imgUrl) {console.log(`正在下载 ${imgUrl}`)const filename = imgUrl.split('/').pop()const req = request.get(imgUrl).set({ 'Referer': 'https://nhentai.net' })req.pipe(fs.createWriteStream(path.join(dir, filename)))
}// sleep函数
function sleep(time) {return new Promise(function (resolve, reject) {setTimeout(function () {resolve()}, time)})
};async function init(url) {let urls = await getImageUrl(url)for (let url of urls) {download(dir, url)await sleep(random(1000, 5000))}
}process.argv.slice(2).forEach(function (val) {init(val);
});
复制代码

用法示例:

node n-site.js https://nhentai.net/g/xxxxx/(即本子首页网址)
复制代码
node n-site.js https://nhentai.net/g/xxxxx/ https://nhentai.net/g/xxxxx/(可以传多个网址作为参数)
复制代码

以上。

此致敬礼

下载n站本子的 node.js 脚本相关推荐

  1. Node.js脚本项目合集(一):Node.js+FFmpeg实现批量从B站导出离线缓存视频到mp4格式,mp4转mp3,实现听歌自由

    Node.js脚本项目合集(一):Node.js+FFmpeg实现批量从B站导出离线缓存视频到mp4格式,mp4转mp3,实现听歌自由 前言 一.准备工作以及介绍 1.什么是FFmpeg 2.FFmp ...

  2. 用 node.js 脚本替代复杂的 npm script

    用 node.js 脚本替代复杂的 npm script Node.js 丰富的生态能赋予我们更强的能力,对于前端工程师来说,使用 Node.js 来编写复杂的 npm script 具有明显的 2 ...

  3. 树莓派开机运行node.js脚本的方法

    http://gyzx.swjtu.edu.cn/icsites/devzone/node/352 一.配置Raspberry Pi无线网络. 插上无线网卡 sudo nano /etc/wpa_su ...

  4. java调用nodejs程序,从java里面调用node.js脚本

    How can I call a node.js inside java and save the console.log values in a String variable? 解决方案 It i ...

  5. 提高工作效率的 Node.js 自动化脚本

    在我前端工作岗位中,总少不了各种繁琐的文件操作,所以很早就想通过写一些 Node.js 脚本来解放自己双手了.虽然 Python 或者 PHP 这样的语言写脚本也很方便,但是我个人觉得还是通过使用 J ...

  6. 2023年Node.js全网详细下载安装的最新教程

    文章目录 1. 文章引言 2. 下载安装 3. 检查是否安装成功 4. 补充说明 1. 文章引言 今天准备写下载和安装vue.js的博文,但安装vue.js的前提是要安装node和npm. 我们在安装 ...

  7. 【全文】狼叔:如何正确的学习Node.js

    说明 2017-12-14 我发了一篇文章<没用过Node.js,就别瞎逼逼>是因为有人在知乎上黑Node.js.那篇文章的反响还是相当不错的,甚至连著名的hax贺老都很认同,下班时读那篇 ...

  8. 狼叔:如何正确的学习Node.js

    1. [知乎Live]狼叔:如何正确的学习Node.js 预览地址 i5ting.github.io/How-to-lear- Live 简介 你好,我是 i5ting ,江湖人称「狼叔」,目前是阿里 ...

  9. 【全文】狼叔:如何正确的学习Node.js 1

    说明 2017-12-14 我发了一篇文章<没用过Node.js,就别瞎逼逼>是因为有人在知乎上黑Node.js.那篇文章的反响还是相当不错的,甚至连著名的hax贺老都很认同,下班时读那篇 ...

最新文章

  1. Java-Maven(四):Eclipse集成Maven环境配置
  2. spring单元测试
  3. scrapy-splash抓取动态数据例子八
  4. MATLAB做离散傅里叶变换DFT
  5. webpack + react 使用 eslint
  6. 在此iphone上尚未受信任_电脑显示服务器上的安全数据库没有此工作站信任关系的解决方法...
  7. 求两个整数的最大公约数
  8. 自定义异常禁用异常堆栈_如何在Mac上禁用或自定义自动更正
  9. java 找不到构造函数_JAVA找不到符号构造函数
  10. Spring中使用XML方式导入Spring配置文件,Boot中使用全注解导入Spring配置
  11. html表单提交数据保存到mysql中_php – Canonical:如何将HTML表单数据保存到MySQL数据库中...
  12. Python整理PEER所下载的地震波源数据——提取地震波至txt+生成地震波反应谱
  13. JavaScript基础学习总结(一) 适合小白
  14. 计算周数的方式 - 现在是今年的第几周?
  15. JSP内置对象Session——setAttribute/getAttibute/removeAttribute
  16. K-mean 算法代码演示
  17. 高效的使用DOM操作
  18. Trojan-Qt5一个纯净安装是必须的
  19. 卫星对时系统(北斗卫星对时系统)京准电子使用手册
  20. 南航计算机学院考博难么,考博难不难?考博难不是考研难?

热门文章

  1. Win10物理机的VMnet8和VMnet1黄色感叹号
  2. 现货交易常见的投资模式
  3. 基于回溯搜索优化算法的WSN覆盖优化
  4. 诺贝尔奖今起揭晓 4位华裔科学家成热门
  5. 高翔slam14讲的部分的实例代码: eigen部分(一)
  6. 场内场外交易成本_开放式基金的场内交易和场外交易有什么区别?
  7. 战痘实录,又同样烦恼的可以看看(转)
  8. Docker 搭建容器合集
  9. windows消息处理过程及消息钩子
  10. VT-x/AMD-V 硬件加速在您的系统中不可用。您的 64-位虚拟机将无法检测到 64-位处理器,从而无法启动。