Notionのススメ
半年前くらいに機能の多さに惚れて、Dropbox PaperからNotionに移行しました。なかでもNotionの推しであるデータベースとメモを結びつける管理がとても便利ですっかりNotionに惚れ込んでしまいました。今回はそのNotionのデータベースの使い方について紹介していきたいと思います。
Notion とは
メモやドキュメント管理からタスク、プロジェクトの管理まであらゆるものを集約して管理できるアプリケーションです。このNotionの強みは何と言ってもデータベースの機能で、作成日やステータスに限らず様々なデータを合わせて保存することができます。
Notionのデータベース とは
エクセルの表のように作成日やステータスなど様々な情報について保存しておくことができ、それに加えてその一行ごとにページを関連づけることができます。また、このデータの表示方法は表形式に限らず、リスト形式やボード形式あるいはギャラリーのようにも表示ができます。 この一行ごとにページを関連づける機能がとても秀逸で、これによって欲しいページが探しやすくなり利便性を上げているように思います。
わたしのNotionの使い方
まず、データベースの旨みを生かすためにプロジェクトごとにそれぞれデータベースを作るのではなく、全て同じデータベースでステータスにプロジェクトを入力するという管理方法がオススメです。Notionではデータベースに複数の表示方法を定義でき、それらについてソートやフィルター情報を保存しておくことができるため、表示方法を変えることでプロジェクトを絞り込んだリストを表示したり、プロジェクトに関わらず最近編集したページを表示したりできます。この表示方法の定義によりむしろ一緒くたにした方が自由度が高い表示ができるというわけです。
今回はこれまで試行錯誤してきて最終形態になったと感じている、議事録とタスクの管理について紹介していきたいと思います。
議事録を管理
先ほど述べたように議事録は一緒くたに管理しています。データ項目にプロジェクト、作成日、変更日という項目を作り、プロジェクトでも日付でも絞り込みができるようにもしています。表示方法はリスト形式もいいですが、意外と気に入っているのがギャラリー表示です。ギャラリー表示だとページの上部が表示されるので、ページの上部に概要を書いておけば議事録をざっと見回すことができます。
タスクを管理
例のごとくタスクも一緒くたに管理しています。データ項目にはプロジェクト、作成日、変更日の他に、ステータス、締め切り日、議事録とのリレーション、子タスクも作れるようにタスク自身とのリレーションを作っています。
まずこのタスク管理の素晴らしいところは何よりもタスクとメモを同時に管理できるところです。タスクを探し出すことができればメモを参照することができるのです。タスク名がわかればタスク名で検索できますし、日付による検索も可能です。データを自由につけることができるため、様々な角度から検索ができ検索が捗ります。
またこのリレーションという機能、関連するドキュメントを結びつけることができるため、記憶を辿るのにとても便利になっています。MTGでの仕様変更時にタスクとの関連付けを行なっておけば、タスクを行う際に見返しやすくなります。
子タスクの関連付けには見積もりに使っています。それぞれの子タスクで見積もりをすれば、rollupという機能で親タスクで総見積もりがわかるようになっています。Notionならデータの集計もできるというわけです!
まとめ
今回はNotionのデータベースの使い方について紹介しました。Notionがドキュメントを管理する一つの候補になれば良いなと思います。
yarnとnpmの違いって?
新しく配属されたプロジェクトでパッケージマネージャはyarn使ってるからーと言われて、今までnpmしか使ったことがなかったのでなんなのそれってことで調べてときの記録を書くます。ついでにnode.js使ってるわりにサーバ側のjsくらいの知識しかなかったのでこちらも一緒に。
Node.jsとは
JavaScriptは本来クライアントサイドで動く言語であり、HTMLで書かれたページに動きをつけたりします。 しかしこれに対してNode.jsはサーバサイドで動くJavaScriptです。 https://nodejs.org/ja/about/
Node.js はスケーラブルなネットワークアプリケーションを構築するために設計された非同期型のイベント駆動の JavaScript 環境です。 以下の「Hello World」の例では、たくさんの接続を同時に処理することができます。 各接続ごとにコールバックは発火され、何もすることがない場合、Node.js はスリープします。
とあり、サンプルコードは下記のように記されていました。
const http = require('http'); const hostname = '127.0.0.1'; const port = 3000; const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello World'); }); server.listen(port, hostname, () => { console.log(`Server running at http://${hostname}:${port}/`); });
その他利点としては下記のものが挙げられているようです。
- 大量のデータ処理が可能
- ノンブロッキングI/Oモデル
- C10K問題(クライアント1万台問題)に対応
- メモリの消費が少ない
- イベントループ
- 処理速度が早い
- Google V8 JavaScript Engine(Google Chromeに搭載されているエンジン)
- サーバサイドでjsが使える
ちょっと待って、C10K問題ってなに、、ということで↓。
クライアント1万台問題
https://ja.wikipedia.org/wiki/C10K%E5%95%8F%E9%A1%8C
C10K問題(英語: C10K problem)とは、Apache HTTP ServerなどのWebサーバソフトウェアとクライアントの通信において、クライアントが約1万台に達すると、Webサーバーのハードウェア性能に余裕があるにも関わらず、レスポンス性能が大きく下がる問題である。
https://ja.wikipedia.org/wiki/Node.js
非同期処理のNode.jsではクライアント1万台問題は起きない。Node.jsでこの問題を解決した技術の中核は、シングルスレッドにおける非同期処理を容易に実装可能にしたイベント駆動型プログラミング環境である。
node.js 上の有名なフレームワーク
この辺もNode.jsのフレームワークと言えるはず
requireってなんなん
https://codezine.jp/article/detail/10967
一応、新しいモジュールシステムが出てきた経緯から説明すると、もともとNode.jsにはCommonJSという昔ながらのモジュールの仕組みがあったんですね。これは、requireを使って特定のファイルやフォルダを取ってくるというものです。 これまではずっとそれを使ってモジュールの仕組みを実現していたんですが、ES2015からES Modulesという仕様が新しく定義されて、言語側の機能でモジュールのimport/exportができるようになりました。
普通に使っているimportやexportの位置付けだったようです。
npm
- Node.jsのパッケージマネージャ
- Node Package Manager(npm)
yarnとは
ここでやっとyarnについてです。
https://qiita.com/lelouch99v/items/c97ff951ca31298f3f24
- 2016年にFaceBookが公開したJavaScriptのパッケージマネージャです。
- npmとの互換性があり、package.jsonが使えます。
yarnのメリット
- npmよりインストールが速い
- 約半分になる場合もあるそう
- npmより厳密にモジュールのバージョンを固定できる
- yarn.lockファイルで、各パッケージのインストールバージョンを固定できる。
- npmと一緒に使える
- npmと同じのpackage.jsonが使えるため、同一プロジェクトでnpm or yarnで固定しなくて良い。
yarnのインストール
$ sudo npm install -g yarn
まさかのnpmでinstallできます。 もちろんhomebrewなどでも可能です。
npmとyarnのコマンド対応
- npm init -> yarn init
- npm install -> yarn
- npm install [パッケージ名] --save -> yarn add [パッケージ名]
- npm install [パッケージ名] --save-dev -> yarn add [パッケージ名] --dev
- npm uninstall [パッケージ名] -> yarn remove [パッケージ名]
- npm install -g [パッケージ名] -> yarn global add [パッケージ名]
https://engineering.fb.com/web/yarn-a-new-package-manager-for-javascript/
npmはインストールパッケージの一貫性、パフォーマンス、セキュリティに問題があり、この問題を解決することを目的として開発されたそうです。 Yarn開発者が直面したnpmの問題解決を目的としています。
https://www.webprofessional.jp/yarn-vs-npm/
npmはパッケージごとにインストールが完了するまで待つのに対し、yarnは並行して実行するためパフォーマンスが向上しています。
まとめ
yarnはnpmの苦手なところを克服したパッケージマネージャでした。こういった背景を知ったことで、これからはnpmよりもyarnの方を積極的に使っていこうと思いました。
pyenv+matplotlibで発生するエラーを回避する
タイトルの通り、pyenvで取得したpythonでmatplotlibを使おうとしたときの話です。
import matplotlib.pyplot as plt ... plt.show()
このようなグラフ表示を伴うコードを書くと以下のようなエラーが発生します。
...(省略) ImportError: Python is not installed as a framework. The Mac OS X backend will not be able to function correctly if Python is not installed as a framework. See the Python documentation for more information on installing Python as a framework on Mac OS X. Please either reinstall Python as a framework, or try one of the other backends. If you are using (Ana)Conda please install python.app and replace the use of 'python' with 'pythonw'. See 'Working with Matplotlib on OSX' in the Matplotlib FAQ for more information.
このエラーで検索をかけると大体が、~/.matplotlib/matplotlibrc
に
"backend" : "TkAgg"
を追加してくださいという記述が見つかります。これはグラフの表示にTkinterを使うという指定をしており、これで上記のエラーが発生しなくなるのはpython3はインストール時にtkinterも(基本は)同梱しているからです。しかし、pyenvを使用しているとうまくいかない場合があります。実際にわたしの環境では以下のエラーが発生しました。
...(省略) import _tkinter # If this fails your Python may not be configured for Tk ModuleNotFoundError: No module named ‘_tkinter’
どうやらtkinterがないと言っているようなのです。 pyenvでpythonをインストールした時にtkinterがうまく入らなかったということになります。実際にそう言った症例もネットで見つかりました。 Python not configured for Tk - Stack Overflow ここではpyenvでpythonをインストールする時に必要なものが書かれていました。zlib、tcl-tkが必要だそうです。
brew install zlib brew install tcl-tk
以上でインストールしましょう。 上記のページでは、この後にpyenvをインストールするよう書いてありましたが、わたしの場合はそのままでも大丈夫でした。 この操作が終わった後にpyenvでのpythonのインストールするとtkinterが入っているので、あとは先ほどのmatplotlibrcの設定があればmatplotlibの描画にtkinterを使えるようになります。
ちなみにこれを入れただけでもtkinterがうまく入らないというケースもあるようで、その場合は.bashrcにパスを記入する必要があるみたいです。 pyenv install doesn't work with homebrew installed tcl-tk · Issue #1375 · pyenv/pyenv · GitHub
おまけ
わたしはこれからさらに仮想環境を作ってやっていたのですが、その場合はホームディレクトリは汚したくないので、仮想環境の方にmatplotlibrcの設定を書きました。以下を仮想環境のpythonで実行すれば、matplotlibrcのファイルの場所がわかります。
import matplotlib
matplotlib.matplotlib_fname()
まとめ
matplotlibの仕様とpyenvの仕様?が絡んでいる問題だったので、解決まで時間がかかりました。。pyenvのこと信頼しきっていたけど、こんな問題があったとはと驚かされた事件でした。
pythonでデコレーターを作るときに気をつけたいこと
sphinxでドキュメントを作成しようと思ったのですが、デコレーターをつけた関数の説明が軒並みおかしいので調べたところ、functools.wrapsというものの存在を知ったので記事にします。
デコレーターの書き方
pythonではデコレーターは以下のように作ります。
def my_decorator(func): """ デコレート対象の関数の前にstart、後にendを標準出力する関数を返します。 :param func: デコレート対象の関数 :return: デコレートされた関数 """ def wrapper(*args, **kwargs): """ デコレート対象の関数の前にstart、後にendを標準出力します。 :param args: :param kwargs: :return: """ print("start") func(*args, **kwargs) print("end") return wrapper @my_decorator def my_method(val1, val2): """ val1, val2を標準出力します。 :param val1: :param val2: :return: """ print(val1, val2) if __name__ == '__main__': my_method(1, 2)
これを実行すると以下が出力されます。
start 1 2 end
このようにmy_method前後で処理をするという目的ではこれだけも良いのですが、logやdocを使うときに問題があるのです。。
問題点
例えば、my_methodのdocstringを見てみましょう。print(my_method.__doc__)
で表示させてみると以下が出てきました。
デコレート対象の関数の前にstart、後にendを標準出力します。 :param args: :param kwargs: :return:
my_decorator内のwrapperに書いたはずの記述が出てきてしまいました。 これはmy_methodをmy_decoratorでデコレートしたため、pythonからはwrapperという関数を実行しているようにしか見えないという状況ということかと考えられます。
もちろんpythonではこれを回避するための仕組みが用意されています。
改善策: functools.wraps
https://docs.python.org/ja/3/library/functools.html#functools.wraps
functools.wrapsが以上のことを回避するpythonで用意されている関数になります。使い方はとっても簡単です。 先ほどの例に追加してみます。
from functools import wraps def my_decorator(func): """ デコレート対象のメソッドの前にstart、後にendを標準出力するメソッドを返します。 :param func: デコレート対象のメソッド :return: デコレートされたメソッド """ @wraps(func) # 追加部分 def wrapper(*args, **kwargs): """ デコレート対象のメソッドの前にstart、後にendを標準出力します。 :param args: :param kwargs: :return: """ print("start") func(*args, **kwargs) print("end") return wrapper @my_decorator def my_method(val1, val2): """ val1, val2を標準出力します。 :param val1: :param val2: :return: """ print(val1, val2) if __name__ == '__main__': my_method(1, 2)
print(my_method.__doc__)
で表示させてみると以下が出てきました。
val1, val2を標準出力します。 :param val1: :param val2: :return:
これは確かにmy_methodに書いたdocstringです。 ということで、pythonでデコレータを使うのは良いけどfunctools.wrapsも忘れずに!というお話でした。
shellでtry-catchをする
例えば以下のようなコードで、移動先のディレクトリがなかったらhelloはechoされないとわたしは思っていたのですが、実際のところはhelloまで出でしまいます。
#!/bin/sh cd hoge echo hello
↓出力
sample.sh: line 3: cd: hoge: No such file or directory hello
そもそもshellはエラーが出たことを認識できているのでしょうか?
コマンドの成否を確認する
終了ステータス | UNIX & Linux コマンド・シェルスクリプト リファレンス
コマンド終了時には「終了ステータス (exit-status)」と呼ばれるコマンドの成否を表す数値が特殊変数
$?
に自動で設定される。
終了ステータスとして設定される値は一般的には
- 成功:0
- 失敗:1 (コマンドやエラーの種類によっては 0 以外)
が設定されるそうです。
ということなのでエラーを認識できているのか確認は以下で行います。
#!/bin/sh cd hoge echo $? echo hello echo $?
↓出力
sample.sh: line 3: cd: hoge: No such file or directory 1 hello 0
どうやらエラーであることは認識できているようです。 ならばtry-catchしたいということでshellでtry-catchする方法を調べてみました。
shellでtry-catch
shell try-catch
で検索したらこちらのサイトが見つかりました。
シェルスクリプトでtry-catch-finally - Qiita
こちらのサイトによるとtry-catchするなら以下のように書けば良いことがわかりました。
#!/bin/sh set -eu function catch { echo Catch } function finally { echo Finally } trap catch ERR trap finally EXIT cd hoge echo hello
これを出力すると以下になりました。
sample.sh: line 13: cd: hoge: No such file or directory Catch Finally
先ほどまで出力されていたhello
の文字が出力されなくなり、Catch、Finallyの文字が出力されたことから、cd hoge
でエラーが発生したタイミングで以降の処理がスキップされ、trapで設定したcatch、finallyを通過して終了したことがわかります。
同様に成功するパターンも確認しておきましょう。
#!/bin/sh set -eu function catch { echo Catch } function finally { echo Finally } trap catch ERR trap finally EXIT cd . echo hello
この出力は以下のようになりました。
hello Finally
以上より、trap
およびset -eu
によってどういうわけかtry-catchができるようになりました。
set -euとは
shellのコマンドのset
とそのオプションであるe
とu
からなっているように見えるのでshellのsetについて調べてみました。見つかったのがこちらです。
【 set 】コマンド――シェルの設定を確認、変更する:Linux基本コマンドTips(205) - @IT
まずはset
というコマンドはshellの設定の確認、変更を行うコマンドとなっています。
そして、e
とu
は以下のように説明されています。
option | option 名 | 説明 |
---|---|---|
e | errexit | パイプやサブシェルで実行したコマンドが1つでもエラーになったら直ちにシェルを終了する |
u | nounset | パラメーター展開中に、設定していない変数があったらエラーとする(特殊パラメーターである「@」と「*」は除く) |
今回エラー発生タイミングで以降の処理をスキップをするようになったのは、set -e
のおかげであるということですね。
ちなみにset -u
の恩恵を受けるようなコードは以下になります。
#!/bin/sh set -u $hoge echo hello
↓出力
sample.sh: line 5: hoge: unbound variable
hogeという設定していない変数を利用しようとした結果エラーになりました。この設定によるエラーはe
のオプションなしでも以降の処理はスキップして終了するのですね。念の為オプションなしの方も確認しておきましょう。
#!/bin/sh $hoge echo hello
↓出力
hello
エラーが吐かれることなく最後まで実行していました。
trapとは
trap [ action condition ... ]
という構文からなっています。
trap ユーティリティーは、 condition が発生したときに qsh によって実行される action を設定します。 qsh は、trap を実行しているときに action を展開し、condition が発生したときに再度展開します。 また、trapには
l
,p
というオプションがあり、それぞれ以下のようにことができます。
option | 説明 |
---|---|
l | すべてのシグナル名とその対応する番号のリストを表示します。 |
p | 各トラップを再入力可能な形式で表示します。 |
conditionにはシグナルの名または番号を指定します。有効なシグナルのリストはtrap -l
で参照することができるようです。
また、デフォルトで存在するのは以下です。
condition | 説明 |
---|---|
ERR | エラー時に(コマンドの返り値が0以外)の時に実行 |
EXIT (0) | 終了時に実行 |
DEBUG | 各種コマンドの後で実行 |
まとめ
shellでも他のプログラミング言語でできることはできるんだなあと思いました。
デデンネの総合順位をスクレイピングして求めた話
2月の初旬に好きなポケモンがgoogleで投票できましたが、皆さんはデデンネに投票してくださいましたでしょうか?
さて、2020/02/27はポケモンの日。前述した投票の結果も、この日の23時に公開されました。公開された情報は、総合TOP30および各地方のTOP30のみです。残念ながらデデンネは総合順位30位内には入ることができず、総合順位はわかりませんでした。しかし、カロス地方にて7位に輝き、その投票数は21,691でした。他の地方のTOP30の子たちの投票数を見るに、デデンネと同等数の投票数を獲得しているポケモンたちはどうやら15位以内に収まっているようでした。デデンネの総合順位が出せる...!ということで出してみました。
ついでに学べたこともあったので、合わせてこの記事に載せようと思います。
BeautifulSoupでは取得できない?
requests + BeautifulSoupを使ってスクレイピングをした経験があるので、安易に今回もこちらを使ってスクレイピングをしようとしました。
from urllib.request import urlopen from bs4 import BeautifulSoup soup=BeautifulSoup(urlopen(url))
上記のコードで拾ってこれで図鑑番号、ポケモン名と投票数が入っているものが取れると思ったのですが、実際に図鑑番号、ポケモン名と投票数が入るはずのところには違うものが入っていました。
<div class="ranking__text"> <p class="ranking__number">No.<span>{{data.no}}</span></p> <h3 class="ranking__name">{{data.jp}}</h3> <p class="ranking__vote"><span>{{data.vote}}</span>票</p> </div>
すごい何処かで見たことあるやつだと思いました。vueと同じようなやつだなと思いました。(jsのテンプレートエンジンですね。)
jsのテンプレートエンジンを使っている画面は取得できない...?
ひとまず確認のため、最近触っているvueでサンプルページを作ってBeautifulSoupに読ませてみました。
読み込んでみると以下が帰ってきました。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"/> <meta content="IE=edge" http-equiv="X-UA-Compatible"/> <meta content="width=device-width,initial-scale=1.0" name="viewport"/> <link href="/favicon.ico" rel="icon"/> <title>sample</title> <link as="script" href="/js/app.js" rel="preload"/> <link as="script" href="/js/chunk-vendors.js" rel="preload"/> </head> <body> <noscript> <strong>We're sorry but sample doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <div id="app"></div> <!-- built files will be auto injected --> <script src="/js/chunk-vendors.js" type="text/javascript"></script> <script src="/js/app.js" type="text/javascript"></script> </body> </html>
<div id="app"></div>
がそのままなところから、確かに図と同じものは読み込めてなさそうなことがわかりました。ソースコード見るに、index.htmlを読んだだけのように見えます。
We're sorry but sample doesn't work properly without JavaScript enabled. Please enable it to continue. ここも重要ですね、表示されてはいないものの、JavaScriptがないと十分に動かないとの注意書きがされています。(index.htmlにある文章なので、スクレイピングしたから出たわけではないです。)
requests_html
先ほどの調査で、requests + BeautifulSoupだけではindex.htmlなるjsの実行前のものが取得されてしまい、jsで書き換えているようなページはきちんと取得できないということがわかりました。見てるページをきちんと取得するためには、index.htmlだけでなくjsも読み込み反映させたものを取得する必要があります。
pythonにはこのようなことをしてくれるライブラリがいくつかあり、Seleniumが特に有名ですが、今回色々用意しなくても楽に実装できそうなrequests_htmlを使うことにしました。
from requests_html import HTMLSession session = HTMLSession() r = session.get(url) # ブラウザエンジンでHTMLを生成させる r.html.render()
ちょっとBeautifulSoupと比べると手間ですが、これでjs反映後のhtmlが取得できるはずです。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <link rel="icon" href="/favicon.ico"> <title>sample</title> <link href="/js/app.js" rel="preload" as="script"> <link href="/js/chunk-vendors.js" rel="preload" as="script"> <style type="text/css"> h3[data-v-469af010] { margin: 40px 0 0; } ul[data-v-469af010] { list-style-type: none; padding: 0; } li[data-v-469af010] { display: inline-block; margin: 0 10px; } a[data-v-469af010] { color: #42b983; } </style> <style type="text/css"> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style> </head> <body> <noscript> <strong>We're sorry but sample doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <div id="app"><img alt="Vue logo" src="/img/logo.82b9c7a5.png"> <div data-v-469af010="" class="hello"><h1 data-v-469af010="">Welcome to Your Vue.js App</h1> <p data-v-469af010=""> For a guide and recipes on how to configure / customize this project,<br data-v-469af010=""> check out the <a data-v-469af010="" href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>. </p> <h3 data-v-469af010="">Installed CLI Plugins</h3> <ul data-v-469af010=""> <li data-v-469af010=""><a data-v-469af010="" href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li> <li data-v-469af010=""><a data-v-469af010="" href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li> </ul> <h3 data-v-469af010="">Essential Links</h3> <ul data-v-469af010=""> <li data-v-469af010=""><a data-v-469af010="" href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li> <li data-v-469af010=""><a data-v-469af010="" href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a> </li> <li data-v-469af010=""><a data-v-469af010="" href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li> <li data-v-469af010=""><a data-v-469af010="" href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li> <li data-v-469af010=""><a data-v-469af010="" href="https://news.vuejs.org" target="_blank" rel="noopener">News</a> </li> </ul> <h3 data-v-469af010="">Ecosystem</h3> <ul data-v-469af010=""> <li data-v-469af010=""><a data-v-469af010="" href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a> </li> <li data-v-469af010=""><a data-v-469af010="" href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a> </li> <li data-v-469af010=""><a data-v-469af010="" href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li> <li data-v-469af010=""><a data-v-469af010="" href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li> <li data-v-469af010=""><a data-v-469af010="" href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li> </ul> </div> </div> <!-- built files will be auto injected --> <script type="text/javascript" src="/js/chunk-vendors.js"></script> <script type="text/javascript" src="/js/app.js"></script>
<div id="app"></div>
の中身が埋まったことがわかります。
準備が整ったのでデデンネの総合順位を取得する
今回、順位を出すのにデータ取り扱いに強いpandasを使って計算を行いました。
import pandas as pd from requests_html import HTMLSession def get_region_rank_data(region): ls = list() url = 'https://pokemonday.pokemon.co.jp/jp/result/' + region + '/' # セッション開始 session = HTMLSession() r = session.get(url) # ブラウザエンジンでHTMLを生成させる r.html.render() headers = r.html.find('.ranking__header') for header in headers: name = header.find('.ranking__name')[0].text vote = int(header.find('.ranking__vote > span')[0].text.replace(",", "")) number = int(header.find('.ranking__number > span')[0].text) ls.append([number, name, vote]) return ls if __name__ == '__main__': regions = [ 'kanto', 'johto', 'hoenn', 'sinnoh', 'unova', 'kalos', 'alola', 'galar', ] data_list = list() for region in regions: data_list.extend(get_region_rank_data(region)) # 集計 array = pd.np.array(data_list) df = pd.DataFrame({ "number": array[:, 0], "name": array[:, 1], "vote": array[:, 2] }) df["vote"] = df["vote"].astype(int) df = df.sort_values("vote", ascending=False) df["rank"] = df["vote"].rank(0, ascending=False) df = df[["rank", "name", "number", "vote"]] df.to_csv('pokemon_vote_ranking.csv', header=True, index=False)
これによってpokemon_vote_ranking.csvに吐き出されたデータは以下のようになりました。
rank,name,number,vote 1.0,ゲッコウガ,658,140559 2.0,ルカリオ,448,102259 3.0,ミミッキュ,778,99077 4.0,リザードン,6,93968 5.0,ブラッキー,197,67062 6.0,ニンフィア,700,66029 7.0,ガブリアス,445,61877 8.0,レックウザ,384,60939 9.0,サーナイト,282,60596 10.0,ゲンガー,94,60214 11.0,ドラパルト,887,57973 12.0,バンギラス,248,56834 13.0,フシギダネ,1,56015 14.0,ストリンダー,849,55032 15.0,ルギア,249,53268 16.0,モクロー,722,52367 17.0,ギルガルド,681,51517 18.0,シャンデラ,609,50943 19.0,ピカチュウ,25,48060 20.0,イーブイ,133,47762 21.0,レントラー,405,46032 22.0,ジュナイパー,724,44011 23.0,ゾロアーク,571,43782 24.0,ルガルガン,745,42792 25.0,アーマーガア,823,41711 26.0,フライゴン,330,41420 27.0,サザンドラ,635,40054 28.0,ジュカイン,254,38724 29.0,バシャーモ,257,38307 30.0,ユキハミ,872,38034 31.0,ミズゴロウ,258,36920 32.0,カイリュー,149,36873 33.0,ミュウ,151,36266 34.0,メタグロス,376,35631 35.0,バクフーン,157,35184 36.0,オンバーン,715,34795 37.0,ハッサム,212,34691 38.0,ポッチャマ,393,34680 39.0,ミュウツー,150,34585 40.0,ゴウカザル,392,33267 41.0,デンリュウ,181,32009 42.0,ゼラオラ,807,31691 43.0,マホイップ,869,30612 44.0,ダークライ,491,30544 45.0,ヌメルゴン,706,30209 46.0,エーフィ,196,30052 47.0,ガオガエン,727,29925 48.0,ウインディ,59,29795 49.0,ジラーチ,385,29611 50.0,ヒノアラシ,155,28332 51.0,ミロカロス,350,28295 52.0,アブソル,359,27781 53.0,グソクムシャ,768,26975 54.0,エースバーン,815,26892 55.0,ラグラージ,260,26540 56.0,スイクン,245,26277 57.0,グレイシア,471,26161 58.0,ザシアン,888,26158 59.0,アシレーヌ,730,25953 60.0,ワンパチ,835,25695 61.0,ボーマンダ,373,24920 62.0,アルセウス,493,24502 63.5,ウルガモス,637,24389 63.5,ココドラ,304,24389 65.0,ラプラス,131,23411 66.0,オノノクス,612,22937 67.0,ワニノコ,158,22526 68.0,ファイアロー,663,22328 69.0,ジャローダ,497,22269 70.0,ミジュマル,501,21990 71.0,エンペルト,395,21773 72.0,デデンネ,702,21691 73.0,クロバット,169,21548 74.0,ゼクロム,644,21477 75.0,オオタチ,162,21447 76.0,ギラティナ,487,21366 77.0,ウールー,831,21266 78.0,ビクティニ,494,20957 79.0,リーフィア,470,20859 80.0,イベルタル,717,20852 81.0,インテレオン,818,20697 82.0,ドダイトス,389,20632 83.0,セレビィ,251,20492 84.0,ヌメラ,704,20299 85.0,ネギガナイト,865,20217 86.0,レシラム,643,20123 87.0,ヒバニー,813,20058 88.0,カビゴン,143,19768 89.0,ワルビアル,553,19628 90.0,キュウコン,38,19044 91.0,ガチゴラス,697,18778 92.0,ブリムオン,858,18581 93.0,チコリータ,152,18521 94.0,ゼニガメ,7,18476 95.0,ホウオウ,250,18278 96.0,オーダイル,160,18245 97.0,ボスゴドラ,306,18120 98.0,エルフーン,547,17855 99.0,ラティアス,380,17478 100.0,シェイミ,492,17465 101.0,ゼルネアス,716,17415 102.0,キテルグマ,760,17181 103.0,メッソン,816,17155 104.0,ツタージャ,495,17020 105.0,チルタリス,334,16814 106.0,カメックス,9,16795 107.0,ヘラクロス,214,16577 108.0,ソルガレオ,791,16274 109.0,メルタン,808,16077 110.0,タイレーツ,870,16009 111.0,タルップル,842,15989 112.5,ムゲンダイナ,890,15699 112.5,ネイティ,177,15699 114.0,ピチュー,172,15695 115.0,カイオーガ,382,15585 116.0,クチート,303,15523 117.0,ゾロア,570,14910 118.0,シャワーズ,134,14887 119.0,マッシブーン,794,14747 120.0,ヘルガー,229,14742 121.0,ルチャブル,701,14607 122.0,ペンドラー,545,14536 123.5,ナマコブシ,771,14358 123.5,ベトベトン,89,14358 125.0,ディアルガ,483,14292 126.0,トゲピー,175,14288 127.0,エルレイド,475,14144 128.0,ランクルス,579,14129 129.0,ムクホーク,398,14054 130.0,ヒトカゲ,4,14049 131.0,ニャビー,725,14005 132.0,モルペコ,877,13945 133.0,メロエッタ,648,13915 134.0,シルヴァディ,773,13897 135.0,メタモン,132,13843 136.0,ニャオニクス,678,13661 137.0,フォッコ,653,13508 138.0,サルノリ,810,13478 139.0,トゲキッス,468,13426 140.0,クワガノン,738,13375 141.0,ヌオー,195,13308 142.0,オーロンゲ,861,12923 143.0,エンニュート,758,12863 144.0,キノガッサ,286,12801 145.0,ジャラランガ,784,12790 146.0,グライオン,472,12676 147.0,ザマゼンタ,889,12641 148.0,アチャモ,255,12568 149.0,ラティオス,381,12487 150.0,ヤドン,79,12369 151.0,メルメタル,809,12356 152.0,マーシャドー,802,12107 153.0,グラードン,383,11982 154.0,ジガルデ,718,11943 155.0,マルヤクデ,851,11619 156.0,ニドキング,34,11586 157.0,ダイケンキ,503,11444 158.0,ウオノラゴン,882,11436 159.0,ミミロップ,428,11411 160.0,ドリュウズ,530,11376 161.0,ポリゴン,137,11311 162.0,ドレディア,549,11292 163.0,ロコン,37,11224 164.0,コダック,54,11212 165.0,ライチュウ,26,11196 166.0,カイロス,127,11162 167.0,ヒトモシ,607,11140 168.0,サンダース,135,11064 169.0,ハクリュー,148,11051 170.0,モスノウ,873,10988 171.0,イワンコ,744,10986 172.0,キリキザン,625,10975 173.0,ビッパ,399,10924 174.0,ディアンシー,719,10918 175.0,アマージョ,763,10900 176.0,マフォクシー,655,10889 177.0,ナエトル,387,10865 178.0,マニューラ,461,10854 179.0,デオキシス,386,10842 180.0,テールナー,654,10807 181.0,ジュプトル,253,10746 182.0,ジュペッタ,354,10579 183.0,フシギバナ,3,10454 184.0,フリーザー,144,10450 185.0,ユキメノコ,478,10408 186.0,エンテイ,244,10404 187.0,ニャスパー,677,10402 188.0,コオリッポ,875,10392 189.0,キュレム,646,10338 190.0,フーパ,720,10327 191.0,アマルルガ,699,10321 192.0,ヤンチャム,674,10187 193.0,マグマラシ,156,10032 194.0,コイル,81,9955 195.0,ポリゴン2,233,9902 196.0,チラチーノ,573,9892 197.0,ルナアーラ,792,9887 198.0,ドラミドロ,691,9882 199.0,エモンガ,587,9798 200.0,パチリス,417,9694 201.0,ロトム,479,9417 202.0,キモリ,252,9339 203.0,ウパー,194,9323 204.0,バケッチャ,710,9162 205.0,ロズレイド,407,9092 206.0,オーロット,709,9019 207.0,ヤミラミ,302,9012 208.0,ケルディオ,647,8915 209.0,ラランテス,754,8889 210.0,ゴロンダ,675,8859 211.0,ムウマージ,429,8833 212.0,バチュル,595,8796 213.0,チラーミィ,572,8739 214.0,ルンパッパ,272,8708 215.0,タチフサグマ,862,8705 216.0,ゴリランダー,812,8625 217.0,トゲデマル,777,8531 218.0,ウッウ,845,8436 219.0,コリンク,403,8373 220.0,ボクレー,708,8231 221.0,ドヒドイデ,748,8221 222.0,ムウマ,200,8156 223.0,ツボツボ,213,8129 224.0,カプ・コケコ,785,8090 225.0,ゴルーグ,623,8035 226.0,ゲノセクト,649,7905 227.0,バンバドロ,750,7787 228.0,ソーナンス,202,7745 229.0,ネクロズマ,800,7739 230.0,アシマリ,728,7542 231.0,コスモッグ,789,7515 232.0,キングドラ,230,7418 233.0,ゴンベ,446,7289 234.0,アブリボン,743,7126 235.0,ポリゴンZ,474,7040 236.0,ヌケニン,292,6703 237.0,カラマネロ,687,6503 238.0,グラエナ,262,6459 239.0,エレザード,695,6386 240.0,ケロマツ,656,6293
デデンネがいた!!!
72.0,デデンネ,702,21691
デデンネの図鑑番号702から0を抜いた順位になっていました。
まとめ
デデンネは総合順位72位!!!
Go 日時フォーマットについて
Goにて日時をフォーマットしようと思い、よくみる%y%M%dを書いたところ、上手くいかなかったため調べてみました。
Goでは20060102と書くと同様のフォーマットができるみたいです。
Goでは日時フォーマットに使う日時が決まっている
なんとGoでは日時フォーマットに使う日時が決まっているのです。
2006年1月2日午後3時4分5秒がその日時です。
実際に表記してほしい状態で指定できるので、わかりやすくていいですよね。(プログラマからしたら、他の言語と違うので逆にわかりにくい気はする...)
Junuaryとかも使える
上記に書いた数字以外もちろん使えます。例えばJunuaryやJunて書いても大丈夫です。
package main import "fmt" import "time" func main() { n := time.Now() fmt.Println(n) // 2009-11-10 23:00:00 +0000 UTC m=+0.000000001 fmt.Println(n.Format("20060102")) // 20091110 fmt.Println(n.Format("2006 Junuary 02")) // 2009 Junuary 10 fmt.Println(n.Format("2006 Jun 02")) // 2009 Jun 10 fmt.Println(n.Format("2006年1月2日")) // 2009年11月10日 fmt.Println(n.Format("06/01/02")) // 09/11/10 }
ちなみに
なんでこの日なんだろう、Goと何か関係がある日なの、、?と考えを巡らしてしまったのですが、googleさんに聞いたところ、Goができた日みたいな素敵な意味ではなく、単純に(1,2,3,4,5,6)の並びだからという話が有力そうです。(覚えやすさ大事...!)