1
This commit is contained in:
12
.vscode/launch.json
vendored
12
.vscode/launch.json
vendored
@@ -9,10 +9,22 @@
|
|||||||
"type": "node",
|
"type": "node",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "同步数据库",
|
"name": "同步数据库",
|
||||||
|
"cwd": "${workspaceFolder}\\server",
|
||||||
"skipFiles": [
|
"skipFiles": [
|
||||||
"<node_internals>/**"
|
"<node_internals>/**"
|
||||||
],
|
],
|
||||||
"program": "${workspaceFolder}\\server\\scripts\\db_sync.js"
|
"program": "${workspaceFolder}\\server\\scripts\\db_sync.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "启动服务",
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
],
|
||||||
|
// 工作区根目录
|
||||||
|
"cwd": "${workspaceFolder}\\server",
|
||||||
|
"program": "${workspaceFolder}\\server\\app.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
6
1.md
6
1.md
@@ -37,4 +37,8 @@
|
|||||||
3. 预期成果 (Outcome)
|
3. 预期成果 (Outcome)
|
||||||
- 可视化看板: 每天自动推送一份“户外品类异动日报”。
|
- 可视化看板: 每天自动推送一份“户外品类异动日报”。
|
||||||
- 爆款预警: 当监测到“防水包”类目下某新品 3 天内排名上升超过 50% 时,系统触发钉钉/邮件预警。
|
- 爆款预警: 当监测到“防水包”类目下某新品 3 天内排名上升超过 50% 时,系统触发钉钉/邮件预警。
|
||||||
- 决策支持: 提供该款产品的“避坑指南”(基于竞品售后差评分析)。
|
- 决策支持: 提供该款产品的“避坑指南”(基于竞品售后差评分析)。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"C:\Program Files\Google\Chrome\Application\chrome.exe" --disable-features=ExtensionManifestV2Unsupported,ExtensionManifestV2Disabled
|
||||||
@@ -20,7 +20,7 @@ const cfg = get_app_config();
|
|||||||
const port = cfg.server.port;
|
const port = cfg.server.port;
|
||||||
|
|
||||||
await sequelize.authenticate();
|
await sequelize.authenticate();
|
||||||
await sequelize.sync();
|
// await sequelize.sync();
|
||||||
start_all_cron_tasks();
|
start_all_cron_tasks();
|
||||||
|
|
||||||
app.listen(port);
|
app.listen(port);
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ export function get_app_config() {
|
|||||||
crx_src_path: must_get('CRX_SRC_PATH'),
|
crx_src_path: must_get('CRX_SRC_PATH'),
|
||||||
action_timeout_ms: get_int('ACTION_TIMEOUT_MS', 300000),
|
action_timeout_ms: get_int('ACTION_TIMEOUT_MS', 300000),
|
||||||
puppeteer_headless: get_bool('PUPPETEER_HEADLESS', false),
|
puppeteer_headless: get_bool('PUPPETEER_HEADLESS', false),
|
||||||
chrome_executable_path: (get_env('CHROME_EXECUTABLE_PATH') || '').trim() || path.resolve(__dirname, '../../chrome-win/chrome.exe')
|
chrome_executable_path: (get_env('CHROME_EXECUTABLE_PATH') || '').trim() || path.resolve(__dirname, '../../chrome-win/chrome.exe'),
|
||||||
|
log_invoke_action: get_bool('LOG_INVOKE_ACTION', true)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
export const cron_task_list = [
|
export const cron_task_list = [
|
||||||
// 示例:每 6 小时跑一次列表抓取
|
// 示例:每 6 小时跑一次列表抓取
|
||||||
// {
|
{
|
||||||
// name: 'amazon_search_list_every_6h',
|
name: 'amazon_search_list_every_6h',
|
||||||
// cron_expression: '0 */6 * * *',
|
cron_expression: '0 */1 * * *',
|
||||||
// action_name: 'amazon_search_list',
|
action_name: 'amazon_search_list',
|
||||||
// action_payload: { keyword: '午餐包', limit: 100 }
|
action_payload: { keyword: '野餐包', limit: 100 }
|
||||||
// }
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { get_app_config } from './app_config.js';
|
|||||||
|
|
||||||
export function get_sequelize_options() {
|
export function get_sequelize_options() {
|
||||||
const cfg = get_app_config();
|
const cfg = get_app_config();
|
||||||
|
console.log( 'get_sequelize_options', cfg.mysql );
|
||||||
|
|
||||||
return {
|
return {
|
||||||
host: cfg.mysql.host,
|
host: cfg.mysql.host,
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import { execute_action_and_record } from './task_executor.js';
|
|||||||
|
|
||||||
const cron_jobs = [];
|
const cron_jobs = [];
|
||||||
|
|
||||||
export function start_all_cron_tasks() {
|
export async function start_all_cron_tasks() {
|
||||||
for (const task of cron_task_list) {
|
for (const task of cron_task_list) {
|
||||||
const job = cron.schedule(task.cron_expression, async () => {
|
// const job = cron.schedule(task.cron_expression, async () => {
|
||||||
try {
|
try {
|
||||||
await execute_action_and_record({
|
await execute_action_and_record({
|
||||||
action_name: task.action_name,
|
action_name: task.action_name,
|
||||||
@@ -16,9 +16,9 @@ export function start_all_cron_tasks() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
// 失败会在 crawl_run_record 落库
|
// 失败会在 crawl_run_record 落库
|
||||||
}
|
}
|
||||||
});
|
// });
|
||||||
|
|
||||||
cron_jobs.push(job);
|
// cron_jobs.push(job);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,15 +13,18 @@ export async function execute_action_and_record(params) {
|
|||||||
let error_message = null;
|
let error_message = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await invoke_extension_action(action_name, action_payload || {});
|
|
||||||
|
|
||||||
|
|
||||||
|
console.log( 'invoke_extension_action-start', action_name, action_payload );
|
||||||
|
const res_invoke = await invoke_extension_action(action_name, action_payload || {});
|
||||||
|
console.log( 'invoke_extension_action-end', action_name, result );
|
||||||
ok = true;
|
ok = true;
|
||||||
result_payload = safe_json_stringify(result);
|
result_payload = safe_json_stringify(res_invoke);
|
||||||
|
|
||||||
// 按 stage 自动入库(不影响原始 run_record 记录)
|
// 按 stage 自动入库(不影响原始 run_record 记录)
|
||||||
await persist_amazon_result(result);
|
await persist_amazon_result(res_invoke.result);
|
||||||
|
|
||||||
return result;
|
return res_invoke;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ok = false;
|
ok = false;
|
||||||
error_message = (err && err.message) || String(err);
|
error_message = (err && err.message) || String(err);
|
||||||
|
|||||||
Reference in New Issue
Block a user