This commit is contained in:
Ubuntu
2026-07-03 16:58:28 +08:00
commit 32b43f85bd
6240 changed files with 1987678 additions and 0 deletions
@@ -0,0 +1,28 @@
#!/usr/bin/env node
/**
* 检查浏览器环境
*/
const fs = require('fs');
const { getBrowserPath } = require('../config/browser');
console.log('🔍 检查浏览器环境...\n');
const paths = getBrowserPath();
console.log('可能的浏览器路径:');
paths.forEach((p, i) => {
const exists = fs.existsSync(p);
console.log(` ${i + 1}. ${p} ${exists ? '✅' : '❌'}`);
});
const found = paths.find(p => fs.existsSync(p));
if (found) {
console.log(`\n✅ 找到可用浏览器: ${found}`);
process.exit(0);
} else {
console.log('\n❌ 未找到浏览器,请安装:');
console.log(' 方式1: npx puppeteer browsers install chrome');
console.log(' 方式2: sudo apt-get install chromium-browser');
console.log(' 方式3: 设置环境变量 PUPPETEER_EXECUTABLE_PATH=/path/to/chrome');
process.exit(1);
}
@@ -0,0 +1,64 @@
#!/usr/bin/env node
/**
* 获取所有平台热点
*/
const { fetchWeiboHot } = require('../src/platforms/weibo');
const { fetchBilibiliTrending } = require('../src/platforms/bilibili');
const { fetchZhihuHot } = require('../src/platforms/zhihu');
async function getAllHotspots() {
console.log('='.repeat(80));
console.log('🔥 中文平台热点聚合抓取');
console.log('='.repeat(80));
const results = {
timestamp: new Date().toISOString(),
platforms: {},
};
// 微博
try {
console.log('\n📌 1. 微博热搜');
results.platforms.weibo = await fetchWeiboHot();
} catch (e) {
console.error('微博抓取失败:', e.message);
results.platforms.weibo = { error: e.message };
}
// B站
try {
console.log('\n📌 2. B站热搜');
results.platforms.bilibili = await fetchBilibiliTrending();
} catch (e) {
console.error('B站抓取失败:', e.message);
results.platforms.bilibili = { error: e.message };
}
// 知乎
try {
console.log('\n📌 3. 知乎热榜');
results.platforms.zhihu = await fetchZhihuHot();
} catch (e) {
console.error('知乎抓取失败:', e.message);
results.platforms.zhihu = { error: e.message };
}
console.log('\n' + '='.repeat(80));
console.log('✅ 所有平台抓取完成');
console.log('='.repeat(80));
// 保存汇总
const fs = require('fs');
const path = require('path');
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filepath = path.join(__dirname, '../data', `all_hotspots_${timestamp}.json`);
fs.mkdirSync(path.dirname(filepath), { recursive: true });
fs.writeFileSync(filepath, JSON.stringify(results, null, 2), 'utf-8');
console.log(`💾 汇总数据已保存: ${filepath}`);
return results;
}
getAllHotspots().catch(console.error);
@@ -0,0 +1,6 @@
#!/usr/bin/env node
/**
* 获取B站热搜
*/
const { fetchBilibiliTrending } = require('../src/platforms/bilibili');
fetchBilibiliTrending().catch(console.error);
@@ -0,0 +1,11 @@
#!/usr/bin/env node
/**
* 获取博客园热门文章
*/
const { fetchCnblogsHot, searchCnblogs } = require('../src/platforms/techblogs/cnblogs');
const keyword = process.argv[2];
if (keyword) {
searchCnblogs(keyword).catch(console.error);
} else {
fetchCnblogsHot().catch(console.error);
}
@@ -0,0 +1,7 @@
#!/usr/bin/env node
/**
* 获取掘金热门文章
*/
const { fetchJuejinHot } = require('../src/platforms/techblogs/juejin');
const category = process.argv[2] || 'all';
fetchJuejinHot(category).catch(console.error);
@@ -0,0 +1,6 @@
#!/usr/bin/env node
/**
* 获取微博热搜
*/
const { fetchWeiboHot } = require('../src/platforms/weibo');
fetchWeiboHot().catch(console.error);
@@ -0,0 +1,6 @@
#!/usr/bin/env node
/**
* 获取知乎热榜
*/
const { fetchZhihuHot } = require('../src/platforms/zhihu');
fetchZhihuHot().catch(console.error);
@@ -0,0 +1,211 @@
#!/usr/bin/env node
/**
* 使用 Puppeteer 搜索技术博客
*/
const puppeteer = require('puppeteer-core');
const { getLaunchOptions } = require('../config/browser');
const fs = require('fs');
const path = require('path');
function saveResult(platform, keyword, items) {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const data = {
platform,
keyword,
timestamp: new Date().toISOString(),
count: items.length,
items,
};
const filepath = path.join(__dirname, '../data', `${platform}_search_${timestamp}.json`);
if (!fs.existsSync(path.dirname(filepath))) {
fs.mkdirSync(path.dirname(filepath), { recursive: true });
}
fs.writeFileSync(filepath, JSON.stringify(data, null, 2), 'utf-8');
return filepath;
}
function printResults(items, platform) {
console.log('\n' + '='.repeat(70));
items.forEach((item, i) => {
console.log(`${i + 1}. ${item.title.substring(0, 60)}${item.title.length > 60 ? '...' : ''}`);
console.log(` ${item.url}`);
});
console.log('='.repeat(70));
}
async function searchJuejin(browser, keyword) {
console.log(`\n📱 搜索掘金: "${keyword}"`);
const page = await browser.newPage();
try {
await page.setUserAgent(
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
);
const url = `https://juejin.cn/search?query=${encodeURIComponent(keyword)}&type=0`;
await page.goto(url, {
waitUntil: 'networkidle2',
timeout: 60000,
});
// 等待搜索结果加载
await new Promise(r => setTimeout(r, 3000));
// 提取搜索结果
const items = await page.evaluate(() => {
const results = [];
// 掘金搜索结果选择器
const selectors = [
'.search-result-list .item a.title',
'.result-list .item .title a',
'[class*="search"] [class*="item"] a[href*="/post/"]',
'.article-item a',
];
for (const selector of selectors) {
const elements = document.querySelectorAll(selector);
if (elements.length > 0) {
elements.forEach((el) => {
const title = el.textContent?.trim();
const href = el.getAttribute('href');
if (title && href && title.length > 5 && !results.find(r => r.title === title)) {
const articleId = href.match(/\/post\/(\d+)/)?.[1];
if (articleId) {
results.push({
title: title.substring(0, 100),
url: `https://juejin.cn/post/${articleId}`,
});
}
}
});
break;
}
}
return results.slice(0, 10);
});
if (items.length > 0) {
printResults(items, '掘金');
const filepath = saveResult('juejin', keyword, items);
console.log(`✅ 找到 ${items.length} 条结果`);
console.log(`💾 已保存: ${filepath}`);
} else {
console.log('⚠️ 未找到结果,页面可能需要登录');
}
return items;
} catch (e) {
console.error('❌ 掘金搜索失败:', e.message);
return [];
} finally {
await page.close();
}
}
async function searchCnblogs(browser, keyword) {
console.log(`\n💻 搜索博客园: "${keyword}"`);
const page = await browser.newPage();
try {
await page.setUserAgent(
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
);
const url = `https://zzk.cnblogs.com/s?w=${encodeURIComponent(keyword)}`;
await page.goto(url, {
waitUntil: 'networkidle2',
timeout: 60000,
});
await new Promise(r => setTimeout(r, 3000));
// 提取搜索结果
const items = await page.evaluate(() => {
const results = [];
const selectors = [
'.searchItem .searchItemTitle a',
'.search-item .title a',
'#search_result .searchItem a',
];
for (const selector of selectors) {
const elements = document.querySelectorAll(selector);
if (elements.length > 0) {
elements.forEach((el) => {
const title = el.textContent?.trim();
const href = el.getAttribute('href');
if (title && href && title.length > 5 && !results.find(r => r.title === title)) {
results.push({
title: title.substring(0, 100),
url: href.startsWith('http') ? href : `https:${href}`,
});
}
});
break;
}
}
return results.slice(0, 10);
});
if (items.length > 0) {
printResults(items, '博客园');
const filepath = saveResult('cnblogs', keyword, items);
console.log(`✅ 找到 ${items.length} 条结果`);
console.log(`💾 已保存: ${filepath}`);
} else {
console.log('⚠️ 未找到结果');
}
return items;
} catch (e) {
console.error('❌ 博客园搜索失败:', e.message);
return [];
} finally {
await page.close();
}
}
async function main() {
const keyword = process.argv[2] || 'android 开发';
const platform = process.argv[3] || 'all';
console.log('='.repeat(70));
console.log(`🔍 技术博客搜索: "${keyword}"`);
console.log('='.repeat(70));
const browser = await puppeteer.launch(getLaunchOptions());
try {
if (platform === 'all' || platform === 'juejin') {
await searchJuejin(browser, keyword);
}
if (platform === 'all' || platform === 'cnblogs') {
await searchCnblogs(browser, keyword);
}
} finally {
await browser.close();
}
console.log('\n' + '='.repeat(70));
console.log('搜索完成');
console.log('='.repeat(70));
}
main().catch(console.error);
+149
View File
@@ -0,0 +1,149 @@
#!/usr/bin/env node
/**
* 搜索技术博客
* 用法: node search-tech.js <关键词> [juejin|cnblogs|all]
*/
const https = require('https');
const fs = require('fs');
const path = require('path');
// 保存结果
function saveResult(platform, data) {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `${platform}_search_${timestamp}.json`;
const filepath = path.join(__dirname, '../data', filename);
if (!fs.existsSync(path.dirname(filepath))) {
fs.mkdirSync(path.dirname(filepath), { recursive: true });
}
fs.writeFileSync(filepath, JSON.stringify(data, null, 2), 'utf-8');
console.log(`💾 结果已保存: ${filepath}`);
}
// HTTP 请求
function httpGet(url, headers = {}) {
return new Promise((resolve, reject) => {
https.get(url, { headers }, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => resolve(data));
}).on('error', reject);
});
}
// 搜索掘金
async function searchJuejin(keyword) {
console.log(`\n📱 搜索掘金: "${keyword}"`);
console.log('-'.repeat(60));
try {
const url = `https://juejin.cn/search?query=${encodeURIComponent(keyword)}&type=0`;
const html = await httpGet(url, {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
'Referer': 'https://juejin.cn/',
});
const items = [];
const regex = /href="https:\/\/juejin\.cn\/post\/(\d+)"[^>]*>([^<]+)<\/a>/gi;
let match;
while ((match = regex.exec(html)) !== null && items.length < 10) {
const title = match[2].trim();
if (title.length > 5 && !items.find(i => i.title === title)) {
items.push({
rank: items.length + 1,
title: title.substring(0, 80),
url: `https://juejin.cn/post/${match[1]}`,
});
}
}
if (items.length > 0) {
items.forEach(i => console.log(`${i.rank}. ${i.title}`));
saveResult('juejin', { keyword, items });
console.log(`✅ 找到 ${items.length} 条结果`);
} else {
console.log('⚠️ 未找到结果');
}
return items;
} catch (e) {
console.error('❌ 掘金搜索失败:', e.message);
return [];
}
}
// 搜索博客园
async function searchCnblogs(keyword) {
console.log(`\n💻 搜索博客园: "${keyword}"`);
console.log('-'.repeat(60));
try {
const url = `https://zzk.cnblogs.com/s?w=${encodeURIComponent(keyword)}`;
const html = await httpGet(url, {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
});
const items = [];
// 匹配搜索结果
const titleRegex = /<a[^>]*class="searchItemTitle"[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/gi;
let match;
while ((match = titleRegex.exec(html)) !== null && items.length < 10) {
const url = match[1];
const title = match[2].replace(/<[^>]+>/g, '').trim();
if (title.length > 5 && !items.find(i => i.title === title)) {
items.push({
rank: items.length + 1,
title: title.substring(0, 80),
url: url.startsWith('http') ? url : `https:${url}`,
});
}
}
if (items.length > 0) {
items.forEach(i => console.log(`${i.rank}. ${i.title}`));
saveResult('cnblogs', { keyword, items });
console.log(`✅ 找到 ${items.length} 条结果`);
} else {
console.log('⚠️ 未找到结果');
}
return items;
} catch (e) {
console.error('❌ 博客园搜索失败:', e.message);
return [];
}
}
// 主函数
async function main() {
const keyword = process.argv[2];
const platform = process.argv[3] || 'all';
if (!keyword) {
console.log('用法: node search-tech.js <关键词> [juejin|cnblogs|all]');
process.exit(1);
}
console.log('='.repeat(60));
console.log(`🔍 技术博客搜索: "${keyword}"`);
console.log('='.repeat(60));
if (platform === 'all' || platform === 'juejin') {
await searchJuejin(keyword);
}
if (platform === 'all' || platform === 'cnblogs') {
await searchCnblogs(keyword);
}
console.log('\n' + '='.repeat(60));
console.log('搜索完成');
console.log('='.repeat(60));
}
main().catch(console.error);
@@ -0,0 +1,77 @@
/**
* 检查微博发送状态
*/
const puppeteer = require('puppeteer-core');
const { getLaunchOptions } = require('../config/browser');
const fs = require('fs');
const COOKIE_FILE = '/home/ubuntu/weibo_cookies.txt';
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function checkStatus() {
console.log('🔍 检查发送状态...');
const browser = await puppeteer.launch({
...getLaunchOptions(),
headless: true,
});
try {
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900 });
// 加载 Cookie
const cookies = JSON.parse(fs.readFileSync(COOKIE_FILE, 'utf-8'));
await page.goto('https://weibo.com', { waitUntil: 'domcontentloaded' });
for (const c of cookies) {
try {
await page.setCookie({
name: c.name,
value: c.value,
domain: c.domain,
path: c.path || '/'
});
} catch (e) {}
}
// 访问个人主页查看最新微博
await page.goto('https://weibo.com/u/me?tabtype=weibo', { waitUntil: 'networkidle2' });
await delay(3000);
await page.screenshot({ path: '/tmp/weibo_login/check_status.png' });
// 获取最新的几条微博
const posts = await page.evaluate(() => {
const items = Array.from(document.querySelectorAll('[class*="card"], [class*="item"], article'));
return items.slice(0, 3).map(item => {
const text = item.textContent || '';
const time = item.querySelector('time, [class*="time"], [class*="date"]')?.textContent || '';
return { text: text.substring(0, 200), time };
});
});
console.log('\n📱 最新微博内容:');
posts.forEach((post, i) => {
console.log(`\n[${i + 1}] ${post.time}`);
console.log(` ${post.text.substring(0, 100)}...`);
});
// 检查是否有刚刚发的测试微博
const hasTestPost = posts.some(p => p.text.includes('自动化脚本') || p.text.includes('🤖'));
if (hasTestPost) {
console.log('\n✅ 找到了测试微博!');
} else {
console.log('\n⚠️ 未找到测试微博,可能发送失败了');
}
} catch (error) {
console.error('❌ 错误:', error.message);
} finally {
await browser.close();
}
}
checkStatus().catch(console.error);
+159
View File
@@ -0,0 +1,159 @@
/**
* 微博自动发布 - 最终版本
*/
const puppeteer = require('puppeteer-core');
const { getLaunchOptions } = require('../config/browser');
const fs = require('fs');
const COOKIE_FILE = '/home/ubuntu/weibo_cookies.txt';
const TEST_CONTENT = '🤖 这是一条来自自动化脚本的测试微博\n时间:' + new Date().toLocaleString('zh-CN') + '\n#自动化测试 #机器人';
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function postWeibo() {
console.log('🌐 启动浏览器...');
const browser = await puppeteer.launch({
...getLaunchOptions(),
headless: true,
});
try {
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900 });
// 加载 Cookie
console.log('🍪 加载 Cookie...');
const cookies = JSON.parse(fs.readFileSync(COOKIE_FILE, 'utf-8'));
await page.goto('https://weibo.com', { waitUntil: 'domcontentloaded' });
for (const c of cookies) {
try {
await page.setCookie({
name: c.name,
value: c.value,
domain: c.domain,
path: c.path || '/',
secure: c.secure || false,
httpOnly: c.httpOnly || false
});
} catch (e) {}
}
// 访问主页
console.log('🔄 访问微博主页...');
await page.goto('https://weibo.com', { waitUntil: 'networkidle2' });
await delay(3000);
await page.screenshot({ path: '/tmp/weibo_login/step1_home.png' });
// 查找并点击"写微博"按钮
console.log('🖱️ 查找"写微博"按钮...');
const writeBtn = await page.$eval('button', buttons => {
const btns = Array.from(document.querySelectorAll('button'));
return btns.find(b => b.textContent?.includes('写微博'));
}).catch(() => null);
// 通过文本查找
let found = false;
const allBtns = await page.$$('button, a, div[role="button"]');
for (const btn of allBtns) {
const text = await page.evaluate(el => el.textContent, btn);
if (text?.includes('写微博')) {
console.log(` 找到: "${text.trim()}"`);
await btn.click();
found = true;
break;
}
}
if (!found) {
console.log('⚠️ 未找到"写微博"按钮,尝试直接访问compose页面');
await page.goto('https://weibo.com/compose', { waitUntil: 'networkidle2' });
} else {
await delay(2000);
}
await page.screenshot({ path: '/tmp/weibo_login/step2_compose.png' });
// 查找发布框
console.log('📝 查找发布框...');
const selectors = [
'textarea[placeholder*="有什么新鲜事"]',
'textarea[placeholder*="想说什么"]',
'textarea.woo-input-main',
'[class*="input"] textarea',
'textarea',
];
let postBox = null;
for (const sel of selectors) {
postBox = await page.$(sel);
if (postBox) {
console.log(` 找到: ${sel}`);
break;
}
}
if (!postBox) {
// 获取所有textarea
const textareas = await page.$$('textarea');
console.log(` 尝试 ${textareas.length} 个 textarea`);
if (textareas.length > 0) {
postBox = textareas[0];
}
}
if (postBox) {
// 输入内容
await postBox.click();
await delay(500);
await postBox.type(TEST_CONTENT, { delay: 30 });
console.log('✍️ 已输入:', TEST_CONTENT.substring(0, 50) + '...');
await delay(1000);
await page.screenshot({ path: '/tmp/weibo_login/step3_typed.png' });
// 查找发送按钮
console.log('🔍 查找发送按钮...');
let sendBtn = null;
const allBtns2 = await page.$$('button, a, div[role="button"]');
for (const btn of allBtns2) {
const text = await page.evaluate(el => el.textContent, btn);
if (text?.includes('发送') || text?.includes('发布')) {
console.log(` 找到: "${text.trim()}"`);
sendBtn = btn;
break;
}
}
if (sendBtn) {
console.log('🚀 点击发送...');
await sendBtn.click();
await delay(5000);
await page.screenshot({ path: '/tmp/weibo_login/step4_sent.png' });
console.log('✅ 发送完成!');
// 检查是否成功
const currentUrl = page.url();
if (currentUrl.includes('weibo.com')) {
console.log('🎉 微博发布流程执行完毕!');
}
} else {
console.log('⚠️ 未找到发送按钮');
}
} else {
console.log('❌ 未找到发布框');
}
} catch (error) {
console.error('❌ 错误:', error.message);
} finally {
await browser.close();
}
}
postWeibo().catch(console.error);
@@ -0,0 +1,74 @@
const puppeteer = require('puppeteer-core');
const { getLaunchOptions } = require('../config/browser');
const fs = require('fs');
const delay = (ms) => new Promise(r => setTimeout(r, ms));
const TEST_CONTENT = '🤖 二维码登录测试成功!时间:' + new Date().toLocaleString('zh-CN');
(async () => {
const browser = await puppeteer.launch(getLaunchOptions());
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900 });
// 访问主页
await page.goto('https://weibo.com', { waitUntil: 'networkidle2' });
await delay(3000);
console.log('🔗 URL:', page.url());
console.log('📄 标题:', await page.title());
// 找写微博按钮并点击
const writeBtn = await page.evaluateHandle(() => {
const btns = Array.from(document.querySelectorAll('button, a, div[role="button"]'));
return btns.find(b => b.textContent && b.textContent.includes('写微博'));
});
if (writeBtn) {
console.log('🖱️ 点击写微博...');
await writeBtn.click();
await delay(2000);
// 找发布框
const postBox = await page.$('textarea[placeholder*="有什么新鲜事"]');
if (postBox) {
await postBox.click();
await delay(500);
await postBox.type(TEST_CONTENT, { delay: 30 });
console.log('✍️ 已输入:', TEST_CONTENT);
await delay(1000);
// 找发送按钮
const sendBtn = await page.evaluateHandle(() => {
const btns = Array.from(document.querySelectorAll('button, a, div[role="button"]'));
return btns.find(b => b.textContent && b.textContent.includes('发送'));
});
if (sendBtn) {
console.log('🚀 点击发送...');
await sendBtn.click();
await delay(5000);
console.log('✅ 已发送!');
await page.screenshot({ path: '/tmp/weibo_qr_login/final_result.png' });
fs.copyFileSync('/tmp/weibo_qr_login/final_result.png', '/home/ubuntu/nanocode/audiobook-player/static/final_result.png');
// 验证
await page.goto('https://weibo.com/u/me?tabtype=weibo', { waitUntil: 'networkidle2' });
await delay(3000);
await page.screenshot({ path: '/tmp/weibo_qr_login/verify_post.png' });
fs.copyFileSync('/tmp/weibo_qr_login/verify_post.png', '/home/ubuntu/nanocode/audiobook-player/static/verify_post.png');
console.log('📸 验证截图已保存');
console.log('🎉 完成!');
} else {
console.log('⚠️ 未找到发送按钮');
}
} else {
console.log('⚠️ 未找到发布框');
}
} else {
console.log('⚠️ 未找到写微博按钮');
}
await browser.close();
})();
@@ -0,0 +1,75 @@
const puppeteer = require('puppeteer-core');
const { getLaunchOptions } = require('../config/browser');
const fs = require('fs');
const delay = (ms) => new Promise(r => setTimeout(r, ms));
const TEST_CONTENT = '🤖 二维码登录测试成功!时间:' + new Date().toLocaleString('zh-CN') + ' #测试';
(async () => {
const browser = await puppeteer.launch(getLaunchOptions());
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900 });
// 访问主页
await page.goto('https://weibo.com', { waitUntil: 'networkidle2' });
await delay(3000);
console.log('🔗 URL:', page.url());
console.log('📄 标题:', await page.title());
// 在页面内执行所有操作
const result = await page.evaluate(async (content) => {
// 找写微博按钮
const writeBtn = Array.from(document.querySelectorAll('button, a, div[role="button"]'))
.find(b => b.textContent && b.textContent.includes('写微博'));
if (!writeBtn) return { error: '未找到写微博按钮' };
// 点击
writeBtn.click();
await new Promise(r => setTimeout(r, 2000));
// 找发布框
const postBox = document.querySelector('textarea[placeholder*="有什么新鲜事"]') ||
document.querySelector('textarea');
if (!postBox) return { error: '未找到发布框' };
// 输入内容
postBox.click();
postBox.value = content;
postBox.dispatchEvent(new Event('input', { bubbles: true }));
await new Promise(r => setTimeout(r, 1000));
// 找发送按钮
const sendBtn = Array.from(document.querySelectorAll('button, a, div[role="button"]'))
.find(b => b.textContent && b.textContent.includes('发送') && !b.disabled);
if (!sendBtn) return { error: '未找到发送按钮' };
// 点击发送
sendBtn.click();
return { success: true, message: '已点击发送' };
}, TEST_CONTENT);
console.log('📝 执行结果:', result);
if (result.success) {
await delay(5000);
await page.screenshot({ path: '/tmp/weibo_qr_login/after_send_js.png' });
fs.copyFileSync('/tmp/weibo_qr_login/after_send_js.png', '/home/ubuntu/nanocode/audiobook-player/static/after_send_js.png');
// 验证
await page.goto('https://weibo.com/u/me?tabtype=weibo', { waitUntil: 'networkidle2' });
await delay(3000);
await page.screenshot({ path: '/tmp/weibo_qr_login/final_verify.png' });
fs.copyFileSync('/tmp/weibo_qr_login/final_verify.png', '/home/ubuntu/nanocode/audiobook-player/static/final_verify.png');
console.log('✅ 流程完成!');
console.log('📸 截图: http://129.211.173.87:8899/screenshots/final_verify.png');
}
await browser.close();
})();
+204
View File
@@ -0,0 +1,204 @@
/**
* 微博登录助手 - 步骤1: 获取验证码
*/
const puppeteer = require('puppeteer-core');
const { getLaunchOptions } = require('../config/browser');
const fs = require('fs');
const PHONE = process.argv[2] || '18688929976';
const SCREENSHOT_DIR = '/tmp/weibo_login';
// 延迟函数
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
// 确保截图目录存在
if (!fs.existsSync(SCREENSHOT_DIR)) {
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
}
async function weiboLoginStep1() {
console.log('🌐 正在打开微博登录页面...');
const browser = await puppeteer.launch({
...getLaunchOptions(),
headless: true,
});
try {
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900 });
// 打开微博
await page.goto('https://weibo.com', {
waitUntil: 'networkidle2',
timeout: 60000,
});
console.log('✅ 页面加载完成');
await delay(3000);
// 保存初始页面截图
await page.screenshot({ path: `${SCREENSHOT_DIR}/01_initial.png` });
console.log('📸 初始页面已截图');
// 检查是否有登录框,如果没有可能需要点击登录按钮
const loginBtn = await page.$('a[href*="login"], .login, [node-type="loginBtn"], .W_btn_g');
if (loginBtn) {
const text = await page.evaluate(el => el.textContent, loginBtn);
console.log(`🔘 发现登录按钮: "${text?.trim()}",点击中...`);
await loginBtn.click();
await delay(3000);
await page.screenshot({ path: `${SCREENSHOT_DIR}/02_login_modal.png` });
}
// 查找手机号输入框
console.log('📱 查找手机号输入框...');
const phoneSelectors = [
'input[name="username"]',
'input[name="phone"]',
'input[placeholder*="手机号"]',
'input[placeholder*="邮箱"]',
'input[type="tel"]',
'input[type="text"]',
'#loginname',
'.W_input',
'input[node-type="username"]',
'input[action-type="text_copy"]',
];
let phoneInput = null;
let usedSelector = '';
for (const sel of phoneSelectors) {
const inputs = await page.$$(sel);
for (const input of inputs) {
const type = await page.evaluate(el => el.type, input);
const placeholder = await page.evaluate(el => el.placeholder, input);
console.log(` 检查: ${sel} (type=${type}, placeholder=${placeholder})`);
if (!phoneInput) {
phoneInput = input;
usedSelector = sel;
}
}
if (phoneInput) break;
}
if (!phoneInput) {
console.log('⚠️ 尝试获取所有输入框...');
const allInputs = await page.$$('input');
console.log(` 找到 ${allInputs.length} 个输入框`);
if (allInputs.length > 0) {
phoneInput = allInputs[0];
}
}
if (!phoneInput) {
throw new Error('未找到输入框');
}
console.log(`✅ 找到输入框: ${usedSelector}`);
// 清空并输入手机号
await phoneInput.click({ clickCount: 3 }); // 全选
await phoneInput.type(PHONE, { delay: 50 });
console.log(`✅ 手机号已输入: ${PHONE}`);
await page.screenshot({ path: `${SCREENSHOT_DIR}/03_phone_entered.png` });
// 查找"获取验证码"按钮
console.log('🔍 查找"获取验证码"按钮...');
const codeBtnSelectors = [
'a[action-type="get_code"]',
'a[node-type="btn_code"]',
'.W_btn_g',
'.get_code',
'a:has-text("获取")',
'a:has-text("验证码")',
'button:has-text("获取")',
'button:has-text("验证码")',
];
let codeBtn = null;
for (const sel of codeBtnSelectors) {
try {
codeBtn = await page.$(sel);
if (codeBtn) {
const text = await page.evaluate(el => el.textContent, codeBtn);
console.log(` 找到按钮: "${text?.trim()}" (${sel})`);
break;
}
} catch (e) {}
}
// 如果没找到,尝试查找所有按钮/链接
if (!codeBtn) {
console.log(' 尝试查找所有按钮...');
const allBtns = await page.$$('a, button');
for (const btn of allBtns) {
const text = await page.evaluate(el => el.textContent, btn);
if (text && (text.includes('获取') || text.includes('验证码') || text.includes('code'))) {
console.log(` 候选: "${text.trim()}"`);
if (!codeBtn && text.includes('获取')) {
codeBtn = btn;
}
}
}
}
if (codeBtn) {
const btnText = await page.evaluate(el => el.textContent, codeBtn);
console.log(`\n🖱️ 点击按钮: "${btnText?.trim()}"`);
await codeBtn.click();
console.log('✅ 已点击"获取验证码"');
// 等待几秒钟,让短信发送
await delay(5000);
await page.screenshot({ path: `${SCREENSHOT_DIR}/04_code_requested.png` });
// 检查是否有提示信息
const tips = await page.$$eval('.W_layer, .W_tips, .tip, .error, .info', els =>
els.map(el => el.textContent?.trim()).filter(Boolean)
);
if (tips.length > 0) {
console.log('\n💬 页面提示:', tips.slice(0, 3));
}
} else {
console.log('⚠️ 未找到验证码按钮,请查看截图手动确认');
}
// 保存当前页面HTML用于分析
const html = await page.content();
fs.writeFileSync(`${SCREENSHOT_DIR}/page.html`, html);
console.log('\n' + '='.repeat(60));
console.log('📋 步骤1完成,当前状态:');
console.log(` 手机号: ${PHONE}`);
console.log(` 验证码: ⏳ 等待发送...`);
console.log('\n📸 截图文件:');
fs.readdirSync(SCREENSHOT_DIR).forEach(f => {
console.log(` - ${SCREENSHOT_DIR}/${f}`);
});
console.log('\n📱 请检查手机,收到验证码后告诉我');
console.log('格式: 验证码 123456');
console.log('='.repeat(60));
// 保存浏览器状态,等待下一步
await page.screenshot({ path: `${SCREENSHOT_DIR}/05_waiting_code.png` });
// 保持浏览器实例供后续使用(通过文件记录WSEndpoint)
const wsEndpoint = browser.wsEndpoint();
fs.writeFileSync(`${SCREENSHOT_DIR}/browser_ws.txt`, wsEndpoint);
console.log('\n⏳ 浏览器保持连接,等待下一步...');
// 保持运行
await new Promise(() => {});
} catch (error) {
console.error('❌ 操作失败:', error.message);
await browser.close();
process.exit(1);
}
}
weiboLoginStep1().catch(console.error);
@@ -0,0 +1,133 @@
/**
* 微博登录助手 V2 - 直接访问登录页面
*/
const puppeteer = require('puppeteer-core');
const { getLaunchOptions } = require('../config/browser');
const fs = require('fs');
const PHONE = process.argv[2] || '18688929976';
const SCREENSHOT_DIR = '/tmp/weibo_login';
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
if (!fs.existsSync(SCREENSHOT_DIR)) {
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
}
async function weiboLogin() {
console.log('🌐 正在打开微博登录页面...');
const browser = await puppeteer.launch({
...getLaunchOptions(),
headless: true,
});
try {
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900 });
// 直接访问登录页面
await page.goto('https://weibo.com/newlogin?tabtype=weibo', {
waitUntil: 'networkidle2',
timeout: 60000,
});
console.log('✅ 登录页面加载完成');
await delay(3000);
await page.screenshot({ path: `${SCREENSHOT_DIR}/login_page.png` });
console.log('📸 已截图');
// 查找并点击短信登录选项卡
const tabs = await page.$$('div[role="tab"], .tab, [class*="tab"]');
console.log(`找到 ${tabs.length} 个选项卡`);
for (const tab of tabs) {
const text = await page.evaluate(el => el.textContent, tab);
console.log(` 选项卡: "${text?.trim()}"`);
if (text && text.includes('短信')) {
console.log('🖱️ 点击短信登录选项卡');
await tab.click();
await delay(2000);
break;
}
}
await page.screenshot({ path: `${SCREENSHOT_DIR}/after_tab.png` });
// 查找手机号输入框
console.log('📱 查找手机号输入框...');
const phoneInput = await page.$('input[type="tel"], input[placeholder*="手机号"], input[name="phone"]');
if (phoneInput) {
await phoneInput.type(PHONE, { delay: 50 });
console.log(`✅ 手机号已输入: ${PHONE}`);
} else {
// 尝试所有输入框
const inputs = await page.$$('input');
console.log(`尝试 ${inputs.length} 个输入框...`);
for (const input of inputs) {
const placeholder = await page.evaluate(el => el.placeholder, input);
const type = await page.evaluate(el => el.type, input);
console.log(` input type=${type} placeholder="${placeholder}"`);
if (type === 'tel' || (placeholder && placeholder.includes('手机'))) {
await input.type(PHONE, { delay: 50 });
console.log(`✅ 手机号已输入: ${PHONE}`);
break;
}
}
}
await page.screenshot({ path: `${SCREENSHOT_DIR}/phone_entered.png` });
// 查找获取验证码按钮
console.log('🔍 查找"获取验证码"按钮...');
const buttons = await page.$$('button, a, div[role="button"]');
let codeBtn = null;
for (const btn of buttons) {
const text = await page.evaluate(el => el.textContent, btn);
if (text && (text.includes('获取') || text.includes('验证码') || text.includes('code'))) {
console.log(` 找到按钮: "${text.trim()}"`);
codeBtn = btn;
break;
}
}
if (codeBtn) {
console.log('🖱️ 点击获取验证码按钮...');
await codeBtn.click();
console.log('✅ 已发送验证码请求');
await delay(3000);
await page.screenshot({ path: `${SCREENSHOT_DIR}/code_requested.png` });
} else {
console.log('⚠️ 未找到验证码按钮');
}
console.log('\n' + '='.repeat(60));
console.log('📋 步骤完成,当前状态:');
console.log(` 手机号: ${PHONE}`);
console.log(` 验证码: ⏳ 等待发送...`);
console.log('\n📸 截图文件:');
fs.readdirSync(SCREENSHOT_DIR).forEach(f => {
console.log(` - ${SCREENSHOT_DIR}/${f}`);
});
console.log('\n📱 请检查手机 18688929976');
console.log('收到验证码后告诉我,格式: 验证码 123456');
console.log('='.repeat(60));
// 保存浏览器状态供后续使用
const cookies = await page.cookies();
fs.writeFileSync(`${SCREENSHOT_DIR}/cookies_step1.json`, JSON.stringify(cookies, null, 2));
// 保持运行等待验证码
await new Promise(() => {});
} catch (error) {
console.error('❌ 错误:', error.message);
await browser.close();
process.exit(1);
}
}
weiboLogin().catch(console.error);
@@ -0,0 +1,140 @@
/**
* 扫码登录后发送测试微博
*/
const puppeteer = require('puppeteer-core');
const { getLaunchOptions } = require('../config/browser');
const fs = require('fs');
const SCREENSHOT_DIR = '/tmp/weibo_qr_login';
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function postAfterQR() {
console.log('🌐 启动浏览器...');
const browser = await puppeteer.launch({
...getLaunchOptions(),
headless: true,
});
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900 });
try {
// 访问微博主页验证登录
console.log('🔄 访问微博主页验证登录...');
await page.goto('https://weibo.com', { waitUntil: 'networkidle2', timeout: 60000 });
await delay(3000);
const currentUrl = page.url();
const title = await page.title();
console.log(`🔗 URL: ${currentUrl}`);
console.log(`📄 标题: ${title}`);
await page.screenshot({ path: `${SCREENSHOT_DIR}/logged_in_home.png` });
fs.copyFileSync(`${SCREENSHOT_DIR}/logged_in_home.png`, `/home/ubuntu/nanocode/audiobook-player/static/logged_in_home.png`);
// 检查是否已登录(看有没有"写微博"按钮)
const allBtns = await page.$$('button, a');
let hasWriteBtn = false;
for (const btn of allBtns) {
const text = await page.evaluate(el => el.textContent, btn);
if (text?.includes('写微博')) {
hasWriteBtn = true;
break;
}
}
if (hasWriteBtn) {
console.log('✅ 检测到"写微博"按钮,登录成功!');
} else {
console.log('⚠️ 未检测到"写微博"按钮,可能还在登录页');
}
// 尝试发送测试微博
console.log('\n📝 准备发送测试微博...');
const TEST_CONTENT = '🤖 二维码登录测试成功!时间:' + new Date().toLocaleString('zh-CN');
// 点击"写微博"
for (const btn of allBtns) {
const text = await page.evaluate(el => el.textContent, btn);
if (text?.includes('写微博')) {
console.log('🖱️ 点击"写微博"...');
await btn.click();
break;
}
}
await delay(2000);
await page.screenshot({ path: `${SCREENSHOT_DIR}/compose_opened.png` });
// 查找发布框
let postBox = await page.$('textarea[placeholder*="有什么新鲜事"]');
if (!postBox) {
const textareas = await page.$$('textarea');
if (textareas.length > 0) postBox = textareas[0];
}
if (postBox) {
await postBox.click();
await delay(500);
await postBox.type(TEST_CONTENT, { delay: 30 });
console.log('✍️ 已输入:', TEST_CONTENT);
await delay(1000);
await page.screenshot({ path: `${SCREENSHOT_DIR}/content_typed.png` });
fs.copyFileSync(`${SCREENSHOT_DIR}/content_typed.png`, `/home/ubuntu/nanocode/audiobook-player/static/content_typed.png`);
// 查找发送按钮
let sendBtn = null;
const allBtns2 = await page.$$('button, a, div[role="button"]');
for (const btn of allBtns2) {
const text = await page.evaluate(el => el.textContent, btn);
if (text?.includes('发送')) {
sendBtn = btn;
console.log(`🖱️ 找到发送按钮: "${text.trim()}"`);
break;
}
}
if (sendBtn) {
// 检查按钮是否可用
const isEnabled = await page.evaluate(el => !el.disabled, sendBtn);
console.log(`📊 按钮状态: ${isEnabled ? '可用' : '禁用'}`);
console.log('🚀 点击发送...');
await sendBtn.click();
await delay(5000);
await page.screenshot({ path: `${SCREENSHOT_DIR}/after_send.png` });
fs.copyFileSync(`${SCREENSHOT_DIR}/after_send.png`, `/home/ubuntu/nanocode/audiobook-player/static/after_send.png`);
console.log('✅ 发送按钮已点击!');
// 验证是否发送成功
await page.goto('https://weibo.com/u/me?tabtype=weibo', { waitUntil: 'networkidle2' });
await delay(3000);
await page.screenshot({ path: `${SCREENSHOT_DIR}/verify.png` });
fs.copyFileSync(`${SCREENSHOT_DIR}/verify.png`, `/home/ubuntu/nanocode/audiobook-player/static/verify.png`);
console.log('📸 已截图验证页面');
console.log('\n🎉 测试微博发送流程已完成!');
} else {
console.log('⚠️ 未找到发送按钮');
}
} else {
console.log('⚠️ 未找到发布框');
}
} catch (error) {
console.error('❌ 错误:', error.message);
await page.screenshot({ path: `${SCREENSHOT_DIR}/error_post.png` });
fs.copyFileSync(`${SCREENSHOT_DIR}/error_post.png`, `/home/ubuntu/nanocode/audiobook-player/static/error_post.png`);
} finally {
await browser.close();
}
}
postAfterQR().catch(console.error);
@@ -0,0 +1,199 @@
/**
* 使用 Cookie 登录微博 V2 - 直接访问发布页面
*/
const puppeteer = require('puppeteer-core');
const { getLaunchOptions } = require('../config/browser');
const fs = require('fs');
const COOKIE_FILE = '/home/ubuntu/weibo_cookies.txt';
const TEST_CONTENT = '这是一条来自自动化脚本的测试微博 🤖 #测试 #自动化 ' + new Date().toLocaleString();
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function postWeibo() {
console.log('🌐 正在启动浏览器...');
const browser = await puppeteer.launch({
...getLaunchOptions(),
headless: true,
});
try {
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900 });
// 读取 Cookie
console.log('🍪 正在加载 Cookie...');
const cookieContent = fs.readFileSync(COOKIE_FILE, 'utf-8');
const cookies = JSON.parse(cookieContent);
console.log(`📋 加载了 ${cookies.length} 个 Cookie`);
// 先访问微博并设置 cookie
await page.goto('https://weibo.com', { waitUntil: 'domcontentloaded', timeout: 60000 });
// 设置 Cookie
for (const cookie of cookies) {
try {
await page.setCookie({
name: cookie.name,
value: cookie.value,
domain: cookie.domain,
path: cookie.path || '/',
secure: cookie.secure || false,
httpOnly: cookie.httpOnly || false,
...(cookie.expirationDate && { expires: Math.floor(cookie.expirationDate) })
});
} catch (e) {}
}
console.log('✅ Cookie 设置完成');
// 访问个人主页验证登录
console.log('🔄 访问个人主页验证登录...');
await page.goto('https://weibo.com/u/me', { waitUntil: 'networkidle2', timeout: 60000 });
await delay(3000);
await page.screenshot({ path: '/tmp/weibo_login/profile_page.png' });
console.log('📸 已截图个人主页');
// 获取页面标题和URL
const title = await page.title();
const url = page.url();
console.log(`📄 页面标题: ${title}`);
console.log(`🔗 当前URL: ${url}`);
// 检查是否在登录页面
if (url.includes('login') || title.includes('登录')) {
console.log('❌ Cookie 已过期,需要重新登录');
return;
}
// 尝试打开发布器
console.log('\n📝 尝试打开发布器...');
await page.goto('https://weibo.com/u/me?tabtype=weibo', { waitUntil: 'networkidle2', timeout: 60000 });
await delay(3000);
// 查找发布框 - 尝试多种选择器
const selectors = [
'textarea[title="微博内容"]',
'.W_input',
'[node-type="textEl"]',
'textarea[placeholder*="有什么新鲜事"]',
'textarea[placeholder*="想说什么"]',
'[class*="publish"] textarea',
'[class*="post"] textarea',
];
let postBox = null;
for (const sel of selectors) {
postBox = await page.$(sel);
if (postBox) {
console.log(`✅ 找到发布框: ${sel}`);
break;
}
}
// 如果没找到,尝试点击"发布"按钮
if (!postBox) {
console.log('🖱️ 尝试点击发布按钮...');
// 通过文本内容查找按钮
const allLinks = await page.$$('a, button, div[role="button"]');
for (const link of allLinks) {
const text = await page.evaluate(el => el.textContent, link);
if (text && (text.includes('发布') || text.includes('发微博'))) {
console.log(` 找到发布按钮: "${text.trim()}"`);
await link.click();
await delay(2000);
break;
}
}
// 再次查找发布框
for (const sel of selectors) {
postBox = await page.$(sel);
if (postBox) break;
}
}
if (postBox) {
console.log('✅ 准备发送微博...');
// 聚焦并输入
await postBox.click();
await delay(500);
await postBox.type(TEST_CONTENT, { delay: 30 });
console.log('✍️ 已输入:', TEST_CONTENT);
await delay(1000);
await page.screenshot({ path: '/tmp/weibo_login/before_send.png' });
// 查找发送按钮
let sendBtn = null;
// 先尝试标准选择器
const sendSelectors = [
'a[title="发布"]',
'[action-type="submit"]',
'[node-type="submit"]',
'.W_btn_a',
'button[type="submit"]',
];
for (const sel of sendSelectors) {
sendBtn = await page.$(sel);
if (sendBtn) {
const text = await page.evaluate(el => el.textContent, sendBtn);
console.log(` 找到发送按钮: "${text?.trim()}" (${sel})`);
break;
}
}
// 如果没找到,通过文本搜索
if (!sendBtn) {
const allBtns = await page.$$('a, button, div[role="button"]');
for (const btn of allBtns) {
const text = await page.evaluate(el => el.textContent, btn);
if (text && (text.includes('发送') || text.includes('发布'))) {
console.log(` 通过文本找到按钮: "${text.trim()}"`);
sendBtn = btn;
break;
}
}
}
if (sendBtn) {
await sendBtn.click();
console.log('🚀 已点击发送!');
await delay(5000);
await page.screenshot({ path: '/tmp/weibo_login/after_send.png' });
console.log('📸 已截图保存结果');
// 检查是否发送成功
const success = await page.$eval('.success, .W_tips, [class*="success"]', el => el.textContent).catch(() => null);
if (success) {
console.log('✅ 发送结果:', success);
}
console.log('\n🎉 测试微博发送流程完成!');
} else {
console.log('⚠️ 未找到发送按钮,请查看 /tmp/weibo_login/before_send.png');
}
} else {
console.log('⚠️ 未找到发布框');
await page.screenshot({ path: '/tmp/weibo_login/no_postbox.png' });
}
} catch (error) {
console.error('❌ 错误:', error.message);
try {
await page.screenshot({ path: '/tmp/weibo_login/error.png' });
} catch (e) {}
} finally {
await browser.close();
}
}
postWeibo().catch(console.error);
@@ -0,0 +1,143 @@
/**
* 使用 Cookie 登录微博并发送测试微博
*/
const puppeteer = require('puppeteer-core');
const { getLaunchOptions } = require('../config/browser');
const fs = require('fs');
const COOKIE_FILE = '/home/ubuntu/weibo_cookies.txt';
const TEST_CONTENT = '这是一条来自自动化脚本的测试微博 🤖 #测试 #自动化';
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function postWeibo() {
console.log('🌐 正在启动浏览器...');
const browser = await puppeteer.launch({
...getLaunchOptions(),
headless: true,
});
try {
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900 });
// 读取并设置 Cookie
console.log('🍪 正在加载 Cookie...');
const cookieContent = fs.readFileSync(COOKIE_FILE, 'utf-8');
let cookies;
try {
cookies = JSON.parse(cookieContent);
// 如果是数组格式,直接使用
if (!Array.isArray(cookies)) {
// 如果是对象格式,转换为数组
cookies = Object.entries(cookies).map(([name, value]) => ({
name,
value,
domain: '.weibo.com',
path: '/'
}));
}
} catch (e) {
// 尝试解析为 name=value; 格式
cookies = cookieContent.split(';').map(pair => {
const [name, value] = pair.trim().split('=');
return { name, value, domain: '.weibo.com', path: '/' };
}).filter(c => c.name && c.value);
}
console.log(`📋 加载了 ${cookies.length} 个 Cookie`);
// 先访问微博主页,再设置 cookie
await page.goto('https://weibo.com', { waitUntil: 'networkidle2', timeout: 60000 });
await delay(2000);
// 设置 Cookie
for (const cookie of cookies) {
try {
// 确保必要的字段
const cookieToSet = {
name: cookie.name,
value: cookie.value,
domain: cookie.domain || '.weibo.com',
path: cookie.path || '/',
secure: cookie.secure || true,
httpOnly: cookie.httpOnly || false,
};
if (cookie.expirationDate) {
cookieToSet.expires = Math.floor(cookie.expirationDate);
}
await page.setCookie(cookieToSet);
} catch (e) {
// 忽略单个 cookie 设置错误
}
}
console.log('✅ Cookie 设置完成');
// 刷新页面,验证登录状态
console.log('🔄 刷新页面验证登录...');
await page.reload({ waitUntil: 'networkidle2', timeout: 60000 });
await delay(3000);
// 截图查看当前状态
await page.screenshot({ path: '/tmp/weibo_login/cookie_login_status.png' });
console.log('📸 已截图保存登录状态');
// 检查是否已登录(查找用户名或发布框)
const userName = await page.$eval('.user-name, .name, [class*="user"]', el => el.textContent).catch(() => null);
const postBox = await page.$('[class*="publish"], [class*="post"], textarea[class*="textarea"]').catch(() => null);
if (userName) {
console.log(`✅ 检测到用户名: ${userName.trim()}`);
}
if (postBox) {
console.log('✅ 找到发布框,准备发送微博...');
// 点击发布框
await postBox.click();
await delay(500);
// 输入内容
await postBox.type(TEST_CONTENT, { delay: 50 });
console.log('✍️ 已输入内容:', TEST_CONTENT);
// 查找发送按钮
const sendBtn = await page.$('[class*="send"], [class*="submit"], button:has-text("发送"), a:has-text("发送")').catch(() => null);
if (sendBtn) {
console.log('🖱️ 点击发送按钮...');
await sendBtn.click();
await delay(3000);
await page.screenshot({ path: '/tmp/weibo_login/after_post.png' });
console.log('📸 已截图保存发送结果');
console.log('\n✅ 测试微博发送完成!');
} else {
console.log('⚠️ 未找到发送按钮');
}
} else {
console.log('⚠️ 未找到发布框,可能未登录成功或页面结构不同');
// 尝试查找登录按钮
const loginBtn = await page.$('a:has-text("登录"), .login, [class*="login"]').catch(() => null);
if (loginBtn) {
console.log('❌ 检测到登录按钮,Cookie 可能已过期');
}
}
} catch (error) {
console.error('❌ 操作失败:', error.message);
await page.screenshot({ path: '/tmp/weibo_login/error.png' });
} finally {
await browser.close();
}
}
postWeibo().catch(console.error);
@@ -0,0 +1,183 @@
/**
* 微博二维码登录测试
* 1. 打开登录页,截取二维码
* 2. 等待用户扫码
* 3. 验证登录并发微博
*/
const puppeteer = require('puppeteer-core');
const { getLaunchOptions } = require('../config/browser');
const fs = require('fs');
const SCREENSHOT_DIR = '/tmp/weibo_qr_login';
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
// 确保目录存在
if (!fs.existsSync(SCREENSHOT_DIR)) {
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
}
async function weiboQRLogin() {
console.log('🌐 启动浏览器...');
const browser = await puppeteer.launch({
...getLaunchOptions(),
headless: true,
});
try {
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900 });
// 访问微博登录页
console.log('🔄 访问微博登录页...');
await page.goto('https://weibo.com/newlogin?tabtype=weibo', {
waitUntil: 'networkidle2',
timeout: 60000,
});
await delay(3000);
console.log('✅ 登录页加载完成');
// 截图 - 应该包含二维码
const qrScreenshot = `${SCREENSHOT_DIR}/qr_code.png`;
await page.screenshot({ path: qrScreenshot });
console.log(`📸 已截图: ${qrScreenshot}`);
// 检查页面是否有二维码元素
const qrSelectors = [
'img[src*="qr"]',
'[class*="qr"]',
'[class*="qrcode"]',
'canvas',
];
let qrFound = false;
for (const sel of qrSelectors) {
const el = await page.$(sel);
if (el) {
console.log(`✅ 找到二维码元素: ${sel}`);
qrFound = true;
break;
}
}
if (!qrFound) {
console.log('⚠️ 未明显找到二维码元素,但已截图整页');
}
console.log('\n' + '='.repeat(60));
console.log('📧 请查收邮件中的二维码截图');
console.log('📱 请使用微博 App 扫描二维码');
console.log('⏳ 等待 60 秒让您扫码...');
console.log('='.repeat(60) + '\n');
// 等待用户扫码
await delay(60000);
// 检查登录状态
console.log('🔍 检查登录状态...');
await page.reload({ waitUntil: 'networkidle2' });
await delay(3000);
const currentUrl = page.url();
const title = await page.title();
console.log(`🔗 当前URL: ${currentUrl}`);
console.log(`📄 页面标题: ${title}`);
// 截图当前状态
await page.screenshot({ path: `${SCREENSHOT_DIR}/after_scan.png` });
// 判断是否登录成功
const isLoggedIn = !currentUrl.includes('login') && !title.includes('登录');
if (isLoggedIn) {
console.log('✅ 登录成功!');
// 尝试发微博
console.log('\n📝 尝试发送测试微博...');
await postTestWeibo(page);
} else {
console.log('⏳ 可能还未扫码或扫码未完成');
console.log('💡 如果需要更多时间,请告诉我延长等待');
}
} catch (error) {
console.error('❌ 错误:', error.message);
await page.screenshot({ path: `${SCREENSHOT_DIR}/error.png` });
} finally {
await browser.close();
}
}
async function postTestWeibo(page) {
const TEST_CONTENT = '🤖 二维码登录测试 ' + new Date().toLocaleString('zh-CN');
try {
// 点击"写微博"
const allBtns = await page.$$('button, a, div[role="button"]');
for (const btn of allBtns) {
const text = await page.evaluate(el => el.textContent, btn);
if (text?.includes('写微博')) {
await btn.click();
console.log('🖱️ 点击"写微博"');
break;
}
}
await delay(2000);
// 查找发布框
let postBox = await page.$('textarea[placeholder*="有什么新鲜事"]');
if (!postBox) {
const textareas = await page.$$('textarea');
if (textareas.length > 0) postBox = textareas[0];
}
if (postBox) {
await postBox.click();
await delay(500);
await postBox.type(TEST_CONTENT, { delay: 30 });
console.log('✍️ 已输入:', TEST_CONTENT);
await delay(1000);
// 查找发送按钮
let sendBtn = null;
const allBtns2 = await page.$$('button, a, div[role="button"]');
for (const btn of allBtns2) {
const text = await page.evaluate(el => el.textContent, btn);
if (text?.includes('发送')) {
sendBtn = btn;
break;
}
}
if (sendBtn) {
console.log('🚀 点击发送...');
await sendBtn.click();
await delay(5000);
await page.screenshot({ path: `${SCREENSHOT_DIR}/post_result.png` });
console.log('✅ 发送完成!');
// 验证
await page.goto('https://weibo.com/u/me?tabtype=weibo', { waitUntil: 'networkidle2' });
await delay(3000);
await page.screenshot({ path: `${SCREENSHOT_DIR}/verify_post.png` });
console.log('📸 已截图验证页面');
} else {
console.log('⚠️ 未找到发送按钮');
}
} else {
console.log('⚠️ 未找到发布框');
}
} catch (error) {
console.error('❌ 发微博失败:', error.message);
}
}
weiboQRLogin().catch(console.error);
@@ -0,0 +1,210 @@
/**
* 微博二维码登录测试 V2
* 1. 访问微博首页
* 2. 点击"登录/注册"按钮
* 3. 截取二维码
* 4. 等待扫码并验证
*/
const puppeteer = require('puppeteer-core');
const { getLaunchOptions } = require('../config/browser');
const fs = require('fs');
const SCREENSHOT_DIR = '/tmp/weibo_qr_login';
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
if (!fs.existsSync(SCREENSHOT_DIR)) {
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
}
async function weiboQRLogin() {
console.log('🌐 启动浏览器...');
const browser = await puppeteer.launch({
...getLaunchOptions(),
headless: true,
});
try {
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900 });
// 访问微博首页
console.log('🔄 访问微博首页...');
await page.goto('https://weibo.com', {
waitUntil: 'networkidle2',
timeout: 60000,
});
await delay(3000);
console.log('✅ 首页加载完成');
// 截图 - 首页状态
await page.screenshot({ path: `${SCREENSHOT_DIR}/homepage.png` });
// 查找并点击"登录"按钮
console.log('🔍 查找登录按钮...');
let loginBtn = null;
// 通过文本查找
const allLinks = await page.$$('a, button, div[role="button"]');
for (const link of allLinks) {
const text = await page.evaluate(el => el.textContent, link);
if (text && (text.trim() === '登录' || text.includes('登录/注册'))) {
console.log(`✅ 找到登录按钮: "${text.trim()}"`);
loginBtn = link;
break;
}
}
if (!loginBtn) {
console.log('⚠️ 通过文本未找到,尝试选择器...');
loginBtn = await page.$('a[href*="login"], .login, [node-type="loginBtn"]');
}
if (loginBtn) {
console.log('🖱️ 点击登录按钮...');
try {
await loginBtn.click();
} catch (e) {
// 如果点击失败,尝试 JavaScript 点击
console.log(' 普通点击失败,尝试 JS 点击...');
await page.evaluate(el => el.click(), loginBtn);
}
await delay(3000);
console.log('✅ 已点击登录');
} else {
console.log('❌ 未找到登录按钮,尝试直接访问登录链接');
await page.goto('https://weibo.com/newlogin', { waitUntil: 'networkidle2' });
await delay(3000);
}
// 截图 - 应该显示登录弹窗/页面
await page.screenshot({ path: `${SCREENSHOT_DIR}/login_page.png` });
console.log('📸 已截图登录页面');
// 检查是否有二维码
const qrSelectors = [
'img[src*="qr"]',
'[class*="qr"]',
'[class*="qrcode"]',
'canvas',
];
let qrFound = false;
for (const sel of qrSelectors) {
const el = await page.$(sel);
if (el) {
console.log(`✅ 找到二维码元素: ${sel}`);
qrFound = true;
break;
}
}
// 专门截图二维码区域
const qrScreenshot = `${SCREENSHOT_DIR}/qr_code_v2.png`;
await page.screenshot({ path: qrScreenshot });
console.log(`📸 已保存: ${qrScreenshot}`);
console.log('\n' + '='.repeat(60));
console.log('📧 请查看登录页面截图');
console.log('📱 请使用微博 App 扫描二维码');
console.log('⏳ 等待扫码...');
console.log('='.repeat(60) + '\n');
// 等待用户扫码
await delay(60000);
// 检查登录状态
console.log('🔍 检查登录状态...');
await page.reload({ waitUntil: 'networkidle2' });
await delay(3000);
const currentUrl = page.url();
const title = await page.title();
console.log(`🔗 当前URL: ${currentUrl}`);
console.log(`📄 页面标题: ${title}`);
await page.screenshot({ path: `${SCREENSHOT_DIR}/after_scan.png` });
// 判断是否登录成功
const isLoggedIn = !currentUrl.includes('login') && !title.includes('登录');
if (isLoggedIn) {
console.log('✅ 登录成功!');
// 尝试发微博
await postTestWeibo(page);
} else {
console.log('⏳ 可能还未扫码完成');
}
} catch (error) {
console.error('❌ 错误:', error.message);
try {
if (typeof page !== 'undefined') {
await page.screenshot({ path: `${SCREENSHOT_DIR}/error.png` });
}
} catch(e) {}
} finally {
await browser.close();
}
}
async function postTestWeibo(page) {
const TEST_CONTENT = '🤖 二维码登录测试 ' + new Date().toLocaleString('zh-CN');
try {
// 点击"写微博"
const allBtns = await page.$$('button, a, div[role="button"]');
for (const btn of allBtns) {
const text = await page.evaluate(el => el.textContent, btn);
if (text?.includes('写微博')) {
await btn.click();
console.log('🖱️ 点击"写微博"');
break;
}
}
await delay(2000);
// 查找发布框
let postBox = await page.$('textarea[placeholder*="有什么新鲜事"]');
if (!postBox) {
const textareas = await page.$$('textarea');
if (textareas.length > 0) postBox = textareas[0];
}
if (postBox) {
await postBox.click();
await delay(500);
await postBox.type(TEST_CONTENT, { delay: 30 });
console.log('✍️ 已输入:', TEST_CONTENT);
await delay(1000);
// 查找发送按钮
let sendBtn = null;
const allBtns2 = await page.$$('button, a, div[role="button"]');
for (const btn of allBtns2) {
const text = await page.evaluate(el => el.textContent, btn);
if (text?.includes('发送')) {
sendBtn = btn;
break;
}
}
if (sendBtn) {
console.log('🚀 点击发送...');
await sendBtn.click();
await delay(5000);
await page.screenshot({ path: `${SCREENSHOT_DIR}/post_result.png` });
console.log('✅ 发送完成!');
}
}
} catch (error) {
console.error('❌ 发微博失败:', error.message);
}
}
weiboQRLogin().catch(console.error);
+120
View File
@@ -0,0 +1,120 @@
/**
* 微博二维码登录 V3 - 直接访问登录地址
*/
const puppeteer = require('puppeteer-core');
const { getLaunchOptions } = require('../config/browser');
const fs = require('fs');
const SCREENSHOT_DIR = '/tmp/weibo_qr_login';
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
if (!fs.existsSync(SCREENSHOT_DIR)) {
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
}
async function weiboQRLogin() {
console.log('🌐 启动浏览器...');
const browser = await puppeteer.launch({
...getLaunchOptions(),
headless: true,
});
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900 });
try {
// 直接访问登录地址
const loginUrl = 'https://passport.weibo.com/sso/signin?entry=miniblog&source=miniblog&disp=popup&url=https%3A%2F%2Fweibo.com%2Fnewlogin%3Ftabtype%3Dweibo%26gid%3D102803%26openLoginLayer%3D0%26url%3Dhttps%3A%2F%2Fweibo.com%2F&from=weibopro';
console.log('🔄 访问登录页面...');
await page.goto(loginUrl, {
waitUntil: 'networkidle2',
timeout: 60000,
});
await delay(5000);
console.log('✅ 登录页面加载完成');
// 截图
await page.screenshot({ path: `${SCREENSHOT_DIR}/passport_login.png` });
console.log('📸 已截图登录页面');
// 检查页面内容
const title = await page.title();
console.log(`📄 页面标题: ${title}`);
console.log(`🔗 当前URL: ${page.url()}`);
// 查找二维码
const qrSelectors = [
'img[src*="qr"]',
'[class*="qr"]',
'[class*="qrcode"]',
'canvas',
'[class*="code"]',
];
let qrFound = false;
for (const sel of qrSelectors) {
const el = await page.$(sel);
if (el) {
console.log(`✅ 找到二维码元素: ${sel}`);
qrFound = true;
// 专门截图二维码元素
try {
await el.screenshot({ path: `${SCREENSHOT_DIR}/qr_only.png` });
console.log('📸 已单独截图二维码');
} catch(e) {}
break;
}
}
if (!qrFound) {
console.log('⚠️ 未明显找到二维码元素');
}
// 复制到 web 目录
const fs = require('fs');
const files = ['passport_login.png', 'qr_only.png'].filter(f => fs.existsSync(`${SCREENSHOT_DIR}/${f}`));
for (const file of files) {
fs.copyFileSync(`${SCREENSHOT_DIR}/${file}`, `/home/ubuntu/nanocode/audiobook-player/static/${file}`);
console.log(`📤 已上传: http://129.211.173.87:8899/screenshots/${file}`);
}
console.log('\n' + '='.repeat(60));
console.log('📱 请使用微博 App 扫描二维码');
console.log('⏳ 等待 60 秒...');
console.log('='.repeat(60) + '\n');
// 等待扫码
await delay(60000);
// 检查状态
console.log('🔍 检查登录状态...');
await page.reload({ waitUntil: 'networkidle2' });
await delay(3000);
console.log(`🔗 当前URL: ${page.url()}`);
await page.screenshot({ path: `${SCREENSHOT_DIR}/after_scan.png` });
fs.copyFileSync(`${SCREENSHOT_DIR}/after_scan.png`, `/home/ubuntu/nanocode/audiobook-player/static/after_scan.png`);
// 判断是否跳转成功
if (page.url().includes('weibo.com') && !page.url().includes('passport')) {
console.log('✅ 看起来登录成功了!');
} else {
console.log('⏳ 扫码可能未完成');
}
} catch (error) {
console.error('❌ 错误:', error.message);
await page.screenshot({ path: `${SCREENSHOT_DIR}/error.png` });
fs.copyFileSync(`${SCREENSHOT_DIR}/error.png`, `/home/ubuntu/nanocode/audiobook-player/static/error.png`);
} finally {
await browser.close();
}
}
weiboQRLogin().catch(console.error);
@@ -0,0 +1,177 @@
/**
* 微博发送 V3 - 带详细错误检查
*/
const puppeteer = require('puppeteer-core');
const { getLaunchOptions } = require('../config/browser');
const fs = require('fs');
const COOKIE_FILE = '/home/ubuntu/weibo_cookies.txt';
const TEST_CONTENT = '🤖 自动化测试 ' + Date.now();
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
async function postWeibo() {
console.log('🌐 启动浏览器...');
const browser = await puppeteer.launch({
...getLaunchOptions(),
headless: true,
});
try {
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900 });
// 监听控制台日志
page.on('console', msg => {
if (msg.type() === 'error') {
console.log(' [页面错误]', msg.text());
}
});
// 加载 Cookie
console.log('🍪 加载 Cookie...');
const cookies = JSON.parse(fs.readFileSync(COOKIE_FILE, 'utf-8'));
await page.goto('https://weibo.com', { waitUntil: 'domcontentloaded' });
for (const c of cookies) {
try {
await page.setCookie({
name: c.name,
value: c.value,
domain: c.domain,
path: c.path || '/'
});
} catch (e) {}
}
// 访问主页
console.log('🔄 访问微博主页...');
await page.goto('https://weibo.com', { waitUntil: 'networkidle2' });
await delay(3000);
// 点击"写微博"
console.log('🖱️ 点击"写微博"...');
const allBtns = await page.$$('button, a, div[role="button"]');
for (const btn of allBtns) {
const text = await page.evaluate(el => el.textContent, btn);
if (text?.includes('写微博')) {
await btn.click();
console.log(' 已点击');
break;
}
}
await delay(2000);
await page.screenshot({ path: '/tmp/weibo_login/v3_compose.png' });
// 查找发布框
console.log('📝 查找发布框...');
let postBox = await page.$('textarea[placeholder*="有什么新鲜事"]');
if (!postBox) {
const textareas = await page.$$('textarea');
console.log(` 找到 ${textareas.length} 个 textarea`);
if (textareas.length > 0) {
postBox = textareas[0];
}
}
if (!postBox) {
throw new Error('未找到发布框');
}
// 输入内容
await postBox.click();
await delay(500);
await postBox.type(TEST_CONTENT, { delay: 30 });
console.log('✍️ 已输入:', TEST_CONTENT);
await delay(1000);
await page.screenshot({ path: '/tmp/weibo_login/v3_typed.png' });
// 查找发送按钮
console.log('🔍 查找发送按钮...');
let sendBtn = null;
let sendText = '';
const allBtns2 = await page.$$('button, a, div[role="button"]');
for (const btn of allBtns2) {
const text = await page.evaluate(el => el.textContent, btn);
if (text?.includes('发送') || text?.includes('发布')) {
sendBtn = btn;
sendText = text.trim();
break;
}
}
if (!sendBtn) {
throw new Error('未找到发送按钮');
}
console.log(` 找到按钮: "${sendText}"`);
// 检查按钮是否可点击
const isEnabled = await page.evaluate(el => {
return !el.disabled && !el.getAttribute('disabled');
}, sendBtn);
console.log(` 按钮状态: ${isEnabled ? '可用' : '禁用'}`);
// 点击前截图
await page.screenshot({ path: '/tmp/weibo_login/v3_before_click.png' });
// 点击发送
console.log('🚀 点击发送...');
await sendBtn.click();
// 等待并检查页面变化
console.log('⏳ 等待响应...');
await delay(5000);
// 检查是否有错误提示
const errorMsg = await page.$eval('.error, .W_layer, .tips, [class*="error"]', el => el.textContent).catch(() => null);
if (errorMsg) {
console.log('⚠️ 页面提示:', errorMsg);
}
// 检查当前URL
const currentUrl = page.url();
console.log('🔗 当前URL:', currentUrl);
// 截图
await page.screenshot({ path: '/tmp/weibo_login/v3_after_send.png' });
console.log('📸 已截图');
// 检查最新微博
await page.goto('https://weibo.com/u/me?tabtype=weibo', { waitUntil: 'networkidle2' });
await delay(3000);
const posts = await page.evaluate(() => {
const items = Array.from(document.querySelectorAll('[class*="card"], [class*="item"]'));
return items.slice(0, 2).map(item => {
const text = item.textContent || '';
return text.substring(0, 100);
});
});
console.log('\n📱 最新微博:');
posts.forEach((p, i) => console.log(` [${i+1}] ${p.substring(0, 80)}...`));
if (posts.some(p => p.includes('自动化测试'))) {
console.log('\n✅ 发送成功!');
} else {
console.log('\n❌ 未找到刚发的微博,发送可能失败了');
}
} catch (error) {
console.error('❌ 错误:', error.message);
try {
await page.screenshot({ path: '/tmp/weibo_login/v3_error.png' });
} catch(e) {}
} finally {
await browser.close();
}
}
postWeibo().catch(console.error);
@@ -0,0 +1,130 @@
/**
* 微博登录 - 分步骤执行
* Step 1: 打开登录页,截图二维码
* Step 2: 等待用户扫码
* Step 3: 保存登录后的 Cookie
*/
const puppeteer = require('puppeteer-core');
const { getLaunchOptions } = require('../config/browser');
const fs = require('fs');
const SCREENSHOT_DIR = '/tmp/weibo_step_login';
const COOKIE_FILE = '/home/ubuntu/weibo_cookies_qr.json';
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
// 确保目录存在
if (!fs.existsSync(SCREENSHOT_DIR)) {
fs.mkdirSync(SCREENSHOT_DIR, { recursive: true });
}
async function stepByStepLogin() {
console.log('🌐 启动浏览器...');
const browser = await puppeteer.launch({
...getLaunchOptions(),
headless: true,
});
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 900 });
try {
// ===== STEP 1: 打开登录页并截图 =====
const loginUrl = 'https://passport.weibo.com/sso/signin?entry=miniblog&source=miniblog&disp=popup&url=https%3A%2F%2Fweibo.com%2Fnewlogin%3Ftabtype%3Dweibo%26gid%3D102803%26openLoginLayer%3D0%26url%3Dhttps%3A%2F%2Fweibo.com%2F&from=weibopro';
console.log('\n📍 Step 1: 打开登录页面...');
await page.goto(loginUrl, {
waitUntil: 'networkidle2',
timeout: 60000,
});
await delay(5000);
console.log('✅ 登录页已加载');
// 截图二维码
const qrScreenshot = `${SCREENSHOT_DIR}/qr_step1.png`;
await page.screenshot({ path: qrScreenshot, fullPage: false });
console.log(`📸 已截图: ${qrScreenshot}`);
// 复制到 web 目录
fs.copyFileSync(qrScreenshot, `/home/ubuntu/nanocode/audiobook-player/static/qr_step1.png`);
console.log('📤 已上传: http://129.211.173.87:8899/screenshots/qr_step1.png');
console.log('\n' + '='.repeat(60));
console.log('🛑 请扫码!');
console.log('📱 打开微博 App → 扫一扫');
console.log('🔗 http://129.211.173.87:8899/screenshots/qr_step1.png');
console.log('⏳ 扫码完成后告诉我,我会继续保存 Cookie');
console.log('='.repeat(60) + '\n');
// 保存浏览器实例,等待用户指令
// 我们会保持浏览器打开,但需要等待用户回复
// 测试:等待一段时间检查是否已扫码
let loggedIn = false;
let attempts = 0;
const maxAttempts = 60; // 最多等待60次,每次2秒 = 120秒
while (!loggedIn && attempts < maxAttempts) {
await delay(2000);
attempts++;
// 检查当前URL
const currentUrl = page.url();
// 如果URL变了,不再包含 passport,说明可能登录成功
if (!currentUrl.includes('passport.weibo.com')) {
console.log(`\n✅ 检测到页面跳转!URL: ${currentUrl}`);
loggedIn = true;
break;
}
// 每10秒提示一次
if (attempts % 5 === 0) {
console.log(`⏳ 等待扫码中... (${attempts * 2}秒)`);
}
}
if (loggedIn) {
// ===== STEP 3: 保存 Cookie =====
console.log('\n📍 Step 3: 保存登录 Cookie...');
const cookies = await page.cookies();
fs.writeFileSync(COOKIE_FILE, JSON.stringify(cookies, null, 2));
console.log(`💾 Cookie 已保存到: ${COOKIE_FILE}`);
console.log(`📊 共 ${cookies.length} 个 Cookie`);
// 显示关键 Cookie
const keyCookies = cookies.filter(c =>
['SUB', 'SUBP', 'ALF', 'SCF', 'SSOLoginState'].includes(c.name)
);
console.log('\n🔑 关键 Cookie:');
keyCookies.forEach(c => {
console.log(` - ${c.name}: ${c.value.substring(0, 30)}...`);
});
// 验证登录状态
await page.goto('https://weibo.com/u/me', { waitUntil: 'networkidle2' });
await delay(3000);
const verifyScreenshot = `${SCREENSHOT_DIR}/logged_in.png`;
await page.screenshot({ path: verifyScreenshot });
fs.copyFileSync(verifyScreenshot, `/home/ubuntu/nanocode/audiobook-player/static/logged_in.png`);
console.log('\n📸 验证截图: http://129.211.173.87:8899/screenshots/logged_in.png');
console.log('\n✅ 全部完成!Cookie 已保存,可以发邮件给你');
} else {
console.log('\n⏱️ 等待超时(120秒),可能未扫码');
}
} catch (error) {
console.error('❌ 错误:', error.message);
} finally {
await browser.close();
}
}
stepByStepLogin().catch(console.error);