a
This commit is contained in:
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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();
|
||||
})();
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
Reference in New Issue
Block a user