-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathplay-fsi.js
222 lines (186 loc) · 7.18 KB
/
play-fsi.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
const { chromium } = require("playwright");
const axios = require("axios");
const winston = require("winston");
const fs = require("fs");
const crypto = require("crypto");
const phoneNumber = "18600372156";
const postUrl =
"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=4fbae71d-8d83-479f-a2db-7690eeb37a5c";
const gotoUrl = "https://www.financialresearch.gov/financial-stress-index/";
// 配置Winston日志记录器
const logger = winston.createLogger({
level: "info",
format: winston.format.combine(
winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
winston.format.printf(
(info) =>
`${info.timestamp} [${info.level.toUpperCase()}] - ${info.message}`
)
),
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: "log/combined.log" }),
],
});
async function sendToWebhook(currentIndex, formattedDate) {
const dateParts = formattedDate.split(',')[1].trim().split('/');
const monthDay = `${parseInt(dateParts[0], 10)}月${parseInt(dateParts[1], 10)}日`;
const year = dateParts[2];
const postData = {
msgtype: "text",
text: {
content: `${monthDay} 美国FSI指数 ${currentIndex}。指数发布时间 ${formattedDate}。美国FSI (Financial Stress Index) 是一种衡量金融市场压力的指标。这个指数通常由美国各大银行或金融机构编制, 用于反映金融市场的整体状况, 包括流动性、信用风险和市场波动性等方面。`,
mentioned_mobile_list: [phoneNumber],
},
};
try {
// Send the POST request
const response = await axios.post(postUrl, postData);
logger.info("sendToWebhook: Response status: " + response.status);
logger.info("sendToWebhook: Response status text: " + response.statusText);
logger.info("sendToWebhook: Response headers: " + JSON.stringify(response.headers));
logger.info("sendToWebhook: Response data: " + JSON.stringify(response.data));
} catch (error) {
logger.error(`sendToWebhook: 发送到Webhook时发生错误: ${error.message}`);
}
}
async function sendImageToWebhook() {
try {
// Read the image file and convert it to base64
const imageBuffer = fs.readFileSync("screenshot.png");
const base64Image = imageBuffer.toString("base64");
// Calculate md5 hash of the base64 image
const md5Hash = crypto
.createHash("md5")
.update(imageBuffer, "binary")
.digest("hex");
// Prepare the POST data
const postData = {
msgtype: "image",
image: {
base64: base64Image,
md5: md5Hash,
},
};
// Send the POST request
const response = await axios.post(postUrl, postData);
logger.info(
"sendImageToWebhook: Image sent to Webhook successfully" + JSON.stringify(response.data)
);
} catch (error) {
logger.error(
`sendImageToWebhook: Error occurred while sending image to Webhook: ${error.message}`
);
}
}
async function scrapeData() {
let browser; // Move the browser variable declaration to the top
try {
logger.info("scrapeData: 启动浏览器");
const startBrowserTime = new Date();
browser = await chromium.launch({ headless: true });
logger.info(`scrapeData: 浏览器启动,耗时: ${new Date() - startBrowserTime}ms`);
const page = await browser.newPage();
logger.info("scrapeData: 导航到网页");
const startNavigationTime = new Date();
let maxRetries = 5;
let timeout = 60000; // Start with a 30-second timeout
let success = false;
for (let i = 0; i < maxRetries && !success; i++) {
try {
await page.goto(gotoUrl, { waitUntil: "load", timeout: timeout });
success = true; // If page.goto succeeds, set success to true
logger.info(`scrapeData: 导航完成,耗时: ${new Date() - startNavigationTime}ms`);
// Simulate Page Down key press
await page.keyboard.press("PageDown");
await new Promise((resolve) => setTimeout(resolve, 20000));
} catch (error) {
logger.error(
`scrapeData: Attempt ${i + 1}: page.goto failed with timeout ${timeout}ms`
);
timeout += 30000; // Increase timeout by 30 seconds for the next attempt
if (i < maxRetries - 1) {
logger.info(`scrapeData: Retrying navigation...`);
}
}
}
if (!success) {
throw new Error("scrapeData: page.goto failed after all retries");
}
const selectorIndex = ".latest-daily-observation .header span";
const selectorDate = ".latest-daily-observation .stat";
await page.waitForSelector(selectorIndex);
await page.waitForSelector(selectorDate);
const currentIndex = await page.textContent(selectorIndex);
const dateInfo = await page.textContent(selectorDate);
const formattedDate = formatDate(dateInfo);
logger.info(
`scrapeData: Current Index: ${currentIndex.trim()}, Date Info: ${dateInfo}, Formatted Date: ${formattedDate}`
);
// Take a screenshot
const screenshotPath = "screenshot.png";
let topLeftX = 150;
let topLeftY = 0;
let width = 1000;
let height = 440;
await page.screenshot({
path: "screenshot.png",
clip: { x: topLeftX, y: topLeftY, width: width, height: height },
});
// Log the screenshot path
logger.info(`scrapeData: Screenshot saved at: ${screenshotPath}`);
await browser.close();
logger.info("scrapeData: 浏览器已关闭");
await sendToWebhook(currentIndex.trim(), formattedDate);
// Call the function to send the image
sendImageToWebhook().catch((err) => logger.error(err));
return { currentIndex: currentIndex.trim(), dateInfo, formattedDate };
} catch (error) {
logger.error(`scrapeData: 抓取数据时发生错误: ${error.message}`);
if (browser) {
await browser.close();
logger.info("scrapeData: 浏览器已关闭");
}
throw error; // Throw the error to be caught by the caller
}
}
function formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleDateString("en-US", {
weekday: "long",
year: "numeric",
month: "2-digit",
day: "2-digit",
});
}
async function main() {
const maxRetries = 5; // Set the maximum number of retries
let retries = 0;
let success = false;
while (retries < maxRetries && !success) {
try {
logger.info("main: 开始执行任务");
const data = await scrapeData();
if (data.error) {
logger.error("main: 抓取过程中发生错误", data.error);
} else {
logger.info("main: 抓取数据完成", JSON.stringify(data));
success = true; // Mark as success to break the loop
}
} catch (err) {
logger.error(err);
retries++;
if (retries < maxRetries) {
logger.info(`main: 等待5分钟后重试... (${retries}/${maxRetries})`);
// await new Promise(resolve => setTimeout(resolve, 5 * 60 * 1000)); // Wait for 5 minutes
await new Promise(resolve => setTimeout(resolve, 1 * 1 * 1000)); // Wait for 5 minutes
}
}
}
if (!success) {
logger.error("main: 达到最大重试次数,任务失败");
process.exit(1); // Exit the process with an error code
}
logger.info("main: 任务执行结束");
}
main().catch((err) => logger.error(err));