161 lines
6.5 KiB
JavaScript
161 lines
6.5 KiB
JavaScript
const { chromium } = require('playwright');
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
|
||
(async () => {
|
||
// 启动浏览器
|
||
const browser = await chromium.launch({
|
||
headless: true // 设置为有头模式,方便观察
|
||
});
|
||
const context = await browser.newContext();
|
||
const page = await context.newPage();
|
||
|
||
try {
|
||
page.setViewportSize({ width: 2560, height: 1440 });
|
||
|
||
// url = "https://play.grafana.org/a/grafana-app-observability-app"
|
||
url = "https://play.grafana.org/dashboards"
|
||
// url = "https://play.grafana.org/a/grafana-synthetic-monitoring-app/probes"
|
||
|
||
// 访问目标网站,增加超时时间并添加重试逻辑
|
||
console.log(`正在访问 ${url}...`);
|
||
|
||
// 增加超时时间到 120 秒
|
||
await page.goto(url, {
|
||
timeout: 120000, // 增加到 120 秒
|
||
waitUntil: 'domcontentloaded' // 改为只等待 DOM 加载完成,不等待所有资源
|
||
});
|
||
|
||
console.log('页面加载完成');
|
||
|
||
// 等待页面稳定
|
||
try {
|
||
await page.waitForLoadState('networkidle', { timeout: 30000 });
|
||
} catch (e) {
|
||
console.log('网络未完全空闲,但继续执行:', e.message);
|
||
}
|
||
|
||
|
||
// 展开所有折叠的部分
|
||
console.log('\n开始展开导航项...');
|
||
|
||
// 用 Set 来记录已经点击过的按钮
|
||
const clickedButtons = new Set();
|
||
|
||
const expandButtons = async () => {
|
||
console.log('开始寻找可展开按钮...');
|
||
// 查找所有折叠按钮
|
||
const buttons = await page.$$('button[aria-label*="Expand"], button[aria-label*="Open"], button[aria-expanded="false"]');
|
||
console.log(`找到 ${buttons.length} 个折叠按钮`);
|
||
|
||
let newButtonsFound = false;
|
||
|
||
for (const button of buttons) {
|
||
try {
|
||
const ariaLabel = await button.getAttribute('aria-label');
|
||
// 检查按钮是否已经点击过
|
||
if (!clickedButtons.has(ariaLabel)) {
|
||
console.log(`点击新按钮: ${ariaLabel}`);
|
||
await button.click();
|
||
clickedButtons.add(ariaLabel);
|
||
newButtonsFound = true;
|
||
await page.waitForTimeout(200);
|
||
}
|
||
} catch (e) {
|
||
console.log(`点击失败: ${e.message}`);
|
||
}
|
||
}
|
||
|
||
return newButtonsFound;
|
||
};
|
||
|
||
// 持续查找和点击,直到没有新按钮
|
||
let iteration = 1;
|
||
while (true) {
|
||
console.log(`\n第 ${iteration} 次查找...`);
|
||
const foundNewButtons = await expandButtons();
|
||
|
||
if (!foundNewButtons) {
|
||
console.log('没有发现新的可展开按钮,结束查找');
|
||
break;
|
||
}
|
||
|
||
console.log(`已点击按钮数量: ${clickedButtons.size}`);
|
||
await page.waitForTimeout(500);
|
||
iteration++;
|
||
}
|
||
|
||
// 确保截图目录存在
|
||
const screenshotDir = path.join(__dirname, 'temp_screenshot');
|
||
|
||
fs.rmSync(screenshotDir, { recursive: true, force: true });
|
||
fs.mkdirSync(screenshotDir, { recursive: true });
|
||
console.log(`创建截图目录: ${screenshotDir}`);
|
||
|
||
const anchorHandles = await page.$$('a');
|
||
console.log(`找到 ${anchorHandles.length} 个链接`);
|
||
|
||
for (let i = 0; i < anchorHandles.length; i++) {
|
||
try {
|
||
const anchorHandle = anchorHandles[i];
|
||
|
||
// 先获取 <a> 标签的 href 与文本内容
|
||
const anchorData = await page.evaluate(el => {
|
||
return {
|
||
url: el.href,
|
||
text: el.innerText.trim()
|
||
};
|
||
}, anchorHandle);
|
||
|
||
// 生成文件名 (使用索引和文本内容的组合)
|
||
let filename = `link_${i+1}_${anchorData.text}`;
|
||
// 替换不合法的文件名字符
|
||
filename = filename.replace(/[\\/:*?"<>|]/g, '_');
|
||
// 限制文件名长度
|
||
if (filename.length > 100) filename = filename.substring(0, 100);
|
||
|
||
try {
|
||
// 使用更可靠的滚动方法
|
||
await page.evaluate(element => {
|
||
// 使用JavaScript的scrollIntoView,更直接且兼容性更好
|
||
element.scrollIntoView({behavior: 'smooth', block: 'center'});
|
||
}, anchorHandle);
|
||
|
||
await page.waitForTimeout(500); // 给滚动和渲染更多时间
|
||
|
||
const rect = await anchorHandle.boundingBox();
|
||
|
||
filename = `${filename}_${rect.x}_${rect.y}_${rect.width}_${rect.height}.png`;
|
||
|
||
// 截图并保存
|
||
const screenshotPath = path.join(screenshotDir, filename);
|
||
await page.screenshot({ path: screenshotPath });
|
||
|
||
console.log(`处理链接 ${i+1}/${anchorHandles.length}: ${anchorData.text} - 已截图保存至 ${filename}`);
|
||
} catch (scrollError) {
|
||
console.log(`处理链接 ${i+1}/${anchorHandles.length}: ${anchorData.text} - 滚动失败但尝试截图`);
|
||
// 即使滚动失败也尝试截图
|
||
try {
|
||
const screenshotPath = path.join(screenshotDir, filename);
|
||
await page.screenshot({ path: screenshotPath });
|
||
} catch (e) {
|
||
console.error(`截图失败: ${e.message}`);
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error(`处理第 ${i+1} 个链接时出错:`, error.message);
|
||
}
|
||
}
|
||
|
||
console.log(`链接总数: ${anchorHandles.length}, 截图已保存到 ${screenshotDir}`);
|
||
|
||
console.log('\n等待1000秒...');
|
||
await page.waitForTimeout(1000 * 1000);
|
||
|
||
} catch (error) {
|
||
console.error('发生错误:', error);
|
||
} finally {
|
||
// 关闭浏览器
|
||
await browser.close();
|
||
}
|
||
})(); |