Files
kurihada 7661a723ea 修复图文发布:创作中心导航、图文标签切换及表单选择器
- 发布前先访问主站建立 session,再跳转创作中心(直接导航会 401)
- 切换「上传图文」标签:跳过 style.left=-9999px 的隐藏副本,不用 getBoundingClientRect
- 修复上传缩略图选择器:.upload-item img → .img-upload-area .img-container
- 修复标题输入框:#note-title → input.d-text[placeholder*="标题"]
- 修复内容编辑器:#note-content → .tiptap.ProseMirror
- 修复发布按钮:.publishBtn → button.d-button:has-text("发布")
- 新增 debug-publish.ts 调试脚本
2026-03-02 01:08:03 +08:00

89 lines
3.6 KiB
TypeScript

import { chromium } from 'rebrowser-playwright';
import { readFileSync } from 'node:fs';
const COOKIE_FILE = `${process.env.HOME}/.social-mcp/xiaohongshu/cookies.json`;
async function main() {
const raw = JSON.parse(readFileSync(COOKIE_FILE, 'utf-8'));
const browser = await chromium.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu'] });
const ctx = await browser.newContext({ storageState: raw });
const page = await ctx.newPage();
console.log('Visiting main site...');
await page.goto('https://www.xiaohongshu.com/explore', { waitUntil: 'domcontentloaded' });
await page.waitForTimeout(2000);
// Find creator center link on the main site
const creatorLinks = await page.$$eval('a[href*="creator"]', els =>
els.map(el => ({ href: el.getAttribute('href'), text: el.textContent?.trim() })).slice(0, 5)
);
console.log('Creator links on main site:', creatorLinks);
// The creator link opens in a new tab — capture it
const [creatorPage] = await Promise.all([
ctx.waitForEvent('page'),
page.click('a[href*="creator.xiaohongshu.com/publish"]'),
]);
await creatorPage.waitForLoadState('domcontentloaded');
await creatorPage.waitForTimeout(3000);
console.log('\nCreator page URL:', creatorPage.url());
console.log('Creator page title:', await creatorPage.title());
console.log('Title:', await page.title());
console.log('URL:', page.url());
const pg = creatorPage;
// Switch to image tab — skip off-screen duplicate
const switched = await pg.$$eval('.creator-tab', (tabs) => {
for (const tab of tabs) {
if (!tab.textContent?.includes('图文')) continue;
const style = (tab as HTMLElement).style;
if (style.left && parseInt(style.left) < -100) continue;
const rect = tab.getBoundingClientRect();
if (rect.width === 0 && rect.height === 0) continue;
(tab as HTMLElement).click();
return true;
}
return false;
});
console.log('Switched to image tab:', switched);
await pg.waitForTimeout(1000);
// Set the file on the hidden input
const fileInput = await pg.waitForSelector('input[type="file"]', { state: 'attached', timeout: 10000 });
console.log('File input found, setting file...');
await fileInput.setInputFiles('/Users/xd/Downloads/IMG_1479.png');
console.log('File set. Waiting 5s for upload...');
await pg.waitForTimeout(5000);
// Check what appeared after upload
const allImgEls = await pg.$$eval('img', els =>
els.filter(el => el.src && !el.src.startsWith('data:') && el.offsetParent !== null)
.map(el => ({ src: el.src.slice(0, 80), cls: el.className }))
);
console.log('\nVisible imgs after upload:', allImgEls);
// Check fixed selector
const imgContainers = await pg.$$('.img-upload-area .img-container');
console.log('\n.img-upload-area .img-container count:', imgContainers.length);
// Verify updated selectors
const imgContainerCount = await pg.$$('.img-upload-area .img-container').then(els => els.length);
console.log('\n[selector check] .img-upload-area .img-container:', imgContainerCount);
const titleInput = await pg.$('input.d-text[placeholder*="标题"]');
console.log('[selector check] title input:', !!titleInput);
const contentEditor = await pg.$('.tiptap.ProseMirror');
console.log('[selector check] content editor:', !!contentEditor);
const publishBtn = await pg.$('button.d-button:has-text("发布")');
console.log('[selector check] publish button:', !!publishBtn, publishBtn ? await publishBtn.textContent() : '');
await browser.close();
}
main().catch(e => { console.error(e); process.exit(1); });