Ammonite/Статистика відвідувань вікісторінок: відмінності між версіями

Вилучено вміст Додано вміст
Ilya (обговорення | внесок)
Ilya (обговорення | внесок)
раніше виправити помилку простіше
Рядок 15:
@ def url(project: String, year: Int, month: Int) = s"https://wikimedia.org/api/rest_v1/metrics/pageviews/top/$project/all-access/$year/$month/all-days"
defined function url
@ url("uk.wikibooks.org", 2016, 121)
res2: String = "https://wikimedia.org/api/rest_v1/metrics/pageviews/top/uk.wikibooks.org/all-access/2016/121/all-days"
</source>
 
Так само як і [[Ammonite/HTTP запит з парсингом JSON|в попередньому прикладі]] отримуємопробуємо отримати дані
<source lang="scala">
import scala.io.Source
val text = Source.fromURL(url("uk.wikibooks.org", 2016, 121)).mkString
</source>
 
І отримуємо помилку
І парсимо повернутий JSON
<tt><pre>
java.io.FileNotFoundException: https://wikimedia.org/api/rest_v1/metrics/pageviews/top/uk.wikibooks.org/all-access/2016/1/all-days
sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1872)
sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474)
sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
java.net.URL.openStream(URL.java:1045)
scala.io.Source$.fromURL(Source.scala:141)
scala.io.Source$.fromURL(Source.scala:131)
$sess.cmd13$.monthlyViews(cmd13.sc:3)
...
</pre></tt>
 
Виявляється сервіс статистики переглядів не розуміє номер місяця без початкового нуля, і потрібно вказати 01, а не 1. Тому, додаємо у функцію створення url початковий 0:
<source lang="scala">
def url(project: String, year: Int, month: Int) = {
val monthStr = (if (month < 10) "0" else "") + month
s"https://wikimedia.org/api/rest_v1/metrics/pageviews/top/$project/all-access/$year/$monthStr/all-days"
}
</source>
 
Парсимо повернутий JSON
<source lang="scala">
import $ivy.`io.circe::circe-parser:0.6.1`, $ivy.`io.circe::circe-optics:0.6.1`
Рядок 137 ⟶ 157:
== Річна статистика ==
 
=== Виправлення формату місяця ===
Винесемо код одержання статистики за місяць у окрему функцію
<source lang="scala">
def getMonthlyViews(project: String, year: Int, month: Int): List[(String, Int)] = {
def url: String = {
val url = s"https://wikimedia.org/api/rest_v1/metrics/pageviews/top/$project/all-access/$year/$month/all-days"
val monthStr = (if (month < 10) "0" else "") + month
val text = Source.fromURL(url).mkString
s"https://wikimedia.org/api/rest_v1/metrics/pageviews/top/$project/all-access/$year/$monthStr/all-days"
val doc = parse(text).getOrElse(Json.Null)
}
val articles = root.items.each.articles.each.article.string.getAll(doc)
val views = root.items.each.articles.each.views.int.getAll(doc)
articles.zip(views)
}
</source>
 
І робимо спробу отримати статистику по 12 місяцям
<source lang="scala">
val monthly = (1 to 12).map(month => monthlyViews("uk.wikibooks.org", 2016, month))
</source>
 
<tt><pre>
java.io.FileNotFoundException: https://wikimedia.org/api/rest_v1/metrics/pageviews/top/uk.wikibooks.org/all-access/2016/1/all-days
sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1872)
sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474)
sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:254)
java.net.URL.openStream(URL.java:1045)
scala.io.Source$.fromURL(Source.scala:141)
scala.io.Source$.fromURL(Source.scala:131)
$sess.cmd13$.monthlyViews(cmd13.sc:3)
...
</pre></tt>
 
Виявляється сервіс статистики переглядів не розуміє номер місяця без початкового нуля, і потрібно вказати 01, а не 1
 
Створимо перелік місяців у такому форматі, як хоче сервіс.
<source lang="scala">
val months = (1 to 9).map(m => "0" + m) ++ (10 to 12).map(m => m.toString)
</source>
Вираз можна записати трохи коротше, не вказуючи назву єдиного параметра внутрішніх функцій:
<source lang="scala">
(1 to 9).map("0" + _) ++ (10 to 12).map(_.toString)
</source>
 
Вивід:
<source lang="scala">
months: collection.immutable.IndexedSeq[String] = Vector("01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12")
</source>
 
І робим другу спробу
<source lang="scala">
val monthly = months.map(month => getMonthlyViews("uk.wikibooks.org", 2016, month))
</source>
 
Вивід:
<source lang="scala">
val monthly = months.map(month => getMonthlyViews("uk.wikibooks.org", 2016, month))
cmd16.sc:1: type mismatch;
found : String
required: Int
val monthly = months.map(month => getMonthlyViews("uk.wikibooks.org", 2016, month))
^
Compilation Failed
</source>
 
Це тому, що Scala має сувору перевірку типів під час компіляції і не дозволить використати змінну типу <tt>String</tt> (рядок) для передачі у функцію, яка очікує число <tt>month: Int</tt>
<source lang="scala">
def getMonthlyViews(project: String, year: Int, month: Int)
</source>
 
Ряд інших мов могли б спробувати перетворити рядок у число під час виконання, що могло б привести до помилки під виконнання.
 
Ми могли б змінити <tt>getMonthlyViews</tt> щоби вона приймала рядок, але це не дуже добра ідея. Адже насправді, ми викликаючи функцію <tt>getMonthlyViews</tt> хочемо отримати дані за номером місяця, і не хочемо нічого знати які рядки допустимі у сервісі статистики.
 
Отже додамо у функцію <tt>getMonthlyViews</tt>перетворення числа місяця у рядок з початковим нулем
<source lang="scala">
val monthStr = (if (month < 10) "0" else "") + month
</source>
 
Повністю оновлена функція виглядає так
<source lang="scala">
def getMonthlyViews(project: String, year: Int, month: Int): List[(String, Int)] = {
val monthStr = (if (month < 10) "0" else "") + month
val url = s"https://wikimedia.org/api/rest_v1/metrics/pageviews/top/$project/all-access/$year/$monthStr/all-days"
val text = Source.fromURL(url).mkString
val doc = parse(text).getOrElse(Json.Null)
Рядок 226 ⟶ 172:
</source>
 
І отримаємо статису за кожним місяцем:
Її можна викликати не задумуючись про формат номеру місяця
<source lang="scala">
val monthly = (1 to 12).map(month => getMonthlyViews("uk.wikibooks.org", 2016, month))