node.js突破nginx防盗链机制,下载图片案例分析 原创

问题

今天项目需求要求采集几个网站的信息,包括一些区块链统计图表之类的信息。

笔者使用的是node.js+axios库发送get请求来获取在图片,下载到本地。测试代码如下:

import fs from 'fs';
import path from 'path';
import http from 'http';
import https from 'https';

const __dirname = path.resolve();
let filePath = path.join(__dirname,'/imgtmp/');
async function downloadfile(url,filename,callback){
    try {
        let ext = path.extname(url);

        console.log('下载的文件名:',filename)
        let mod = null;//http、https 别名
        if(url.indexOf('https://')!==-1){
            mod = https;
        }else{
            mod = http;
        }
        const req = mod.get(url, {
            headers:{
                "Content-Type": "application/x-www-form-urlencoded"
              }
        },(res)=>{
            let writePath = '';
            writePath = filePath + '/' + filename;
            const file = fs.createWriteStream(writePath)
            res.pipe (file)
            file.on ("error", (error) => {
                console.log (`There was an error writing the file. Details: `,error)
                return false;
            })
            file.on ("close", () => {
                callback (filename)
            })

            file.on ('finish', () => {
                file.close ()
                console.log ("Completely downloaded.")
            })
        })

        req.on ("error", (error) => {
            console.log (`Error downloading file. Details: $ {error}`)
        })
    } catch (error) {
        console.log('图片下载失败!',error);
    }

}

let url = 'https://xx.xxxx.com/d/file/zxgg/a2cffb8166f07c0232eca49f8c9cc242.jpg';//图片url
let filename = path.basename(url);
await downloadfile(url,filename,()=>{
    console.log(filename,"文件已下载成功");
})

运行代码,图示文件下载成功!

然而当笔者打开图片一看,就傻眼了~图片显示损坏,再看大小,只有304字节~

目测应该是图片保存了一些错误信息,于是用editplus以文本形式打开该图片,果然看到了错误信息~

解决方法

百度了一下,确定是图片nginx服务器Referer防盗链设置,于是继续百度,找到了问题的关键~

谷歌浏览器打开网址,在控制台上看到了这段Referer信息:

对方的网站在Referer设置的就是他的网址,于是改进代码,在headers中加入Referer参数"referer":'https://www.xxxx.com/'

import fs from 'fs';
import path from 'path';
import http from 'http';
import https from 'https';

const __dirname = path.resolve();
let filePath = path.join(__dirname,'/imgtmp/');
async function downloadfile(url,filename,callback){
    try {
        let ext = path.extname(url);

        console.log('下载的文件名:',filename)
        let mod = null;//http、https 别名
        if(url.indexOf('https://')!==-1){
            mod = https;
        }else{
            mod = http;
        }
        const req = mod.get(url, {
            headers:{
                "Content-Type": "application/x-www-form-urlencoded",
                "referer":'https://www.xxxx.com/'
              }
        },(res)=>{
            let writePath = '';
            writePath = filePath + '/' + filename;
            const file = fs.createWriteStream(writePath)
            res.pipe (file)
            file.on ("error", (error) => {
                console.log (`There was an error writing the file. Details: `,error)
                return false;
            })
            file.on ("close", () => {
                callback (filename)
            })

            file.on ('finish', () => {
                file.close ()
                console.log ("Completely downloaded.")
            })
        })

        req.on ("error", (error) => {
            console.log (`Error downloading file. Details: $ {error}`)
        })
    } catch (error) {
        console.log('图片下载失败!',error);
    }

}

let url = 'https://xx.xxxx.com/d/file/zxgg/a2cffb8166f07c0232eca49f8c9cc242.jpg';//图片url
let filename = path.basename(url);
await downloadfile(url,filename,()=>{
    console.log(filename,"文件已下载成功");
})

再次运行代码,图片文件下载成功,打开显示一切正常!

后记

笔者又测试了另一种实现方法,即使用playwright调用浏览器打开页面,再使用await page.locator('selector路径').screenshot({ path: 'image图片保存路径'}); 将图片网页截图保存下载。

对比了一番,发现使用playwright截图的方法需要在遍历图片元素的时候根据当前元素逆向获取parentNode节点以及遍历childNodes节点,算法相对比较复杂!而且screenshot函数截图的效果也会比原图略显模糊,因此推荐使用axios传递Referer参数的方法获取原图。

PS:方法二的调试过程中写了一段逆向遍历selector的函数,提供给大家参考,如有不足之处,欢迎指正~

/**
 * 获取selector
*/
function getSelectorPath(element) {
    if (!!element.id !== false) {
      return '#' + element.id;
    }
    if (element === document.body && !!element) {
      return element.tagName.toLowerCase();
    }

    let ix = 0;
    const siblings = element.parentNode?.childNodes;
    for (let i = 0; i < siblings?.length; i++) {
      const sibling = siblings[i];
      if (sibling.innerHTML === element.innerHTML && !!element.parentNode) {
        return `${getSelectorPath(element.parentNode)} > ${element.tagName.toLowerCase()}:nth-child(${ix + 1})`;
      }
      if (sibling.nodeType === 1) {
        ix++;
      }
    }
}
(0)

相关推荐

  • node+axios实现下载外网文件到本地

    目录 引言 初始化项目 安装axios 实现逻辑 执行 引言 作为一个web前端开发,对axios肯定不陌生,但是在前端开发中,一般是使用axios来请求后端接口,获取数据.而使用node+axios下载网络文件到本地磁盘可能很少接触,搜索了很多相关的博客文章,讲解的好像都不够清晰明了,所以本文就记录一下实践方法. 初始化项目 npm init -y 安装axios npm i -S axios 实现逻辑 根目录下新建app.js // app.js const axios = require(

  • nodejs实现生成文件并在前端下载

    目录 nodejs生成文件并在前端下载 前端 后端 nodejs下载文件问题 第一种方式:使用原生的http模块 第二种方式:使用Express+Axios下载文件 总结 nodejs生成文件并在前端下载 最近遇到一个小需求,前端要下载一个json文件,内容是对应数据的json对象. 看网上写的都太复杂了,只是下载一个小文件,只需要用到res.end()就够了. 前端 在a标签上加上download属性就可以点击下载文件了,download可以赋值,值为下载之后的文件名.也可以留空,用原有的文件

  • Node.js实现下载文件的两种实用方式

    目录 第一种方式:使用原生的http模块 第二种方式:使用Express+Axios下载文件 总结 设置响应头 返回数据流 第一种方式:使用原生的http模块 我们仅需要用到fs和http两个node.js的原生模块,不需要安装第三方模块,就可以实现文件的下载.代码如下: var fs = require('fs'); var http = require("http"); var server = http.createServer(); server.on("reques

  • nodejs连接ftp上传下载实现方法详解【附:踩坑记录】

    依赖 //ftp 模块是目前找到的还不错的,对于ftp的基本功能都支持 npm install ftp 连接ftp const ftp = require('ftp');//连接FTP const client = new ftp(); client.on('ready',()=>{ console.log('ftp client is ready'); }); client.connect({ host : '***.***.***.***', port : '****', user : '*

  • 配置Nginx的防盗链的操作方法

    实验环境 •一台最小化安装的CentOS 7.3虚拟机 •配置:1核心/512MB •nginx版本1.12.2 一.配置盗链网站 1.启动一台nginx虚拟机,配置两个网站 vim /etc/nginx/conf.d/vhosts.conf 添加以下内容 server { listen 80; server_name site1.test.com; root /var/wwwroot/site1; index index.html; location / { } } server { list

  • Nginx防盗链的配置方法

    处于服务性能的考虑,我们通常把HTML静态资源按照不同类型划分存放在多台服务上. 如果拓扑图: 超文本传输协议中的Referer作用 Referer:null    表示请求者直接访问 Referer:blocked  一般为防火墙设备添加的 Referer:URL      表示URL中的主机告诉请求者的间接访问 图中jpg.good.com显然是一台专门用户存放图片的服务器,而www.good.com是一台WEB服务器,从域名可以看出必然是一家公司,条件: 1.只允许访问www.good.c

  • Nginx图片防盗链配置实例

    做运维的朋友经常会有一些烦恼,比如网站总是被人抄袭,比如网站总是被人引用上面的图片,虽然一张图两张图,并不耗费很多流量,但一旦引用的人多了,这个还是比较废流量的. 防盗链就是禁止其他网站引用自己网站资源而做的一系列设置,优点就不需要说了,绝多数就是防止资源浪费,特别是有宽带.流量限制的空间如果不做一些 限制可能就光引用自己网站图片.视频等等资源可能会消耗很大一部分流量.本文就简单的说一下在nginx服务器上如何做防盗链设置. nginx防盗链代码 第1步:下载nginx网站配置文件. 有些网友可

  • Nginx服务器下防盗链的方法介绍

    修改 /usr/local/nginx/conf/nginx.conf 这个配置文件. 找到 location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { expires 30d; }[/code] 修改成: location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { valid_referers none blocked *.jannn.com jannn.com; if($invalid_referer) { rewrite ^/ h

  • Node.js实现批量下载图片简单操作示例

    本文实例讲述了Node.js实现批量下载图片简单操作.分享给大家供大家参考,具体如下: 使用Node.js批量下载图片 首先要获取到图片链接: const img = [ "http://yw-yx.oss-cn-hangzhou.aliyuncs.com/ywwl-jylesson/2019/08/52218400506629423.jpg", "http://yw-yx.oss-cn-hangzhou.aliyuncs.com/ywwl-jylesson/2019/08/

  • nginx利用referer指令实现防盗链配置

    实现图片防盗链: location ~* \.(gif|jpg|png|webp)$ { valid_referers none blocked domain.com *.domain.com server_names ~\.google\. ~\.baidu\.; if ($invalid_referer) { return 403; #rewrite ^/ http://www.domain.com/403.jpg; } root /opt/www/image; } 以上所有来至domain

  • nginx配置防盗链的三种实现方式总结

    目录 什么是资源盗链 一.引导案例 二.Nginx防盗链实现原理 三.Nginx防盗链具体实现 实现方式一 实现方式二 实现方式三 总结 什么是资源盗链 资源盗链是指内容不在自己服务器上,而通过技术手段,绕过别人的限制,将别人的内容,比如热门的图片放到自己页面上,展示给用户,以此来盗取别人网站的流量,即蹭流量. 简而言之就是用别人的东西成就自己的网站 如下,分别在网上找的两个图片,可以直接在浏览器中打开这2个链接 一.引导案例 接下来,利用上面的这两个图片链接,我们在nginx的资源目录下,创建

随机推荐