-
Notifications
You must be signed in to change notification settings - Fork 5
/
grab.js
151 lines (130 loc) · 4.96 KB
/
grab.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
* @Author: ShawnPhang
* @Date: 2023-09-30 21:58:50
* @Description: 网页抓取
* @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-10-31 09:35:25
*/
const puppeteer = require("puppeteer");
const fs = require("fs");
const path = require("path");
if (!process.argv[2]) {
console.error('--> Banner 未命名, 请正确运行命令, 例如: npm run grab xxx')
return
}
console.log('正在下载资源中...');
let saveFolder = "";
const today = new Date();
const year = today.getFullYear();
const month = ("0" + (today.getMonth() + 1)).slice(-2); // 月份从 0 开始计数,所以需要加 1,并且保证两位数格式
const day = ("0" + today.getDate()).slice(-2); // 保证两位数格式
const date = year + "-" + month + "-" + day
const folderPath = "./assets/" + date;
if (fs.existsSync(folderPath)) {
// 如果文件夹存在,则清空文件夹
fs.readdirSync(folderPath).forEach((file) => {
const filePath = path.join(folderPath, file);
fs.unlinkSync(filePath); // 删除文件
});
} else {
// 如果文件夹不存在,则创建文件夹
fs.mkdirSync(folderPath, { recursive: true });
}
saveFolder = folderPath;
const data = [];
(async () => {
const browser = await puppeteer.launch({
headless: "new",
args: ["--no-sandbox", "--disable-setuid-sandbox"],
});
const page = await browser.newPage();
page.setViewport({
width: 1650,
height: 800
})
try {
await page.goto("https://www.bilibili.com/", {
waitUntil: "domcontentloaded",
});
await page.waitForSelector(".animated-banner");
await sleep(3000);
// 获取所有 ".layer" 元素
let layerElements = await page.$$(".animated-banner .layer");
// 获取并下载保存数据
for (let i = 0; i < layerElements.length; i++) {
const layerFirstChild = await page.evaluate(async (el) => {
const pattern = /translate\(([-.\d]+px), ([-.\d]+px)\)/;
const { width, height, src, style, tagName } = el.firstElementChild;
const matches = style.transform.match(pattern);
const transform = [1,0,0,1,...matches.slice(1).map(x => +x.replace('px', ''))]
return { tagName: tagName.toLowerCase(), opacity: [style.opacity,style.opacity], transform, width, height, src, a: 0.01 };
}, layerElements[i]);
// data.push(layerFirstChild);
await download(layerFirstChild) // 下载并保存数据
}
// 完成后自动偏移banner
let element = await page.$('.animated-banner')
let { x, y } = await element.boundingBox()
await page.mouse.move(x + 0, y + 50)
await page.mouse.move(x + 1000, y, { steps: 1 })
await sleep(1200);
// 偏移后计算每个图层的相对位置,并得出加速度a
layerElements = await page.$$(".animated-banner .layer"); // 重新获取
for (let i = 0; i < layerElements.length; i++) {
const skew = await page.evaluate(async (el) => {
const pattern = /translate\(([-.\d]+px), ([-.\d]+px)\)/;
const matches = el.firstElementChild.style.transform.match(pattern);
return matches.slice(1).map(x => +x.replace('px', ''))[0]
}, layerElements[i]);
data[i].a = (skew - data[i].transform[4]) / 1000
}
} catch (error) {
console.error("Error:", error);
}
async function download(item) {
const fileArr = item.src.split("/");
const filePath = `${saveFolder}/${fileArr[fileArr.length - 1]}`;
const content = await page.evaluate(async (url) => {
const response = await fetch(url);
const buffer = await response.arrayBuffer();
return { buffer: Array.from(new Uint8Array(buffer)) };
}, item.src);
// const base64Data = Buffer.from(blobContent).toString('base64');
// fs.writeFileSync(filePath, base64Data, 'base64');
const fileData = Buffer.from(content.buffer);
fs.writeFileSync(filePath, fileData);
data.push({ ...item, ...{ src: filePath } });
}
fs.writeFileSync(path.resolve(__dirname, `${saveFolder}/data.json`), JSON.stringify(data, null, 2));
console.log('正在写入本地文件...');
await sleep(300)
// 编写 config
let codes = fs.readFileSync("config.js", "utf8");
const newConfig = `{
name: "${process.argv[2]}",
data: await banner_${date.replaceAll('-','')}.json()
},`;
const newImport = `const banner_${date.replaceAll('-','')} = await fetch('./assets/${date}/data.json?r='+Math.random())`
// 循环拆解每一行
const codeCollector = [];
for (const iterator of codes.split("\n")) {
codeCollector.push(iterator);
if (iterator.indexOf("-- ADD NEW --") !== -1) {
codeCollector.push(newConfig);
} else if (iterator.indexOf("-- IMPORT --") !== -1) {
codeCollector.push(newImport);
}
}
// 写入新文件
fs.writeFileSync('config.js', codeCollector.join("\n"))
await sleep(300)
await browser.close();
console.log('运行 npm run serve 查看效果吧!');
})();
function sleep(timeout) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, timeout);
});
}