node.js突破nginx防盜鏈機(jī)制,下載圖片案例分析 原創(chuàng)
問題
今天項目需求要求采集幾個網(wǎng)站的信息,包括一些區(qū)塊鏈統(tǒng)計圖表之類的信息。
筆者使用的是node.js+axios庫發(fā)送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,"文件已下載成功");
})運(yùn)行代碼,圖示文件下載成功!
然而當(dāng)筆者打開圖片一看,就傻眼了~圖片顯示損壞,再看大小,只有304字節(jié)~
目測應(yīng)該是圖片保存了一些錯誤信息,于是用editplus以文本形式打開該圖片,果然看到了錯誤信息~
解決方法
百度了一下,確定是圖片nginx服務(wù)器Referer防盜鏈設(shè)置,于是繼續(xù)百度,找到了問題的關(guān)鍵~
谷歌瀏覽器打開網(wǎng)址,在控制臺上看到了這段Referer信息:
對方的網(wǎng)站在Referer設(shè)置的就是他的網(wǎng)址,于是改進(jìn)代碼,在headers中加入Referer參數(shù)"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,"文件已下載成功");
})再次運(yùn)行代碼,圖片文件下載成功,打開顯示一切正常!
后記
筆者又測試了另一種實現(xiàn)方法,即使用playwright調(diào)用瀏覽器打開頁面,再使用await page.locator('selector路徑').screenshot({ path: 'image圖片保存路徑'}); 將圖片網(wǎng)頁截圖保存下載。
對比了一番,發(fā)現(xiàn)使用playwright截圖的方法需要在遍歷圖片元素的時候根據(jù)當(dāng)前元素逆向獲取parentNode節(jié)點以及遍歷childNodes節(jié)點,算法相對比較復(fù)雜!而且screenshot函數(shù)截圖的效果也會比原圖略顯模糊,因此推薦使用axios傳遞Referer參數(shù)的方法獲取原圖。
PS:方法二的調(diào)試過程中寫了一段逆向遍歷selector的函數(shù),提供給大家參考,如有不足之處,歡迎指正~
/**
* 獲取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++;
}
}
}相關(guān)文章
node.js實現(xiàn)端口轉(zhuǎn)發(fā)
這篇文章主要為大家詳細(xì)介紹了node.js實現(xiàn)端口轉(zhuǎn)發(fā)的關(guān)鍵代碼,感興趣的小伙伴們可以參考一下2016-04-04
簡單聊一聊Node.js參數(shù)max-old-space-size
簡單的說Node.js就是運(yùn)行在服務(wù)端的JavaScript,下面這篇文章主要給大家介紹了關(guān)于Node.js參數(shù)max-old-space-size的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01
使用node-canvas在服務(wù)端渲染echarts圖表解析
這篇文章主要介紹了使用node-canvas在服務(wù)端渲染echarts圖表解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10
node.js調(diào)用Chrome瀏覽器打開鏈接地址的方法
其實在Node.JS中打開瀏覽器網(wǎng)址非常簡單,但還是有必要整理下分享給有需要的朋友們,這篇文章主要給大家介紹了node.js如何調(diào)用Chrome瀏覽器打開鏈接地址的方法,文中介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起看看吧。2017-05-05
實戰(zhàn)node靜態(tài)文件服務(wù)器的示例代碼
本篇文章主要介紹了實戰(zhàn)node靜態(tài)文件服務(wù)器的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-03-03

