X-Artikel-Veröffentlicher
Veröffentlichen Sie Markdown-Inhalte im X (Twitter) Artikel-Editor, wobei die Formatierung durch Rich-Text-Konvertierung erhalten bleibt.
Voraussetzungen
- Playwright MCP für Browser-Automatisierung
- Benutzer bei X mit Premium Plus-Abonnement angemeldet
- Python 3.9+ mit Abhängigkeiten:
- macOS:
pip install Pillow pyobjc-framework-Cocoa - Windows:
pip install Pillow pywin32 clip-util
- macOS:
- Für Mermaid-Diagramme:
npm install -g @mermaid-js/mermaid-cli
Skripte
Befindet sich in ~/.claude/skills/x-article-publisher/scripts/:
parse_markdown.py
Markdown parsen und strukturierte Daten extrahieren:
python parse_markdown.py <markdown_file> [--output json|html] [--html-only]
Gibt JSON zurück mit: title, cover_image, content_images, dividerse (mit block_index für Positionierung), html, total_blocks
copy_to_clipboard.py
Bild oder HTML in die System-Zwischenablage kopieren (plattformübergreifend):
# Bild kopieren (mit optionaler Komprimierung)
python copy_to_clipboard.py image /pfad/zum/bild.jpg [--quality 80]
# HTML für Rich-Text-Einfügen kopieren
python copy_to_clipboard.py html --file /pfad/zum/inhalt.html
table_to_image.py
Markdown-Tabelle in PNG-Bild konvertieren:
python table_to_image.py <eingabe.md> <ausgabe.png> [--scale 2]
Verwenden, wenn X Articles die native Tabellendarstellung nicht unterstützt oder für einheitliches Styling.
Vorverarbeitung (Optional)
Vor dem Veröffentlichen das Markdown nach Elementen durchsuchen, die konvertiert werden müssen:
Tabellen → PNG
# Tabelle in temporäre Datei extrahieren, dann konvertieren
python ~/.claude/skills/x-article-publisher/scripts/table_to_image.py /tmp/tabelle.md /tmp/tabelle.png
# Tabelle im Markdown ersetzen durch: 
Mermaid-Diagramme → PNG
# Mermaid-Block in .mmd-Datei extrahieren, dann konvertieren
mmdc -i /tmp/diagramm.mmd -o /tmp/diagramm.png -b white -s 2
# Mermaid-Block ersetzen durch: 
Trennlinien (---)
Trennlinien werden automatisch von parse_markdown.py erkannt und im bottomper-Array ausgegeben. Sie müssen über das Menü Einfügen > Trennlinie von X Articles eingefügt werden (HTML <hr>-Tags werden von X ignoriert).
Arbeitsablauf
Strategie: „先文后图后分割线“ (Text zuerst, Bilder zweitens, Trennlinien zuletzt)
Bei Artikeln mit Bildern und Trennlinien zuerst den GESAMTEN Textinhalt einfügen, dann Bilder und Trennlinien an den korrekten Positionen mithilfe des Block-Index einfügen.
- (Optional) Vorverarbeitung: Tabellen/Mermaid in Bilder konvertieren
- Markdown mit Python-Skript parsen → Titel, Bilder, Trennlinien mit block_index, HTML erhalten
- Zum X Articles-Editor navigieren
- Titelbild hochladen (erstes Bild)
- Titel ausfüllen
- HTML in die Zwischenablage kopieren (Python) → Mit Cmd+V einfügen
- Inhaltsbilder an den durch block_index angegebenen Positionen einfügen
- Trennlinien an den durch block_index angegebenen Positionen einfügen (über das Menü Einfügen > Trennlinie)
- Als Entwurf speichern (NIE automatisch veröffentlichen)
高效执行原则 (Effizienzrichtlinien)
Ziel: Wartezeiten zwischen Operationen minimieren, für ein reibungsloses automatisiertes Erlebnis.
1. Unnötiges browser_snapshot vermeiden
Die meisten Browser-Operationen (click, type, press_key usw.) enthalten den Seitenstatus im Ergebnis. Nicht nach jeder Operation separat browser_snapshot aufrufen, sondern direkt den von der Operation zurückgegebenen Seitenstatus verwenden.
❌ Falsche Vorgehensweise:
browser_click → browser_snapshot → analysieren → browser_click → browser_snapshot → ...
✅ Richtige Vorgehensweise:
browser_click → Seitenstatus aus Ergebnis abrufen → browser_click → ...
2. Unnötiges browser_wait_for vermeiden
browser_wait_for nur in folgenden Fällen verwenden:
- Warten auf den Abschluss des Bild-Uploads (
textGone="正在上传媒体") - Warten auf das initiale Laden der Seite (sehr selten)
Nicht browser_wait_for verwenden, um auf das Erscheinen von Schaltflächen oder Eingabefeldern zu warten – diese sind sofort verfügbar, sobald die Seite geladen ist.
3. Unabhängige Operationen parallel ausführen
Wenn zwei Operationen keine Abhängigkeiten voneinander haben, können mehrere Tools in derselben Nachricht parallel aufgerufen werden:
✅ Kann parallel ausgeführt werden:
- Titel ausfüllen (browser_type) + HTML in Zwischenablage kopieren (Bash)
- Markdown parsen und JSON generieren + HTML-Datei generieren
❌ Kann nicht parallel ausgeführt werden (hat Abhängigkeiten):
- Es muss zuerst auf „Erstellen“ geklickt werden, bevor das Titelbild hochgeladen werden kann
- Es muss zuerst der Inhalt eingefügt werden, bevor Bilder eingefügt werden können
4. Browser-Operationen nacheinander ausführen
Der von jeder Browser-Operation zurückgegebene Seitenstatus enthält alle benötigten Elementverweise. Diese Verweise direkt für den nächsten Schritt verwenden:
# Idealer Ablauf (jeder Schritt direkt, ohne zusätzliches Warten):
browser_navigate → „Erstellen“-Schaltfläche aus zurückgegebenem Status suchen → browser_click(create)
→ „Hochladen“-Schaltfläche aus zurückgegebenem Status suchen → browser_click(hochladen) → browser_file_upload
→ „Anwenden“-Schaltfläche aus zurückgegebenem Status suchen → browser_click(anwenden)
→ Titel-Eingabefeld aus zurückgegebenem Status suchen → browser_type(titel)
→ Editor anklicken → browser_press_key(Meta+v)
→ ...
5. Vorbereitende Arbeiten vorziehen
Vor Beginn der Browser-Operationen alle vorbereitenden Arbeiten abschließen:
- Markdown parsen, um JSON-Daten zu erhalten
- HTML-Datei in /tmp/ generieren
- Informationen zu Titel, Titelbild, Inhaltsbildern usw. notieren
So können die Browser-Operationen kontinuierlich ausgeführt werden, ohne zwischendurch für die Datenverarbeitung anhalten zu müssen.
Schritt 1: Markdown parsen (Python)
parse_markdown.py verwenden, um alle strukturierten Daten zu extrahieren:
python ~/.claude/skills/x-article-publisher/scripts/parse_markdown.py /pfad/zum/artikel.md
Ausgabe-JSON:
{
"title": "Artikel-Titel",
"cover_image": "/pfad/zum/ersten-bild.jpg",
"cover_exists": true,
"content_images": [
{"path": "/pfad/zum/img2.jpg", "original_path": "/md/verz/assets/img2.jpg", "exists": true, "block_index": 5, "after_text": "kontext..."},
{"path": "/pfad/zum/img3.jpg", "original_path": "/md/verz/assets/img3.jpg", "exists": true, "block_index": 12, "after_text": "weiterer..."}
],
"html": "<p>Inhalt...</p><h2>Abschnitt</h2>...",
"total_blocks": 45,
"missing_images": 0
}
Wichtige Felder:
block_index: Das Bild sollte NACH dem Blockelement an diesem Index eingefügt werden (0-basiert)total_blocks: Gesamtzahl der Blockelemente im HTMLafter_text: Nur für Referenz/Debugging, NICHT zur Positionierungexists: Ob die Bilddatei gefunden wurde (wenn false, wird der Upload fehlschlagen)original_path: Der aus dem Markdown aufgelöste Pfad (vor der automatischen Suche)path: Der tatsächlich zu verwendende Pfad (kann von original_path abweichen, wenn automatisch gesucht wurde)missing_images: Anzahl der nirgendwo gefundenen Bilder
HTML für die Zwischenablage in einer temporären Datei speichern:
python parse_markdown.py artikel.md --html-only > /tmp/artikel_html.html
Schritt 2: X Articles-Editor öffnen
Browser-Fehlerbehandlung
Bei Auftreten des Fehlers Error: Browser is already in use:
# Option 1: Browser zuerst schließen, dann neu öffnen
browser_close
browser_navigate: https://x.com/compose/articles
# Option 2: Wenn browser_close unwirksam ist (gesperrt), Benutzer auffordern, Chrome manuell zu schließen
# Option 3: Vorhandenen Tab verwenden, direkt dorthin navigieren
browser_tabs action=list # Vorhandene Tabs anzeigen
browser_navigate: https://x.com/compose/articles # Im aktuellen Tab navigieren
Beste Praxis: Vor jedem Start mit browser_tabs action=list den Status überprüfen, um das Erstellen unnötiger leerer Tabs zu vermeiden.
Zum Editor navigieren
browser_navigate: https://x.com/compose/articles
Wichtig: Nach dem Laden der Seite wird die Entwurfsliste angezeigt, nicht der Editor. Daher:
- Warten, bis die Seite vollständig geladen ist:
browser_snapshotverwenden, um den Seitenstatus zu überprüfen - Sofort auf die Schaltfläche „create“ klicken: Nicht auf Elemente des Editors wie „Titel hinzufügen“ warten, diese erscheinen erst nach dem Klicken auf „create“
- Warten, bis der Editor geladen ist: Nach dem Klicken auf „create“ auf das Erscheinen der Editor-Elemente warten
# 1. Zur Seite navigieren
browser_navigate: https://x.com/compose/articles
# 2. Seiten-Snapshot abrufen, „create“-Schaltfläche finden
browser_snapshot
# 3. Auf die Schaltfläche „create“ klicken (normalerweise ist ref etwa "create" oder hat ein create-Label)
browser_click: element="create button", ref=<create_button_ref>
# 4. Der Editor sollte jetzt geöffnet sein; mit dem Hochladen des Titelbilds usw. fortfahren
Hinweis: Nicht browser_wait_for text="添加标题" verwenden, um auf das Laden der Seite zu warten, da dieser Text erst nach dem Klicken auf „create“ erscheint und zu einem Timeout führen würde.
Falls eine Anmeldung erforderlich ist, den Benutzer auffordern, sich manuell anzumelden.
Schritt 3: Titelbild hochladen
- Auf die Schaltfläche „添加照片或视频“ klicken
- browser_file_upload mit dem Pfad des Titelbilds (aus der JSON-Ausgabe) verwenden
- Überprüfen, ob das Bild hochgeladen wurde
Schritt 4: Titel ausfüllen
- Textfeld mit Platzhalter „添加标题“ finden
- browser_type verwenden, um den Titel einzugeben (aus der JSON-Ausgabe)
Schritt 5: Textinhalt einfügen (Python-Zwischenablage)
HTML mithilfe von Python in die System-Zwischenablage kopieren, dann einfügen:
# HTML in die Zwischenablage kopieren
python ~/.claude/skills/x-article-publisher/scripts/copy_to_clipboard.py html --file /tmp/artikel_html.html
Dann im Browser:
browser_click auf Editor-Textfeld
browser_press_key: Meta+v
Dadurch bleibt die gesamte Rich-Text-Formatierung erhalten (H2, fett, Links, Listen).
Schritt 6: Inhaltsbilder einfügen (Textsuche zur Positionierung)
Empfohlene Methode: Die after_text-Textsuche zur Positionierung verwenden, die intuitiver und zuverlässiger ist als block_index.
Positionierungsprinzip
Das Feld after_text jedes Bildes enthält den Endtext des vorherigen Absatzes (maximal 80 Zeichen). Im Editor nach dem Absatz suchen, der diesen Text enthält, darauf klicken und dann das Bild einfügen.
Vorgehen
Für jedes Inhaltsbild (aus dem content_images-Array) in absteigender Reihenfolge von block_index:
# 1. Bild in die Zwischenablage kopieren (mit Komprimierung)
python ~/.claude/skills/x-article-publisher/scripts/copy_to_clipboard.py image /pfad/zum/img.jpg --quality 85
# 2. Im browser_snapshot nach dem Absatz suchen, der after_text enthält
# Die ref dieses Absatzes finden
# 3. Auf den Absatz klicken, der after_text enthält
browser_click: element="Absatz mit Zieltext", ref=<paragraph_ref>
# 4. **Wichtiger Schritt**: End-Taste drücken, um den Cursor an das Zeilenende zu bewegen
# Dieser Schritt ist sehr wichtig! Vermeidet, dass durch Klicken auf einen Link im Absatz die Position verschoben wird
browser_press_key: End
# 5. Bild einfügen
browser_press_key: Meta+v
# 6. Auf den Upload warten (nur textGone verwenden, keinen Zeitparameter)
browser_wait_for textGone="正在上传媒体"
Warum die End-Taste drücken?
Problem: Wenn ein Absatz einen Link enthält (z. B. [Linktext](https://raw.githubusercontent.com/wshuyi/x-article-publisher-skill/main/url)), kann das Klicken auf den Absatz Folgendes auslösen:
- Ein Popup zum Bearbeiten des Links
- Den Cursor innerhalb des Links positionieren, nicht am Ende des Absatzes
Lösung: Nach dem Klicken auf den Absatz sofort die End-Taste drücken:
- Stellt sicher, dass der Cursor ans Ende des Absatzes bewegt wird
- Vermeidet Störungen durch Links
- Das Bild wird korrekt nach diesem Absatz eingefügt
Positionierungsstrategie
In der von browser_snapshot zurückgegebenen Struktur nach Schlüsselwörtern aus after_text suchen:
textbox [ref=editor]:
generic [ref=p1]:
- StaticText: "元旦假期我在家里翻手机相册..." # Wenn after_text diesen Text enthält, auf p1 klicken
heading [ref=h1]:
- StaticText: "演示"
generic [ref=p2]:
- StaticText: "这东西到底有多省事儿?"
- link [ref=link1]: "Claude Code" # Hinweis: Absätze können Links enthalten
...
Beispiel für umgekehrtes Einfügen
Bei 3 Bildern mit block_index 5, 12, 27:
- Zuerst das Bild mit block_index=27 einfügen (after_text-Suche + End + Einfügen)
- Dann das Bild mit block_index=12 einfügen
- Zuletzt das Bild mit block_index=5 einfügen
Vom Größten zum Kleinsten einfügen vermeidet Positionsverschiebungen.
Schritt 6.5: Trennlinien einfügen (über das Menü)
Wichtig: ----Trennlinien in Markdown können nicht über das HTML-<hr>-Tag eingefügt werden (X Articles ignoriert es). Sie müssen über das Menü „Einfügen“ von X Articles eingefügt werden.
Vorgehen
Für jede Trennlinie (aus dem bottomper-Array) in umgekehrter Reihenfolge von block_index:
# 1. Auf das Blockelement an der Position block_index klicken
browser_click auf das Element an Position block_index im Editor
# 2. Menü „Einfügen“ öffnen (Schaltfläche „添加媒体“ / Medien hinzufügen)
browser_click auf die Schaltfläche "Insert" oder "添加媒体"
# 3. Auf den Menüpunkt „Trennlinie“ klicken
browser_click auf den Menüpunkt "Divider" oder "分割线"
# Die Trennlinie wird an der Cursorposition eingefügt
Reihenfolge mit Bildern
Es wird empfohlen, zuerst alle Bilder und dann alle Trennlinien einzufügen. Beide in der Reihenfolge vom größten block_index zum kleinsten:
- Alle Bilder einfügen (beginnend mit dem größten block_index)
- Alle Trennlinien einfügen (beginnend mit dem größten block_index)
Schritt 7: Entwurf speichern
- Überprüfen, ob der Inhalt eingefügt wurde (Wortzähler-Anzeige prüfen)
- Entwurf wird automatisch gespeichert, oder bei Bedarf auf die Schaltfläche „Speichern“ klicken
- Auf „预览“ (Vorschau) klicken, um die Formatierung zu überprüfen
- Melden: „Entwurf gespeichert. Bitte manuell überprüfen und veröffentlichen.“
Wichtige Regeln
- NIE veröffentlichen – Nur als Entwurf speichern
- Erstes Bild = Titelbild – Das erste Bild als Titelbild hochladen
- Rich-Text-Konvertierung – Markdown vor dem Einfügen immer in HTML konvertieren
- Zwischenablage-API verwenden – Über die Zwischenablage einfügen, um die Formatierung zu erhalten
- Block-Index-Positionierung – block_index für die präzise Platzierung von Bildern/Trennlinien verwenden
- Umgekehrte Reihenfolge beim Einfügen – Bilder und Trennlinien vom höchsten zum niedrigsten block_index einfügen
- H1-Titelbehandlung – H1 wird nur als Titel verwendet und nicht in den Textkörper aufgenommen
- Trennlinien über Menü – Markdown-
---muss über das Menü Einfügen > Trennlinie eingefügt werden (HTML-<hr>wird ignoriert)
Unterstützte Formatierungen
| Element | Unterstützung | Hinweise |
|---|---|---|
H2 (##) | Nativ | Abschnittsüberschriften |
Fett (**) | Nativ | Starke Betonung |
Kursiv (*) | Nativ | Betonung |
Links ([](https://raw.githubusercontent.com/wshuyi/x-article-publisher-skill/main/url)) | Nativ | Hyperlinks |
| Geordnete Listen | Nativ | 1. 2. 3. |
| Ungeordnete Listen | Nativ | - Aufzählungspunkte |
Blockzitate (>) | Nativ | Zitierter Text |
| Codeblöcke | Konvertiert | → Blockzitate |
| Tabellen | Konvertiert | → PNG-Bilder (table_to_image.py verwenden) |
| Mermaid | Konvertiert | → PNG-Bilder (mmdc verwenden) |
Trennlinien (---) | Menü einfügen | → Einfügen > Trennlinie |
Beispielablauf
Benutzer: „/pfad/zum/artikel.md auf X veröffentlichen“
# Schritt 1: Markdown parsen
python ~/.claude/skills/x-article-publisher/scripts/parse_markdown.py /pfad/zum/artikel.md > /tmp/artikel.json
python ~/.claude/skills/x-article-publisher/scripts/parse_markdown.py /pfad/zum/artikel.md --html-only > /tmp/artikel_html.html
- Zu https://x.com/compose/articles navigieren
- Titelbild hochladen (browser_file_upload nur für das Titelbild)
- Titel ausfüllen (aus JSON:
title) - HTML kopieren und einfügen:
Dann: browser_press_key Meta+vpython ~/.claude/skills/x-article-publisher/scripts/copy_to_clipboard.py html --file /tmp/artikel_html.html - Für jedes Inhaltsbild in umgekehrter Reihenfolge von block_index:
python copy_to_clipboard.py image /pfad/zum/img.jpg --quality 85- Auf das Blockelement an Position
block_indexklicken - browser_press_key Meta+v
- Warten, bis der Upload abgeschlossen ist
- Auf das Blockelement an Position
- In der Vorschau überprüfen
- „Entwurf gespeichert. Bitte manuell überprüfen und veröffentlichen.“
Bewährte Methoden
Warum block_index statt Textvergleich?
- Präzise Positionierung: Unabhängig vom Textinhalt, auch bei ähnlichen Textstellen wird die richtige Position gefunden
- Zuverlässigkeit: Der Index ist deterministisch und wird nicht durch ähnliche Texte verwechselt
- Einfaches Debugging:
after_textbleibt zur manuellen Überprüfung erhalten
Warum Python statt JavaScript im Browser?
- Lokale Verarbeitung zuverlässiger: Python greift direkt auf die System-Zwischenablage zu, ohne Einschränkungen durch die Browser-Sandbox
- Bildkomprimierung: Bilder vor dem Upload komprimieren (--quality 85), um die Upload-Zeit zu verkürzen
- Code-Wiederverwendung: Die Skripte bleiben unverändert, die Konvertierungslogik muss nicht jedes Mal neu geschrieben werden
- Einfaches Debugging: Skripte können einzeln getestet werden, Probleme sind leicht zu identifizieren
Wartestrategie
Wichtige Erkenntnis: Das browser_wait_for von Playwright MCP wartet zuerst time Sekunden und überprüft dann die Bedingung, anstatt zu pollen!
// Tatsächlich ausgeführter Code:
await new Promise(f => setTimeout(f, time * 1000)); // Zuerst feste Wartezeit
await page.getByText("xxx").waitFor({ state: 'hidden' }); // Dann überprüfen
Richtige Verwendung:
- ✅ Nur
textGoneverwenden, ohnetime: Playwright selbstständig pollen lassen - ✅ Nur
timeverwenden: Feste Wartezeit in Sekunden - ❌
textGoneundtimegleichzeitig verwenden: Zuerst time Sekunden warten, dann überprüfen, Zeitverschwendung
# Empfohlen: Nur textGone verwenden, damit es automatisch auf das Erfüllen der Bedingung wartet
browser_wait_for textGone="正在上传媒体"
# Oder: Mit browser_snapshot den Status pollen
# Nach jeder Operation den zurückgegebenen Seitenstatus überprüfen, kein zusätzliches Warten erforderlich
Effizienz beim Bildeinfügen
Die Browser-Operationen pro Bild wurden von 5 auf 2 Schritte reduziert:
- Alt: Klicken → Medien hinzufügen → Medien → Foto hinzufügen → file_upload
- Neu: Auf Absatz klicken → Meta+v
Titelbild vs. Inhaltsbilder
- Titelbild: browser_file_upload verwenden (weil es eine spezielle Upload-Schaltfläche gibt)
- Inhaltsbilder: Python-Zwischenablage + Einfügen verwenden (effizienter)
Fehlerbehebung
MCP-Verbindungsprobleme
Wenn Playwright MCP-Tools nicht verfügbar sind (Fehler No such tool available oder Not connected):
Option 1: MCP neu verbinden (empfohlen)
/mcp-Befehl ausführen, playwright auswählen, Restart auswählen
Option 2: Restprozesse bereinigen und neu verbinden
# Alle restlichen playwright-Prozesse beenden
pkill -f "mcp-server-playwright"
pkill -f "@playwright/mcp"
# Dann /mcp ausführen, um die Verbindung wiederherzustellen
Konfigurationsdatei: ~/.claude/mcp_servers.json
Browser-Fehlerbehandlung
Bei Auftreten des Fehlers Error: Browser is already in use:
# Option 1: Browser zuerst schließen, dann neu öffnen
browser_close
browser_navigate: https://x.com/compose/articles
# Option 2: Chrome-Prozess beenden
pkill -f "Chrome.*--remote-debugging"
# Dann neu navigieren
Falsche Bildposition
Wenn die Bildposition nicht korrekt ist (insbesondere beim Klicken auf Absätze mit Links):
Ursache: Beim Klicken auf den Absatz wird möglicherweise versehentlich der Link aktiviert, was zu einer falschen Cursorposition führt
Lösung: Nach dem Klicken unbedingt die End-Taste drücken, um den Cursor an das Zeilenende zu bewegen
# Korrekter Ablauf
1. browser_click auf den Zielabsatz klicken
2. browser_press_key: End # Wichtiger Schritt!
3. browser_press_key: Meta+v # Bild einfügen
4. browser_wait_for textGone="正在上传媒体"
Bildpfad nicht gefunden
Wenn Bilder mit relativem Pfad im Markdown nicht gefunden werden (z. B. ./assets/image.png befindet sich tatsächlich an einem anderen Ort):
Automatische Suche: Das Skript durchsucht automatisch die folgenden Pfade in dieser Reihenfolge:
- Der ursprüngliche relative Pfad
- Das Verzeichnis der Quelldatei
- Das Verzeichnis „assets“ zusammen mit der Quelldatei
- Benachbarte Verzeichnisse
Manuelle Angabe: Wenn die automatische Suche fehlschlägt, kann das Bild über die Option --image-path angegeben werden.

