13
$\begingroup$

Is there a common method of grabbing an SE post or answer here as a formatted notebook so that you can immediately run it, instead of copy-pasting the code blocks?

I've heard SSE uses MarkdownSharp and people have written converters, so this must have been asked and answered before....

How nice with this be:

SemanticImport["https://mathematica.stackexchange.com/questions/57706", "Notebook"]
$\endgroup$
1
12
$\begingroup$

Here is an approach, not battle tested, YMMV. It depends on the new body_markdown parameter in the SE API responses. From there we can use whatever MD->NB tool we like; there are tons of those out in the wild.

Here's the code (we have to do a bit of HTML entity clean up, sadly)

ClearAll[mseMarkdown, cleanHTML];
$msefilterMap = <|
   "questions" -> "!9YdnSJ*_T",
   "answers" -> "!9_bDE(S6I"
   |>;
buildMSEUrl[
   id_, 
   postType : "questions" | "answers",
   version : _Real : 2.2, 
   filter : _String | Automatic : Automatic
   ] :=
  URLBuild[
   <|
    "Scheme" -> "https",
    "Domain" -> "api.stackexchange.com",
    "Path" -> {ToString[version], postType, ToString[id]},
    "Query" -> {"site" -> "mathematica", 
      "filter" -> Replace[filter, Automatic -> $msefilterMap[postType]]}
    |>
   ];
mseMarkdown[
   id_, 
   postType : "questions" | "answers",
   version : _Real : 2.2, filter : _String | Automatic : Automatic] :=
  
  Block[{resp, url, md},
   url = buildMSEUrl[id, postType, version, filter];
   resp = Import[url, "RawJSON"];
   md = #["body_markdown"] & /@ resp["items"];
   If[! ListQ[md],
    If[resp["quota_remaining"] == 0,
     mseMarkdown::QuotaExceeded = 
      "StackExchange API quota exceeded, authenticate for more";
     Message[mseMarkdown::QuotaExceeded];
     $Failed,
 md
 ],
If[StringQ[#], cleanHTML[#], #] & /@ md
]
   ];
$cleanEnts =
  Block[{ents = Templating`HTML`PackagePrivate`$EscapeHTMLEntities},
   ents = Association[ents];
   ents = AssociationThread[Values[ents], Keys[ents]];
   Normal[ents]
   ];
cleanHTML[string_] :=
 StringReplace[string, $cleanEnts]

I made sure to accept a comma-separated list of IDs since using a lot of IDs (up to 100) at once only counts as one call against your quota. You can be smarter about API calls if you want to.

And now applying this to your question

mdText = mseMarkdown[243919, "questions"]

{"Is there a common method of grabbing an SE post or answer here as a formatted \
notebook so that you can immediately run it, instead of copy-pasting the code \
blocks?
 
 
 
 I've heard SSE uses MarkdownSharp and people have written converters, so this \
must have been asked and answered before....
 
 
 
 How nice with this be: 
 
 
 
     SemanticImport[\"https://mathematica.stackexchange.com/questions/57706\", \
\"Notebook\"]
 
 
 
 
 
 "}

and now use whatever MD converter you want, I'm using the one I built for my own webdev purposes

<< BTools`Web`

mdNB = mdText // Map[MarkdownToNotebook]

{Notebook[{Cell[
    "Is there a common method of grabbing an SE post or answer here as a \
formatted notebook so that you can immediately run it, instead of copy-pasting \
the code blocks?
    ", "Text", "Markdown"], 
   Cell["I've heard SSE uses MarkdownSharp and people have written converters, \
so this must have been asked and answered before....
    ", "Text", "Markdown"], Cell["How nice with this be: 
    
    ", "Text", "Markdown"], 
   Cell[BoxData[
     RowBox[{"SemanticImport", "[", 
       RowBox[{"\"https://mathematica.stackexchange.com/questions/57706\"", ",",
          " ", "\"Notebook\""}], "]"}]], "Code", "Markdown"]}, {}]}

finally here's what it looks like

enter image description here

Here's the previous answer, just to show that the quality of the MD converter really matters (mine ain't great)

oldAnsMD = mseMarkdown[3537, "answers"];

oldAnsMD[[1]] // MarkdownToNotebook // CreateDocument

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.