{"id":632,"date":"2026-02-28T08:33:00","date_gmt":"2026-02-28T06:33:00","guid":{"rendered":"https:\/\/vittrup-graversen.dk\/?p=632"},"modified":"2026-03-28T12:10:39","modified_gmt":"2026-03-28T10:10:39","slug":"saadan-genererede-jeg-et-word-cloud-wordpress-blog-med-rust-og-python","status":"publish","type":"post","link":"https:\/\/vittrup-graversen.dk\/index.php\/2026\/02\/28\/saadan-genererede-jeg-et-word-cloud-wordpress-blog-med-rust-og-python\/","title":{"rendered":"S\u00e5dan genererede jeg et word cloud WordPress-blog med Rust og Python"},"content":{"rendered":"\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1600\" height=\"1000\" src=\"https:\/\/vittrup-graversen.dk\/wp-content\/uploads\/2026\/02\/blog-wordcloud.png\" alt=\"Word cloud genereret fra vittrup-graversen.dk \u2014 toppet af claude, agent og code\" class=\"wp-image-631\" srcset=\"https:\/\/vittrup-graversen.dk\/wp-content\/uploads\/2026\/02\/blog-wordcloud.png 1600w, https:\/\/vittrup-graversen.dk\/wp-content\/uploads\/2026\/02\/blog-wordcloud-300x188.png 300w, https:\/\/vittrup-graversen.dk\/wp-content\/uploads\/2026\/02\/blog-wordcloud-1024x640.png 1024w, https:\/\/vittrup-graversen.dk\/wp-content\/uploads\/2026\/02\/blog-wordcloud-768x480.png 768w, https:\/\/vittrup-graversen.dk\/wp-content\/uploads\/2026\/02\/blog-wordcloud-1536x960.png 1536w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><\/figure>\n\n\n\n<p>Jeg faldt over et lille Rust-baseret CLI-tool lavet af <a href=\"https:\/\/github.com\/simonw\/research\/tree\/main\/rust-wordcloud\" target=\"_blank\" rel=\"noopener\">Simon Willison<\/a> \u2014 en af de mest produktive open source-udviklere jeg f\u00f8lger. Toolet genererer word clouds fra ren tekst, og med ~46.000 ord fra 67 blogindl\u00e6g p\u00e5 vittrup-graversen.dk l\u00e5 opgaven ligefor: Hvad er egentlig bloggens DNA? Hvad handler den her blog <em>virkelig<\/em> om?<\/p>\n\n\n\n<p>Svaret, som du kan se ovenfor, er ikke overraskende \u2014 men det er alligevel lidt sjovt at se det sort p\u00e5 hvidt (eller rettere: farverigt p\u00e5 m\u00f8rk baggrund): &#8220;claude&#8221; dominerer med 420 forekomster. Efterfulgt af &#8220;agent&#8221; (227x), &#8220;code&#8221; (220x), &#8220;agenter&#8221; (155x) og &#8220;anthropic&#8221; (129x). En AI-blog, der skriver om AI og AI-agenter, har alts\u00e5 AI i blodet. Who would have thought\ud83d\ude04<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Fra kildekode til word cloud WordPress i tre trin<\/h2>\n\n\n\n<p>F\u00f8rste skridt var at bygge toolet. Simon Willisons repo er et Rust-workspace, s\u00e5 det er bare:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>git clone https:\/\/github.com\/simonw\/research\ncd research\/rust-wordcloud\ncargo build --release<\/code><\/pre>\n\n\n\n<p>Det tager et par minutter, men s\u00e5 har man en lynhurtig <code>wordcloud<\/code>-binary. N\u00e6ste skridt: Hent al tekst fra bloggen. Det er nemt med WordPress REST API \u2014 et lille Python-script paginerer sig igennem alle posts og samler <code>content.rendered<\/code> i en stor tekstfil:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import requests, re, html\n\nposts, page = &#91;], 1\nwhile True:\n    r = requests.get(f\"https:\/\/vittrup-graversen.dk\/wp-json\/wp\/v2\/posts\",\n                     params={\"per_page\": 100, \"page\": page, \"_fields\": \"content\"})\n    if r.status_code != 200 or not r.json():\n        break\n    for p in r.json():\n        text = re.sub(r'&lt;&#91;^&gt;]+&gt;', ' ', p&#91;'content']&#91;'rendered'])\n        posts.append(html.unescape(text))\n    page += 1\n\nwith open(\"blog-text.txt\", \"w\") as f:\n    f.write(\"\n\".join(posts))<\/code><\/pre>\n\n\n\n<p>67 posts, ~46.000 ord. Fint.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Problemet med danske stopord \u2014 og l\u00f8sningen<\/h2>\n\n\n\n<p>Her kom f\u00f8rste forhindring. Simon Willisons tool filtrerer automatisk engelske stopord (&#8220;the&#8221;, &#8220;and&#8221;, &#8220;is&#8221; osv.), men den ved intet om dansk. F\u00f8rste fors\u00f8g gav mig et word cloud domineret af &#8220;det&#8221;, &#8220;til&#8221;, &#8220;p\u00e5&#8221;, &#8220;med&#8221;, &#8220;er&#8221;, &#8220;som&#8221; \u2014 alts\u00e5 det rene grammatiske st\u00f8j.<\/p>\n\n\n\n<p>L\u00f8sningen er enkel: Et Python-script der fjerner danske stopord inden teksten sendes til wordcloud-toolet. Jeg brugte <code>nltk<\/code>&#8216;s danske stopordsliste (plus et par ekstra som &#8220;ogs\u00e5&#8221;, &#8220;bare&#8221;, &#8220;meget&#8221;):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import nltk\nfrom nltk.corpus import stopwords\n\nnltk.download('stopwords', quiet=True)\nda_stops = set(stopwords.words('danish'))\nda_stops.update(&#91;'ogs\u00e5', 'bare', 'meget', 'n\u00e5r', 'hvor', 'hvad', 'kan'])\n\nwith open(\"blog-text.txt\") as f:\n    words = f.read().lower().split()\n\nfiltered = &#91;w for w in words if w.isalpha() and w not in da_stops and len(w) &gt;= 3]\n\nwith open(\"blog-text-filtered.txt\", \"w\") as f:\n    f.write(\" \".join(filtered))<\/code><\/pre>\n\n\n\n<p>Derefter er det bare at k\u00f8re wordcloud-toolet med lidt parametre til bredde, farver og antal ord:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>wordcloud blog-text-filtered.txt   -o blog-wordcloud.png   --width 1600   --height 1000   --max-words 150   --colors vibrant   --min-word-len 3<\/code><\/pre>\n\n\n\n<p>Under 2 sekunder. Rust er ret hurtig, for nu at sige det mildt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Hvad afsl\u00f8rte word cloud WordPress-analysen?<\/h2>\n\n\n\n<p>Resultatet er det billede du ser \u00f8verst. Og det er jo lidt meta: Jeg bruger Claude Code til at drive min blog om Claude Code og AI-agenter, og s\u00e5 genererer jeg et word cloud WordPress-analyse der viser&#8230; at jeg prim\u00e6rt skriver om Claude, agenter og AI. Cirklen er komplet.<\/p>\n\n\n\n<p>De \u00f8vrige topord er heller ikke overraskende: &#8220;model&#8221;, &#8220;data&#8221;, &#8220;system&#8221;, &#8220;tools&#8221;, &#8220;workflow&#8221;, &#8220;automation&#8221;. Det er en teknisk blog om agentic engineering, og det er pr\u00e6cis hvad ordene afspejler. Men det er alligevel sjovt at f\u00e5 det visualiseret \u2014 det giver et hurtigt, intuitivt overblik over temaerne, som man ikke helt f\u00e5r ved at l\u00e6se indholdsfortegnelsen.<\/p>\n\n\n\n<p>Hvis du vil lave det samme for din blog, er det overraskende enkelt. WordPress REST API er \u00e5bent for l\u00e6sning p\u00e5 de fleste installationer, og Simon Willisons tool er <a href=\"https:\/\/github.com\/simonw\/research\/tree\/main\/rust-wordcloud\" target=\"_blank\" rel=\"noopener\">frit tilg\u00e6ngeligt p\u00e5 GitHub<\/a>. Eneste &#8220;trick&#8221; er stopords-filtreringen, hvis du skriver p\u00e5 dansk (eller et andet ikke-engelsk sprog).<\/p>\n\n\n\n<p>Det minder lidt om den pointe Max Woolf n\u00e6vner i sin <a href=\"https:\/\/minimaxir.com\/2026\/02\/ai-agent-coding\/\" target=\"_blank\" rel=\"noopener\">artikel om AI agent coding<\/a> \u2014 at AI-tools i stigende grad er bedst, n\u00e5r du forst\u00e5r hvad de g\u00f8r under motorhjelmen. At bruge rust-wordcloud kr\u00e6ver ikke at du kan Rust, men du skal stadig forst\u00e5 stopords-problemet og l\u00f8se det selv. AI hj\u00e6lper; du t\u00e6nker.<\/p>\n\n\n\n<p>Vil du se mere om hvad Claude Code faktisk kan som coding-assistent, har jeg skrevet om det i <a href=\"https:\/\/vittrup-graversen.dk\/index.php\/2026\/02\/28\/claude-code-husker-nu-dine-rettelser-og-praeferencer-automatisk\/\">Claude Code husker nu dine rettelser og pr\u00e6ferencer automatisk<\/a> og <a href=\"https:\/\/vittrup-graversen.dk\/index.php\/2026\/02\/27\/anthropic-goer-claude-til-enterprise-infrastruktur-med-10-nye-cowork-plugins\/\">Anthropic g\u00f8r Claude til enterprise-infrastruktur<\/a>.<\/p>\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n<hr><p style=\"color:#888888\"><em>Denne artikel er skrevet i samarbejde med AI, og efterf\u00f8lgende redigeret af et rigtigt menneske \ud83d\ude42<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>S\u00e5dan genererede jeg et word cloud til min WordPress-blog med Rust og Python. En praktisk guide til datavisualisering.<\/p>\n","protected":false},"author":1,"featured_media":631,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[24],"tags":[23],"class_list":["post-632","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-agentic-engineering","tag-claudecode"],"acf":[],"_links":{"self":[{"href":"https:\/\/vittrup-graversen.dk\/index.php\/wp-json\/wp\/v2\/posts\/632","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vittrup-graversen.dk\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vittrup-graversen.dk\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vittrup-graversen.dk\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vittrup-graversen.dk\/index.php\/wp-json\/wp\/v2\/comments?post=632"}],"version-history":[{"count":2,"href":"https:\/\/vittrup-graversen.dk\/index.php\/wp-json\/wp\/v2\/posts\/632\/revisions"}],"predecessor-version":[{"id":1020,"href":"https:\/\/vittrup-graversen.dk\/index.php\/wp-json\/wp\/v2\/posts\/632\/revisions\/1020"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vittrup-graversen.dk\/index.php\/wp-json\/wp\/v2\/media\/631"}],"wp:attachment":[{"href":"https:\/\/vittrup-graversen.dk\/index.php\/wp-json\/wp\/v2\/media?parent=632"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vittrup-graversen.dk\/index.php\/wp-json\/wp\/v2\/categories?post=632"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vittrup-graversen.dk\/index.php\/wp-json\/wp\/v2\/tags?post=632"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}