Node.js 种子下载器
Node.js 种子下载器
庆祝 2018 国庆,制作了一个 Node.js 的种子下载器。爬取页面,根据页面的链接,破解另外一个网站,下载种子文件。项目比较简单,爬取页面没有使用任何爬虫框架。项目源码
Node.js 的安装请看我的另外一篇文章,Node.js 的多版本安装。
项目初始化
新建一个文件夹 FBIWarning,在该文件夹下打开命令行 CMD 或者 git bash。运行 npm init -y,该文件夹会生成一个 package.json 文件。
安装依赖包
安装依赖包 cnpm install --save cheerio iconv-lite request socks5-http-client。每个依赖包的功能如下:
cheerio// 解析 DOMiconv-lite// 解决中文乱码的问题request// http 请求,图片和种子的下载socks5-http-client// socks 代理
爬取网页策略
网页之间,是靠链接联系在一起的,符合数据结构里面的图状结构。所以,对应有如下两种爬取策略。
- 爬取所有列表页面的链接后,再去爬取所有详情页面,对应图算法的广度优先遍历。
- 爬取一部分列表页面,就去爬取详情页面。然后再去爬取列表页面,爬取详情页面,循环进行,对应图算法的深度优先遍历。
因为是国外网站,网络可能随时断开,所以采用第二种策略比较好。同时,也能很快得到种子文件。为了防止重复爬取页面,可以将爬取页面的链接作为索引。
请求代理
网站是国外网站,需要使用梯子,否则不能爬取。代理传送门。socks5-http-client 配合 reqeust 使用,可以解决代理的问题。但是,该代理只支持 socks 代理, http(s) 代理暂不支持。
解决中文乱码的问题
目标网站的页面编码是 gbk ,而 request 依赖包的默认编码是 UTF-8,使用默认编码解码方式,会导致页面的中文变成乱码。所以得到返回数据前,去掉默认编码,就是设置编码为 encoding: null,然后使用 iconv-lite 使用 gbk 方式解码,这样就可以解决中文编码为乱码的问题,代码如下:
const request = require("request")
// 解析 dom
const cheerio = require("cheerio")
// 中文编码
const iconv = require("iconv-lite")
// 代理
const Agent = require("socks5-http-client/lib/Agent")
const COMMON_CONFIG = require("./config")
/**
* 请求页面
* @param {String} requestUrl 请求页面
*/
function requestPage(requestUrl) {
try {
return new Promise((resolve, reject) => {
if (!requestUrl) {
resolve(false)
}
request.get(
{
url: requestUrl,
agentClass: Agent,
agentOptions: {
socksPort: 13838, // 代理端口
socksHost: "127.0.0.1" // 代理 Host
},
headers: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"
},
// 去掉默认 utf-8 解码,否则解码会乱码
encoding: null
},
function(err, response, body) {
// 防止解析报错
try {
// 统一解决中文乱码的问题
let content = iconv.decode(body, "gbk")
let $ = cheerio.load(content)
resolve($, err, response, body, content)
} catch (error) {
resolve(null)
}
}
)
})
} catch (error) {
//如果连续发出多个请求,即使某个请求失败,也不影响后面的其他请求
Promise.resolve(null)
}
}
并发请求
分页请求有很多个,可以使用递归来一个一个请求,但是写法不太好看。所以,可以使用 ES7+ 里面的 async 函数,将同步过程变为异步过程。async 要配合 await 使用,就可以将同步过程变为异步过程。详细了解 async 请看阮一峰 ES async
async function innerRecursion() {
for (let i = 1; i <= 100; i++) {
let requestUrl = "http://www.baidu.com?page=" + i // 事例网站,非爬取网站
let result = await this.requestPage(url)
}
}
一个一个请求比较慢,可以使用 Promise.all 实现并发请求。当然,也可以使用 async 模块 提高下载的并发量,有需要的可以自己去了解。这个 async 模块并非上面的 async 函数。
function innerRecursion() {
let requestUrls = []
for (let i = 1; i <= 100; i++) {
let requestUrl = "http://www.baidu.com?page=" + i // 事例网站,非爬取网站
requestUrls.push(requestUrl)
}
let promises = requestUrls.map(url => this.requestPage(url))
Promise.all(promises)
.then(results => {
// results 是一个数组,对应上面每个请求的结果
})
.catch(error => {
// 捕获请求中可能发生的错误
console.log(error)
})
}
图片下载
图片的下载非常简单,代码如下:
/**
* 下载文件
* @param {String} url 请求链接
* @param {String} filePath 文件路径
*/
function downloadFile(url, filePath) {
// try...catch 防止一个请求出错,导致程序终止 种子的下载相同
try {
if (!url || !filePath) {
return false
}
request
.get({
url,
agentClass: Agent,
agentOptions: {
socksPort: 13838, // 代理端口
socksHost: "127.0.0.1" // 代理 Host
},
headers: {
headers: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"
}
}
})
.pipe(fs.createWriteStream(filePath))
} catch (error) {
console.log(error)
}
}
破解网站种子下载
解析详情页面,只能得到类似 http://www.jandown.com?ref=VENU794 的链接,需要破解该网站的种子下载。查看网站的种子下载方式,就是一个 post 请求,后端就会返回种子文件。刚开始的时候,不熟悉服务端的表单提交方式,导致文件一直得不到,后来详细查看了 request 的官文文档,发现是自己写错了。结合上面的图片下载,种子的下载方式自然就有了,代码如下:
/**
* 下载种子链接
* @param {String} childDir // 子目录
* @param {String} downloadUrl // 下载种子地址
*/
function downloadTorrent(childDir, downloadUrl) {
try {
// 解析出链接的 code 值
let code = querystring.parse(downloadUrl.split("?").pop()).ref
if (!code || !childDir) {
return false
}
// 发出 post 请求,然后接受文件即可
request
.post({
url: "http://www.jandown.com/fetch.php",
agentClass: Agent,
agentOptions: {
socksPort: 13838, // 代理端口
socksHost: "127.0.0.1" // 代理 Host
},
headers: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"
},
formData: {
code
}
})
.pipe(fs.createWriteStream(childDir + "/" + code + ".torrent"))
} catch (error) {
console.log(error)
}
}
面向对象
刚开始是使用面向过程的方式写的,后来发现代码太重复了,所以采用 OOP 改写了整个代码。详细了解 javaScript Class 请看阮一峰 ES class
总结
- 学习中文编码为乱码的解决方法
- 学习了
request的代理以及文件下载功能 - 破解种子网站的种子下载功能
- js 面向对象开发
- 爬虫并发量解决
感谢阅读!
Node.js 种子下载器的更多相关文章
- Node.js包管理器Yarn的入门介绍与安装
FAST, RELIABLE, AND SECURE DEPENDENCY MANAGEMENT. 就在昨天, Facebook 发布了新的 node.js 包管理器 Yarn 用以替代 npm .咱 ...
- Node.js包管理器:
Node.js包管理器: 当我们要把某个包作为工程运行的一部分时,通过本地模式获取,如果要在命令行下使用,则使用全局模式安装 使用全局模式安装的包并不能直接在JavaScript文件中用require ...
- node.js之调试器
node.js之调试器 1.在命令行窗口中,可以使用"node debug" 命令来启用调试器,代码如下: node debug<需要被执行的脚本文件名> 接下来根据一 ...
- Node.js的下载、安装、配置、Hello World、文档阅读
Node.js的下载.安装.配置.Hello World.文档阅读
- Folx种子下载器怎么管理下载任务
对于喜欢追剧的用户来说,同时下载好几部剧是司空见惯的事情.但有时候,有些剧比较好看或者热度比较高时,就会希望优先将其下载下来. 对于使用Folx种子下载器的用户来说,可以结合使用下载列表+最大活动数的 ...
- npm --- Node.js包管理器
目录 1. 安装Node.js 2. 运行npm 3. npm介绍 3.1 安装插件 3.2 更新插件 3.3 卸载插件 3.4 查看当前目录中的插件列表 4. 使用cnpm 4.1 安装 npm( ...
- Node.js 包管理器 NPM 讲解
包管理器又称软件包管理系统,它是在电脑中自动安装.配制.卸载和升级软件包的工具组合,在各种系统软件和应用软件的安装管理中均有广泛应用.对于我们业务开发也很受益,相同的东西不必重复去造轮子. 每个工具或 ...
- 9.Node.js 包管理器npm
npm 是 Node.js 官方提供的包管理工具, 用于 Node.js包的发布.传播.依赖控制 安装 express ==> 流行的基于Node.js的Web开发框架,可以快速地搭建一个完整 ...
- node.js服务器端下载、上传文件
使用request 下载文件: 安装依赖: npm i requestsourceUrl下载源,targetUrl保存路径 async function downLoadFile(sourceUrl, ...
随机推荐
- JAVA操作证书
一.生成证书工具keytool Java自带的工具keytool可以用来生成密钥证书,也可以查看或删除证书库里的证书.无论是windows还是Linux系统,这个工具都会出现在jdk安装目录的bin文 ...
- [转]Example Design - Using the AXI DMA in polled mode to transfer data to memory
Description Attached to this Answer Record is an Example Design for using the AXI DMA in polled mode ...
- Docker 踩坑记(failed to build: Get https://registry-1.docker.io/v2/microsoft/dotnet/manifests/2.1-sdk: unauthorized: incorrect username or password)
今天看了下.net core 示例项目eShopWebOnline. 无奈在使用docker的时候总是提示一下错误信息,大致信息是用户名密码错误.但是,明明桌面右下角Docker帐号处于登录状态. E ...
- PHP将图片转base64编码以及base64图片转换为图片并保存代码
图片转base64编码 /*图片转换为 base64格式编码*/ $img = 'uploads/01.png'; $base64_img = base64EncodeImage($img); ech ...
- js中的严格模式和非严格模式的比较
前言 es5的严格模式是采用具有限制性JavaScript变体的一种方式,从而使代码显示地脱离'懒散模式/非严格模式' 严格模式 严格模式通过抛出错误来消除一些原有静默错误 严格模式修复了一些导致Ja ...
- Debian+Django+uWsgi+nginx+mysql+celery
下载系统各种依赖 nano /etc/apt/sources.list 在Debian中使用apt-get安装软件包时经常会提示让你插入netinst的光盘: Media change: please ...
- vs2017更新出错:The entire Box execution exiting with result code: 0x0
在将vs2017 15.7.4更新至15.9.5出现“The entire Box execution exiting with result code: 0x0”错误,也就是文件解压下载开始安装后, ...
- java去除查询实体字段多值之间空格
String str = 需要去除的字段; str.replaceAll(",","");
- git commit时暂时忽略已提交的文件
当正在修改某文件A,此时需要commit,但是A没修改完暂时不能一起commit. 执行: git update-index --assume-unchanged A的路径 git暂时会忽略该文件的修 ...
- 利用Github免费搭建个人主页(转)
搭建过程涉及: Github注册 Github搭建博客 域名选购 绑定域名 更多 一. Github注册 在地址栏输入地址:http://github.com/join填写相关信息, 按步骤完成即可 ...