Как получить доступ к API Stackru из Mathematica
На днях мне стало интересно, есть ли у Stackru API-интерфейс, к которому я могу получить доступ из Mathematica, и, очевидно, он имеет: "Сохранение аннотаций графика"
Какой лучший способ получить данные из Stackru в Mathematica? Sjoerd использовал информацию, чтобы сделать заговор. Я заинтересован в добавлении связанных с SO уведомлений в закрепленную ячейку, которую я храню в своих записных книжках, чтобы я мог знать, когда будут обновления или ответы, не покидая Mathematica.
2 ответа
По многочисленным просьбам, код для генерации топ-10 SO-ответчиков строит (кроме аннотаций) с использованием SO API (это довольно аккуратный и полный API; там много вкусностей. Также легко - посмотрите мой код).
Обновление: добавлен ключ приложения, чтобы гарантировать, что код лучше взаимодействует с SO-API (более высокая ежедневная ограничение вызовов). Пожалуйста, используйте его только для этого приложения.
Апрель 2011
Август 2011
ММА 8 версия! Версия MMA7 дальше вниз
getRepChanges[userID_Integer] :=
Module[{totalChanges},
totalChanges =
"total" /.
Import["http://api.stackru.com/1.1/users/" <>
ToString[userID] <> "/reputation?key=NgVJ4Y6vFkuF-oqI-eOvOw&fromdate=0&pagesize=1&page=1",
"JSON"
];
Join @@
Table[
"rep_changes" /.
Import["http://api.stackru.com/1.1/users/" <>
ToString[userID] <>
"/reputation?key=NgVJ4Y6vFkuF-oqI-eOvOw&fromdate=0&pagesize=100&page="
<> ToString[page],
"JSON"
],
{page, 1, Ceiling[totalChanges/100]}
]
]
topAnswerers =
({"display_name","user_id", "email_hash"} /. #) & /@
("user" /.
("top_users" /.
Import[
"http://api.stackru.com/1.1/tags/mathematica/top-answerers/all-time",
"JSON"
]
)
)
topAnswerers = {#, #2,
Import["http://www.gravatar.com/avatar/" <> #3 <> ".jpg?s=36&d=identicon&d=identicon"]
} & @@@ topAnswerers
repChangesTopUsers =
Table[
repChange =
ReleaseHold[
(
Hold[
{
DateList["on_date" + AbsoluteTime["January 1, 1970"]],
"positive_rep" - "negative_rep"
}
] /. #
) & /@ getRepChanges[userID]
] // Sort;
accRepChange = {repChange[[All, 1]],Accumulate[repChange[[All, 2]]]}\[Transpose],
{userID, topAnswerers[[All, 2]]}
];
pl = DateListLogPlot[
Tooltip @@@
Take[({repChangesTopUsers, Row /@ topAnswerers[[All, {3, 1}]]}\[Transpose]),
10], Joined -> True, Mesh -> None, ImageSize -> 1000,
PlotRange -> {All, {10, All}},
BaseStyle -> {FontFamily -> "Arial-Bold", FontSize -> 16},
DateTicksFormat -> {"MonthNameShort", " ", "Year"},
GridLines -> {True, None},
FrameLabel -> (Style[#, FontSize -> 18] & /@ {"Date", "Reputation",
"Top-10 answerers", ""})]
РЕДАКТИРОВАТЬ
Обратите внимание, что вы можете построить график до 20 включительно, изменив значение в функции Take. Вскоре он становится занятым.
Пытался улучшить читабельность кода разметки. Я боюсь, что это приведет к появлению некоторых паразитных мест при копировании.
РЕДАКТИРОВАТЬ
Размер страницы обратно на 100 элементов / страница ==> меньшее количество вызовов API Обратите внимание, что первым вызовом API является определение количества сообщений, которые пользователь имеет. Эти данные присутствуют независимо от размера страницы, поэтому желательно, чтобы они были небольшими (10 или около того, возможно 1, не проверялось). Затем данные извлекаются на последовательных страницах, пока не будет достигнута последняя страница. Вы можете использовать максимальный размер страницы (100) для этого. Просто позаботьтесь о том, чтобы максимальное количество страниц в цикле корректировалось соответствующим образом.
РЕДАКТИРОВАТЬ: лучше код ММА 7 (пт 22 апреля)
MMA 7 не выполняет импорт JSON, поэтому вместо этого я выполняю импорт текста, за которым следует простой перевод JSON. Я уже несколько раз тестировал эту версию (в MMA 8), и, похоже, она работает без ошибок, которые я получил вчера.
getRepChanges[userID_Integer] :=
Module[{totalChanges},
totalChanges =
"total" /.
ImportString[
StringReplace[(Import[
"http://api.stackru.com/1.1/users/" <>
ToString[userID] <>
"/reputation?key=NgVJ4Y6vFkuF-oqI-eOvOw&fromdate=0&pagesize=1&page=1", "Text"]), {":" ->
"->", "[" -> "{", "]" -> "}"}], "NB"];
Join @@
Table["rep_changes" /.
ImportString[
StringReplace[
Import["http://api.stackru.com/1.1/users/" <>
ToString[userID] <>
"/reputation?key=NgVJ4Y6vFkuF-oqI-eOvOw&fromdate=0&pagesize=100&page=" <> ToString[page],
"Text"], {":" -> "->", "[" -> "{", "]" -> "}"}],
"NB"], {page, 1, Ceiling[totalChanges/100]}]]
topAnswerers = ({"display_name", "user_id",
"email_hash"} /. #) & /@ ("user" /. ("top_users" /.
ImportString[
StringReplace[
" " <> Import[
"http://api.stackru.com/1.1/tags/mathematica/top-answerers/all-time", "Text"], {":" -> "->", "[" -> "{", "]" -> "}"}],
"NB"]))
topAnswerers = {#, #2,
Import["http://www.gravatar.com/avatar/" <> #3 <>
".jpg?s=36&d=identicon&d=identicon"]} & @@@ topAnswerers
repChangesTopUsers =
Table[repChange =
ReleaseHold[(Hold[{DateList[
"on_date" + AbsoluteTime["January 1, 1970"]],
"positive_rep" - "negative_rep"}] /. #) & /@
getRepChanges[userID]] // Sort;
accRepChange = {repChange[[All, 1]],
Accumulate[repChange[[All, 2]]]}\[Transpose], {userID,
topAnswerers[[All, 2]]}];
DateListLogPlot[
Tooltip @@@
Take[({repChangesTopUsers,
Row /@ topAnswerers[[All, {3, 1}]]}\[Transpose]), 10],
Joined -> True, Mesh -> None, ImageSize -> 1000,
PlotRange -> {All, {10, All}},
BaseStyle -> {FontFamily -> "Arial-Bold", FontSize -> 16},
DateTicksFormat -> {"MonthNameShort", " ", "Year"},
GridLines -> {True, None},
FrameLabel -> (Style[#, FontSize -> 18] & /@ {"Date", "Reputation",
"Top-10 answerers", ""})]
РЕДАКТИРОВАТЬ: вспомогательные функции для фильтрации по тегам записей Эти функции могут быть использованы для фильтрации прибыли репутации, чтобы найти выгоды только для определенных тегов. tagLookup
получает целое число post_ID в качестве входных данных и возвращает теги определенного сообщения. getQuestionIDs
а также getAnswerIDsFrom...
идти другим путем. С помощью тега они находят все идентификаторы вопросов и ответов, чтобы можно было MemberQ
принадлежит ли данный post_ID к этому тегу. Оба тега tagLookup и getAnswerID работают медленно, так как необходимо много вызовов API. Я не смог протестировать две последние функции, так как доступ к API был закрыт или мой IP-адрес был ограничен.
tagLookup[postID_Integer] :=
Module[{im},
im = Import["http://api.stackru.com/1.1/questions/" <> ToString[postID],"JSON"];
If[("questions" /. im) != {},
First[("tags" /. ("questions" /. im))],
im = Import["http://api.stackru.com/1.1/answers/" <> ToString[postID],"JSON"];
First[("tags" /. ("questions" /. Import["http://api.stackru.com/1.1/questions/" <>
ToString[First["question_id" /. ("answers" /. im)]], "JSON"]))]
]
]
getQuestionIDs[tagName_String] := Module[{total},
total =
"total" /.
Import["http://api.stackru.com/1.1/questions?tagged=" <>
tagName <> "&pagesize=1", "JSON"];
Join @@
Table[("question_id" /. ("questions" /.
Import["http://api.stackru.com/1.1/questions?key=NgVJ4Y6vFkuF-oqI-eOvOw&tagged=" <>
tagName <> "&pagesize=100&page=" <> ToString[i],
"JSON"])), {i, 1, Ceiling[total/100]}]
]
getAnswerIDsFromQuestionID[questionID_Integer] :=
Module[{total},
total =
Import["http://api.stackru.com/1.1/questions/" <>
ToString[questionID] <> "/answers?key=NgVJ4Y6vFkuF-oqI-eOvOw&pagesize=1", "JSON"];
If[total === $Failed, Return[$Failed], total = "total" /. total];
Join @@ Table[
"answer_id" /. ("answers" /.
Import["http://api.stackru.com/1.1/questions/" <>
ToString[questionID] <> "/answers?key=NgVJ4Y6vFkuF-oqI-eOvOw&pagesize=100&page=" <>
ToString[i], "JSON"]), {i, 1, Ceiling[total/100]}]
]
getAnswerIDsFromTag[tagName_String] :=
Module[{},
Join @@ (getAnswerIDsFromQuestionID /@
Cases[getQuestionIDs[tagName], Except[$Failed]])
]
Бретт, не связанный с SO API, но вы можете использовать RSS-канал для самых новых вопросов с тегами Mathematica. Вот моя наивная реализация:
QuestionHyperlink[data_] :=
Function[{name, title, link},
Hyperlink[Tooltip[title, name], link]] @@ Join[
Cases[data,
XMLElement[
"author", _, {___, XMLElement["name", {}, {name_}], ___}] :>
name],
Cases[data, XMLElement["title", _, {title_}] :> title],
Cases[data, XMLElement["link", rules_, {}] :> ("href" /. rules)]]
Cases[Import[
"http://stackru.com/feeds/tag?tagnames=mathematica&sort=\
newest", "XML"],
XMLElement["entry", attrs_, data_] :>
QuestionHyperlink[data], Infinity]