MySQLの小ネタ
普段はWorkbenchとかプログラムとかからDBを扱っているので、CUIではあまり見ない。mysqlをふとした時にターミナルで見たりすると面食らう事があるので、いくつか使えそうなネタを調べた
PAGERの指定
SELECTの結果とかをPAGERで見ることが出来る。コンソールでSELECTの結果を見ると、レイアウトがグチャグチャになってしまうので、少しでも見やすくするためにPAGERを使って見る。
mysqlを始めるときに指定するやり方
mysqlを始めるときにpagerを指定して、各種結果を標準出力からpagerに渡すことが出来る
$ mysql -u username -p --pager='less -S'
mysqlモードに入った後からの指定
最初にpagerの指定を付け忘れても、後から指定、変更ができる
mysql > pager less -S
PAGERの終了
どんな結果もpagerで出るようになるのだが、逆にpagerだと見にくいと感じるもある。たとえばshow tablesとか、describe tableして結果を見ながらSQLを書こうかなと思っていてもpagerで出てしまうので、標準出力には残らない。
mysql > nopager
これでpagerの指定を解除できる
参考:
結果を縦で見る
\Gを付けることで結果を横から縦にすることが出来る
mysql > SELECT foo, bar from baz\G
クエリの末に\Gを書くと
|foo |bar | +-----------+--------+ |hoge |fuga | |hogehoge |piyo |
いつものこんな感じの出力が
********* 1. row ********** foo:hoge bar:fuga ********* 2. row ********** foo:hogehoge bar:piyo
こうなる。
JSON形式で表せたらいいなぁなんて思ったりもしたけど、今のところその機能は無い。
EDITORで編集
当然クエリなんかを書く際はエディタを使ったほうが編集しやすいに決まってる。ということでエディタを起動してクエリを編集
mysql > edit
こうすると環境変数EDITORに指定されているエディタが起動する。僕の場合はvimが起動し、クエリを書いて保存、終了。これで即クエリを実行してくれれば便利なんだけど、改めてセミコロンを打たないと実行されない。正直ちょっと使いづらいかなぁという印象。editと打つだけで直前のクエリをバッファに出してくれるのはちょっと便利。
ファイルからクエリ実行
それならばあらかじめ編集してあるファイルを使えばいいということで、ファイルからクエリを実行する方法。
mysql > source hoge.sql
パスの補完をしてくれないのがただただつらい。
shellコマンド実行
ソースから実行するにしても、そもそもどこにいるんだっけ?とカレントディレクトリを調べたい時にmysqlモードからshellコマンドを実行する事が出来る。
mysql > \! ls -la
shellコマンドが実行できるということは、俺たちのvimももちろん実行できるのでファイルの編集もへっちゃら。
mysql > \! vim hoge.sql
ただ、.bashrcとかに書いたエイリアスが効かないのが何ともいえない。とりあえずこのshellコマンドが実行できる事がわかればいろいろ捗りそう。
help
こうやって調べたことは体に刻み込まれる前に忘れてしまうものですが、まぁ、ヘルプを見たら大体出てるので忘れても思い出しやすいですね。
mysql > help
List of all MySQL commands: Note that all text commands must be first on line and end with ';' ? (\?) Synonym for `help'. clear (\c) Clear the current input statement. connect (\r) Reconnect to the server. Optional arguments are db and host. delimiter (\d) Set statement delimiter. edit (\e) Edit command with $EDITOR. ego (\G) Send command to mysql server, display result vertically. exit (\q) Exit mysql. Same as quit. go (\g) Send command to mysql server. help (\h) Display this help. nopager (\n) Disable pager, print to stdout. notee (\t) Don't write into outfile. pager (\P) Set PAGER [to_pager]. Print the query results via PAGER. print (\p) Print current command. prompt (\R) Change your mysql prompt. quit (\q) Quit mysql. rehash (\#) Rebuild completion hash. source (\.) Execute an SQL script file. Takes a file name as an argument. status (\s) Get status information from the server. system (\!) Execute a system shell command. tee (\T) Set outfile [to_outfile]. Append everything into given outfile. use (\u) Use another database. Takes database name as argument. charset (\C) Switch to another charset. Might be needed for processing binlog with multi-byte charsets. warnings (\W) Show warnings after every statement. nowarning (\w) Don't show warnings after every statement. resetconnection(\x) Clean session context. For server side help, type 'help contents'
けどhelp pagerとかしてもなんも出ないので、helpに期待しすぎてもです。
Scrapyのコツ
Scrapyを作ってていくつかコツをつかんだ気がする。といっても処理側の話なので、xpathをマスターしないことにはScrapyが作れないことには変わりない。
Spiderのコツ
itemをitemクラスに格納する際にはyieldをうまく使うといい。
前回やったRSSのようにデータが繰り返しの構造になっている場合には、forループを回している最中で処理がyieldに到達するとpipelineへと処理が移行する。pipelineの処理が終わると、またSpiderにおいてforループの続きが行われる。
前回記事ではpipelineに関する処理は省略したが、SpiderとpipelineはSpiderでitemにデータを全部いれてからpipelineでforループを使って処理をしていた
- 変更前
# your Spider item['title'] =response.xpath('//item/title/text()').extract() item['link'] =response.xpath('//item/link/text()').extract() yield item
# your pipeline title = item['title'] link = item['link'] for (t, l) in zip(title, link): print("title", t) print("link", l)
これをSpiderでforループを回して途中でyieldするようにして、pipelineではforループを書かないように変更した。
- 変更後
# your Spider rss = response.xpath('//item') for sel in rss: item = HatenaHotentryItem() item['title'] = sel.xpath('title/text()').extract()[0] item['link'] = sel.xpath('title/text()').extract()[0] yield item
# your pipeline title = item['title'] link = item['link'] print("title", title) print("link", link)
これでforループの途中でpipelineに処理が移行し、pipelineがitemを使って何かしらの処理ができるようになる。どっちでforループを書くのかってだけといえばそのとおり。
pipelineのコツ
コツってほどでもないけど、上のSpiderに合わせて変更をする。pipelineではSpiderのライフサイクルに合わせて処理の定義ができる。
Item Pipeline — Scrapy 1.3.0 documentation
具体的にはSpider開始時、処理中と終了時の処理を定義できる。たとえば、Spider開始時にRDBとのコネクションを張って、Spider終了時にコネクションを切るといった事もできる。
class YourPipeline(object): def __init__(self): # いわゆるinit。pipelineがインスタンス化されたときに呼び出される # pipeline特有のものではなくpython標準なので、特に解説するようなことはない def open_spider(self, spider): # スパイダーが起動したときに呼び出される # DBへのコネクションを張ったりとか def process_item(self, item, spider): # スパイダーがyieldした時に呼び出される # itemを使って具体的に処理をする def close_spider(self, spider): # スパイダーが終了したときに呼び出される # トランザクションをcommitしたりDBをcloseしたりとか
処理を変えるとoutputするjsonのデータ構造も変わるので、好きなほうに変えるといいと思う。jsonがどういった構造のほうが扱いやすいかで決めたらいい。
ScrapyでRSSをスクレイピング
RSSリーダがすでにあるのに、スクレイピングをするなんて、、、いや、余計なことは考えない!!
スパイダーを作ってアイテムに入れるまで
今回のお題としては、はてぶの人気エントリのRSSを取ってきてアイテムに入れるまで。パイプラインに関しては今回は扱わない。
まずはプロジェクトの作成
scrapy startproect hatena_hotentry
続いてスパイダーの生成
cd hatena_hotentry
scrapy genspider HotentrySpider feeds.feedburner.com
ここまでは何の問題もなく終わる。
それからシェルを使ってxpathの確認
scrapy shell http://feeds.feedburner.com/hatena/b/hotentry
例によってソースを確認して(※データは記事作成時のもの)
~前略~ <item rdf:about="http://anond.hatelabo.jp/20170118083140"> <title>映画館でわざわざ観る必要がない問題</title> <link>http://anond.hatelabo.jp/20170118083140</link> <description>「この世界の片隅に」はわざわざ映画館で観る理由がない。映画館で観る人はとにかく褒めたいアーリーアダプターと話題に乗っかりたいブロガーさんだけである。 いずれYoutubeかAmazonビデオでなら観るだろう。そしてレビューに「素晴らしかった!」とか書くんだろう。 この手の話はここ10年映画が衰退している理由でもある。 BDの普及、レンタル屋、テレビの高精細大画面化。 キネマ旬報はこの流れとともにお...</description> <content:encoded><![CDATA[<blockquote cite="http://anond.hatelabo.jp/20170118083140" title="映画館でわざわざ観る必要がない問題"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fanond.hatelabo.jp%2F" alt="" /> <a href="http://anond.hatelabo.jp/20170118083140">映画館でわざわざ観る必要がない問題</a></cite><p>「この世界の片隅に」はわざわざ映画館で観る理由がない。映画館で観る人はとにかく褒めたいアーリーアダプターと話題に乗っかりたいブロガーさんだけである。 いずれYoutubeかAmazonビデオでなら観るだろう。そしてレビューに「素晴らしかった!」とか書くんだろう。 この手の話はここ10年映画が衰退している理由でもある。 BDの普及、レンタル屋、テレビの高精細大画面化。 キネマ旬報はこの流れとともにお...</p><p><a href="http://b.hatena.ne.jp/entry/http://anond.hatelabo.jp/20170118083140"><img src="http://b.hatena.ne.jp/entry/image/http://anond.hatelabo.jp/20170118083140" alt="はてなブックマーク - 映画館でわざわざ観る必要がない問題" title="はてなブックマーク - 映画館でわざわざ観る必要がない問題" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?http://anond.hatelabo.jp/20170118083140"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote><img src="http://feeds.feedburner.com/~r/hatena/b/hotentry/~4/8vfCvvBcSzw" height="1" width="1" alt=""/>]]></content:encoded> <dc:date>2017-01-18T08:57:56+09:00</dc:date> <dc:subject>エンタメ</dc:subject> <hatena:bookmarkcount>197</hatena:bookmarkcount> </item> <item rdf:about="https://note.mu/wakusei2nd/n/n562b7d525897"> <title>なぜ日本が世界共通語「Emoji」を生み出したのか、そしてその影響とは/古川健介『TOKYO INTERNET』|PLANETS|note</title> <link>https://note.mu/wakusei2nd/n/n562b7d525897</link> <description>なぜ日本が世界共通語「Emoji」を生み出したのか、そしてその影響とは/古川健介『TOKYO INTERNET』 ★☆★☆★☆★☆★☆★☆★☆★☆★☆ こちらの記事は、1/19(木)24:00までの期間限定で全文無料でお読みいただけます! ★☆★☆★☆★☆★☆★☆★☆★☆★☆ Daily PLANETS では毎月第2水曜日に、古川健介さんの連載『TOKYO INTERNET』を配信しています。連載...</description> <content:encoded><![CDATA[<blockquote cite="https://note.mu/wakusei2nd/n/n562b7d525897" title="なぜ日本が世界共通語「Emoji」を生み出したのか、そしてその影響とは/古川健介『TOKYO INTERNET』|PLANETS|note"><cite><img src="http://cdn-ak.favicon.st-hatena.com/?url=http%3A%2F%2Fnote.mu%2F" alt="" /> <a href="https://note.mu/wakusei2nd/n/n562b7d525897">なぜ日本が世界共通語「Emoji」を生み出したのか、そしてその影響とは/古川健介『TOKYO INTERNET』|PLANETS|note</a></cite><p><a href="https://note.mu/wakusei2nd/n/n562b7d525897"><img src="http://cdn-ak.b.st-hatena.com/entryimage/316512078-1484693699.jpg" alt="なぜ日本が世界共通語「Emoji」を生み出したのか、そしてその影響とは/古川健介『TOKYO INTERNET』|PLANETS|note" title="なぜ日本が世界共通語「Emoji」を生み出したのか、そしてその影響とは/古川健介『TOKYO INTERNET』|PLANETS|note" class="entry-image" /></a></p><p>なぜ日本が世界共通語「Emoji」を生み出したのか、そしてその影響とは/古川健介『TOKYO INTERNET』 ★☆★☆★☆★☆★☆★☆★☆★☆★☆ こちらの記事は、1/19(木)24:00までの期間限定で全文無料でお読みいただけます! ★☆★☆★☆★☆★☆★☆★☆★☆★☆ Daily PLANETS では毎月第2水曜日に、古川健介さんの連載『TOKYO INTERNET』を配信しています。連載...</p><p><a href="http://b.hatena.ne.jp/entry/https://note.mu/wakusei2nd/n/n562b7d525897"><img src="http://b.hatena.ne.jp/entry/image/https://note.mu/wakusei2nd/n/n562b7d525897" alt="はてなブックマーク - なぜ日本が世界共通語「Emoji」を生み出したのか、そしてその影響とは/古川健介『TOKYO INTERNET』|PLANETS|note" title="はてなブックマーク - なぜ日本が世界共通語「Emoji」を生み出したのか、そしてその影響とは/古川健介『TOKYO INTERNET』|PLANETS|note" border="0" style="border: none" /></a> <a href="http://b.hatena.ne.jp/append?https://note.mu/wakusei2nd/n/n562b7d525897"><img src="http://b.hatena.ne.jp/images/append.gif" border="0" alt="はてなブックマークに追加" title="はてなブックマークに追加" /></a></p></blockquote><img src="http://feeds.feedburner.com/~r/hatena/b/hotentry/~4/Yrhv1rRQwes" height="1" width="1" alt=""/>]]></content:encoded> <dc:date>2017-01-18T07:51:51+09:00</dc:date> <dc:subject>テクノロジー</dc:subject> <hatena:bookmarkcount>287</hatena:bookmarkcount> </item> ~後略~
なるほどね、itemタグからのtitleタグなのねと以下のように入れたら何も出なかった
In [1]: response.xpath('//item/title/text()').extract() Out[1]: []
公式のドキュメントにそれっぽい記述があった。
Selectors — Scrapy 1.3.0 documentation
Once in the shell we can try selecting all <link> objects and see that it doesn’t work (because the Atom XML namespace is obfuscating those nodes): But once we call the Selector.remove_namespaces() method, all nodes can be accessed directly by their names:
どうやらscrapyする相手がxmlとかrssとかatom形式の場合だと名前空間が邪魔して、素直に読めないからひと手間必要ということが分かった。
ということで以下のようにする
In [2]: response.selector.remove_namespaces() In [3]: response.xpath('//item/title/text()').extract() Out[3]: ['映画館でわざわざ(略)
これでOK。rssなどをscrapeした場合はresponse.selector.remove_namespaces()しないとデータが見えない。
ついでに<dc:subject>とかなってるタグ。そのままでは取れないけど、dcとかの前部分を無視してコロン以降の後部分を使えばデータが取れる
In [4]: response.xpath('//item/subject/text()').extract() Out[4]: ['エンタメ(略)
shellで検証した結果を受けて編集したSpiderとItem
- Spider
- Item
最後にcrawlが動かせれば出来上がり
scrapy crawl Hotentry (結果略)
scrapyを作る際はshellの検証が必須ですねぇ
関連記事
20161228アンテナ
自身のアンテナを書くのをマネしてみた。気が付いたらまた見直そう
アンテナ
- データサイエンス
- 技術
- IOT
- ビーコン
- RaspberryPI
- Arduino
- Edison
- Docker
- IOT
- 開発
- OS
- DB
- 開発環境
- Vim
- プラグイン
- vimshell
- PowerShell
- Vim
- 学問
- その他
- 手帳
- 文房具
- Amazonプライム
- ボルダリング
- ランニング
- サッカー
- 映画
- 本
今回はPython関係多めかな。
Jupyter Notebookの設定をする
JupyterNotebookの設定をする。導入はこちら
Jupyter notebookをホストのブラウザで使用する
Ubuntu on Virtualboxで運用しているので、Jupyterとか使用する際にはゲスト側ではなく、ホスト側のブラウザで実行すると捗る。ということでJupyterを起動する際には以下のようにしていた。
- ポートフォワードの設定
VMの設定→ネットワーク→NATアダプタ→ポートフォワーディング
ポートフォワードの設定をしておく。これをしておくとホスト側のブラウザなどでポートを指定すると、ゲスト側のポートにフォワードしてくれる。下段がJupyter用で、上段がDjango用に設定している。Djangoについては今回関係ないので割愛。
- jupyter notebook実行時のコマンド
cd my/favorite/notebook/directory jupyter notebook --ip=0.0.0.0
ipのオプションを付けることでアクセス制限をかけることが出来る。「0.0.0.0」はアクセス制限なし。これを利用してホスト側のブラウザでJupyterを使う。以上でホスト側のブラウザでhttp://localhost:8888を打つとゲストで起動しているJupyterを使うことが出来る。
jupyter_notebook_config
ということで、jupyter notebookを使うときはいつも同じディレクトリで動かしているし、ipの指定もしている。ついでに件のコマンドを打つとゲスト側でブラウザが立ち上がってくる。使わないのに。ということでこれを制御する方法。
まずはコンフィグファイルの生成
jupyter notebook --generate-config
~/.jupyter/jupyter_notebook_config.pyが生成される。このファイルを編集して設定する。
- ip指定
コンフィグファイルから「c.NotebookApp.ip」という文字列を探す。jupyterに設定できる項目はコメントアウトされているので、これを有効にするだけでいいようになっている。それでip指定は以下のように変更
c.NotebookApp.ip = '*'
- ディレクトリ指定
同様に「c.NotebookApp.notebook_dir」という文字列を探す。これを指定することでいつも同じディレクトリで動かせる。
c.NotebookApp.notebook_dir = 'your/favorite/notebook/directory'
- ブラウザの自動起動
「c.NotebookApp.open_browser」という文字列を探して設定。jupyter起動後にブラウザは自動起動しなくなる。
c.NotebookApp.open_browser = False
他のコメントアウトされている項目を見るとそれなりに想像がつきそうだが、自分の場合はこんな感じで十分かと。他の設定項目に関して知りたいのであれば公式ドキュメントを見てもらうといい。
Configuration Overview — Jupyter Notebook 5.0.0.dev documentation
これで以下のようにシンプルにコマンドを打てば設定どおりにjupyterが使える。
jupyter notebook
実はこの設定ファイル云々は本来ならばサーバ用の設定となる。運用しているサーバでjupyterを起動し、その際の挙動を設定ファイルで制御するという形だ。なので設定次第で、スマホでjupyterなんてこともできるようになる。
Powershellでzipファイルを作る
WindowsのエクスプローラとではファイルをZIPするには任意のファイル(またはフォルダ)をクリックして選択して、右クリののちにZIPしていると思われる。でもそういったGUIでの操作よりもCUIでできないものかと思った。
ZIPをCUIで作る
Windowsではcmd.exeではなく、powershellでできる。
- 構文
Compress-Archive -Path <target file> -Destination <file name>
- 基本形
Compress-Archive -Path a.txt -Destination archive.zip
- フォルダを指定する
Compress-Archive -Path my_folder -Destination archive.zip
- 拡張子を指定する場合
Compress-Archive -Path *.log -Destination archive.zip
- 複数指定する場合
Compress-Archive -Path a.txt, my_folder, *.log -Destination archive.zip
- cmd.exeから実行する場合
powershell Compress-Archive -Path *.txt -Destination archive.zip
この通りcmd.exeからもコマンドの前にpowershellをつけるだけで実行できるのでファイルをアーカイブするバッチが作れる。そもそもpowershellのスクリプトを作ればいいのだが、それはそれ。あとは「zip」とかでエイリアスを作っておくのもいい。
- zipでエイリアスを作る
Set-Alias zip Compress-Archive
このCompress-ArchiveコマンドレットはPowerShellV5からの導入なので、バージョンが低い場合は新しいのを入れる必要がある。
Powershellでリモート接続
WindowsでもCUIでリモート接続をしたいと思った。Powershellならできると聞いて早速試してみた。リモートデスクトップ接続しちゃえばいいじゃんなんてことは言わない!!
事前準備
まずは接続される側で設定が必要。PowerShellを起動してリモート接続をEnableにする。
Enable-PSRemoting
接続
接続する側でコマンドを打てば接続ができる。これは接続先としてcomputernameを指定するやり方。
Enter-PSSession -ComputerName <computername>
ファイルの編集
SSHならvimとかviとかエディタのコマンドを打ってファイルの編集が開始できるのだが、先方にvimが入っていたとしてもPowerShell内では動かなかった。ではどうすればいいのかということでそれ専用のコマンドを見つけた。
PSEdit <file-name>
ただし、「Windows PowerShell ISE」のv5以上でしかPSEditは動かなかったので注意。ということで、これでファイルの編集ができるようになった。接続後はPATHとかも先方の環境で通っているので、何かしらのEXEとか、設定済のタスクとかを先方の環境で実行ができる。
あとは
PowerShellをマスターしたいなぁ。でもほとんどはCMD.exeで事足りるんだよなぁ。