2017年8月13日日曜日

使用されている CSS のみ抽出したり整形したり

環境: Ubuntu 16.04.2 LTS


Sphinx の html 文書を用意

使用されている CSS のみ抽出したり、整形したりする対象として、Sphinx の html 文書を用意します。

パッケージインストール

$ sudo apt install python3-sphinx
$ sudo apt install make

Sphinx 文書を作成

$ mkdir sphinx
$ cd sphinx/
$ sphinx-quickstart
$ make html

$ ls -la build/html/
total 40
drwxrwxr-x 4 ubuntu ubuntu 4096 Aug 13 16:47 .
drwxrwxr-x 4 ubuntu ubuntu 4096 Aug 13 16:47 ..
-rw-rw-r-- 1 ubuntu ubuntu  230 Aug 13 16:47 .buildinfo
-rw-rw-r-- 1 ubuntu ubuntu 2541 Aug 13 16:47 genindex.html
-rw-rw-r-- 1 ubuntu ubuntu 3770 Aug 13 16:47 index.html
-rw-rw-r-- 1 ubuntu ubuntu  197 Aug 13 16:47 objects.inv
-rw-rw-r-- 1 ubuntu ubuntu 2943 Aug 13 16:47 search.html
-rw-rw-r-- 1 ubuntu ubuntu  240 Aug 13 16:47 searchindex.js
drwxrwxr-x 2 ubuntu ubuntu 4096 Aug 13 16:47 _sources
drwxrwxr-x 2 ubuntu ubuntu 4096 Aug 13 16:47 _static

作成した Sphinx 文書の index.html ファイルで使用している CSS ファイルを確認

$ head -n 20 build/html/index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <title>Welcome to aaa’s documentation! &mdash; aaa ccc documentation</title>

    <link rel="stylesheet" href="_static/alabaster.css" type="text/css" />
    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />

    <script type="text/javascript">
      var DOCUMENTATION_OPTIONS = {
        URL_ROOT:    './',
        VERSION:     'ccc',
        COLLAPSE_INDEX: false,
        FILE_SUFFIX: '.html',
        HAS_SOURCE:  true

以下の CSS ファイルを使っていました。

  • _static/alabaster.css
  • _static/pygments.css

CSS ファイルのサイズを確認

$ ls -l build/html/_static/alabaster.css build/html/_static/pygments.css
-rw-rw-r-- 1 ubuntu ubuntu 9220 Aug 13 16:47 build/html/_static/alabaster.css
-rw-rw-r-- 1 ubuntu ubuntu 4149 Aug 13 16:47 build/html/_static/pygments.css

2つの CSS ファイルをあわせて 13KBytes 程度です。

これらの CSS ファイルには実際には使用されていない CSS やコメントも含まれています。


使用されている CSS のみ抽出

UnCSS を使って、使用されている CSS のみ抽出します。

パッケージインストール

$ sudo apt install nodejs
$ sudo apt install npm

node という名前で nodejs を使えるようにします

$ sudo update-alternatives --install /usr/bin/node node /usr/bin/nodejs 10

$ ls -la /usr/bin/node
lrwxrwxrwx 1 root root 22 Aug 13 17:14 /usr/bin/node -> /etc/alternatives/node

$ ls -la /etc/alternatives/node
lrwxrwxrwx 1 root root 15 Aug 13 17:14 /etc/alternatives/node -> /usr/bin/nodejs

UnCSS インストール

$ sudo npm install -g uncss

使用されている CSS のみ抽出

$ uncss build/html/index.html > build/html/_static/res.css

使用されている CSS のみ抽出され、サイズが 13KBytes 程度から 6KBytes 程度に減りました。

$ ls -l build/html/_static/res.css
-rw-rw-r-- 1 ubuntu ubuntu 5943 Aug 13 18:05 build/html/_static/res.css

CSS ファイルを整形

res.css のファイルの最後は以下のようになっていました。

$ tail build/html/_static/res.css

/* misc. */

/* Make nested-list/multi-paragraph items look better in Releases changelog
 * pages. Without this, docutils' magical list fuckery causes inconsistent
 * formatting between different release sub-lists.
 */

/* Hide fugly table cell borders in ..bibliography:: directive output */
/*** uncss> filename: build/html/_static/pygments.css ***/ /* Comment */ /* Error */ /* Keyword */ /* Operator */ /* Comment.Hashbang */ /* Comment.Multiline */ /* Comment.Preproc */ /* Comment.PreprocFile */ /* Comment.Single */ /* Comment.Special */ /* Generic.Deleted */ /* Generic.Emph */ /* Generic.Error */ /* Generic.Heading */ /* Generic.Inserted */ /* Generic.Output */ /* Generic.Prompt */ /* Generic.Strong */ /* Generic.Subheading */ /* Generic.Traceback */ /* Keyword.Constant */ /* Keyword.Declaration */ /* Keyword.Namespace */ /* Keyword.Pseudo */ /* Keyword.Reserved */ /* Keyword.Type */ /* Literal.Number */ /* Literal.String */ /* Name.Attribute */ /* Name.Builtin */ /* Name.Class */ /* Name.Constant */ /* Name.Decorator */ /* Name.Entity */ /* Name.Exception */ /* Name.Function */ /* Name.Label */ /* Name.Namespace */ /* Name.Tag */ /* Name.Variable */ /* Operator.Word */ /* Text.Whitespace */ /* Literal.Number.Bin */ /* Literal.Number.Float */ /* Literal.Number.Hex */ /* Literal.Number.Integer */ /* Literal.Number.Oct */ /* Literal.String.Backtick */ /* Literal.String.Char */ /* Literal.String.Doc */ /* Literal.String.Double */ /* Literal.String.Escape */ /* Literal.String.Heredoc */ /* Literal.String.Interpol */ /* Literal.String.Other */ /* Literal.String.Regex */ /* Literal.String.Single */ /* Literal.String.Symbol */ /* Name.Builtin.Pseudo */ /* Name.Variable.Class */ /* Name.Variable.Global */ /* Name.Variable.Instance */ /* Literal.Number.Integer.Long */

改行されておらず、可読性が低いので整形します。

パッケージインストール

$ sudo apt install python3-cssutils

以下のように Python スクリプト作成

$ cat test.py
#!/usr/bin/env python3

import cssutils

sheet = cssutils.parseFile('build/html/_static/res.css')
print(sheet.cssText.decode())

CSS ファイルを整形

$ ./test.py > build/html/_static/res2.css

res2.css の中身を見ると、整形されていることを確認できます。



2017年8月12日土曜日

2段階認証プロセスを使用した Google アカウントを使って Python からメール送信

Google のメールサーバーを使って Python からメール送信する場合、スクリプト内部にて Google アカウントでメールサーバーにログインする必要があります。

しかし、ログインに使用する Google アカウントに 2段階認証プロセスが使われている場合は Google サービスへのログインパスワードではなく、アプリパスワードを Google のサイトで生成し、このアプリパスワードでメールサーバーにログインする必要があります。


Google アカウントのアプリパスワードを生成

このあたりを参考にしてアプリパスワードを生成します。

https://support.google.com/mail/answer/185833?hl=ja


Python スクリプトからメール送信

以下の内容でメールを送信するサンプルコードです。

サンプルコード

#!/usr/bin/env python3

from smtplib import SMTP
from email.mime.text import MIMEText
from email.header import Header

GOOGLE_ACCOUNT = 'example@gmail.com'
APP_PASSWORD = 'xxxxxxxxxxxxxxxx'

def send_mail(to_addrs, subject, mail_body, sub_type='plain'):
    smtp_server = 'smtp.gmail.com'
    port = 587
    from_addr = GOOGLE_ACCOUNT
    encoding = 'utf-8'

    msg = MIMEText(mail_body.encode(encoding), sub_type, encoding)
    msg['Subject'] = Header(subject, encoding)
    msg['From'] = from_addr
    msg['To'] = ', '.join(to_addrs)

    server = SMTP(smtp_server, port)
    server.starttls()
    server.login(GOOGLE_ACCOUNT, APP_PASSWORD)
    server.sendmail(from_addr, to_addrs, msg.as_string())
    server.quit()

body = '''
ほげほげ
ふがふが
ぴよぴよ
'''.strip()

send_mail(['addr1@xxx.example.net', 'addr2@yyy.example.net', 'addr3@zzz.example.net'], 'テストメール', body)

HTML メールを送信

HTML メールを送信する場合は send_mail() の引数 sub_type に ‘html’ を指定します。

html_body = '''
<table border=1>
    <tr><th></th><th>あああ</th><th>いいい</th></tr>
    <tr><td>ううう</td><td>えええ</td><td>おおお</td></tr>
    <tr><td>かかか</td><td>ききき</td><td>くくく</td></tr>
    <tr><td>けけけ</td><td>こここ</td><td>さささ</td></tr>
</table>
'''.strip()

send_mail(['addr1@xxx.example.net', 'addr2@yyy.example.net', 'addr3@zzz.example.net'], 'テスト HTML メール', html_body, 'html')

2017年7月11日火曜日

pdftk で pdf ファイルを結合

pdftk で pdf ファイルを結合してみました。

$ pdftk original1.pdf original2.pdf original3.pdf cat output new.pdf

以下のサイトには回転や分割の方法なども載っています。


2017年1月29日日曜日

Google App Engine で cron

app.yaml と同じ場所に cron.yaml を設置

$ cat cron.yaml
cron:
- description: kick continuously
  url: /
  schedule: every 5 minutes

cron.yaml の書き方はこのあたりを参照

デプロイ

$ gcloud app deploy app.yaml cron.yaml --project PROJECT_ID
  • cron.yaml も指定する必要がありました。

2017年1月28日土曜日

Google App Engine で ソースコードを編集

Google App Engine で Python サンプルアプリをデプロイ でデプロイしたサンプルアプリを編集してみます。

今まで、[Hello World!] と表示されていたものを [Hello Python!] と表示されるように編集します。


環境

  • Ubuntu 16.04.1 LTS

Google Cloud SDK をインストール

パッケージをインストール

$ sudo apt install wget
$ sudo apt install git

Create an environment variable for the correct distribution

$ export CLOUD_SDK_REPO="cloud-sdk-$(lsb_release -c -s)"

$ echo ${CLOUD_SDK_REPO}
cloud-sdk-xenial

Add the Cloud SDK distribution URI as a package source

$ echo "deb https://packages.cloud.google.com/apt $CLOUD_SDK_REPO main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
deb https://packages.cloud.google.com/apt cloud-sdk-xenial main

$ ls -la /etc/apt/sources.list.d/
total 12
drwxr-xr-x 2 root root 4096 Jan 28 17:18 .
drwxr-xr-x 6 root root 4096 Jan  2 15:25 ..
-rw-r--r-- 1 root root   64 Jan 28 17:18 google-cloud-sdk.list

$ cat /etc/apt/sources.list.d/google-cloud-sdk.list
deb https://packages.cloud.google.com/apt cloud-sdk-xenial main

Import the Google Cloud Platform public key

$ wget https://packages.cloud.google.com/apt/doc/apt-key.gpg -O - | sudo apt-key add -
  • 参考にしたページでは crul を使って apt-key.gpg をダウンロードしていましたが、なぜかうまくいかなかったので wget を使いました。

Update the package list and install the Cloud SDK

$ sudo apt-get update && sudo apt-get install google-cloud-sdk

$ which gcloud
/usr/bin/gcloud

認証

以下実行

$ gcloud init

[You must log in to continue. Would you like to log in (Y/n)?] で [Y] を入力

[ Go to the following link in your browser: ] と表示され、https://accounts.google.com/o/oauth2/auth?redirect_uri=... で始まる URL が表示されたのでブラウザで開く

Google アカウントを選択

[Google Cloud SDK が次の許可をリクエストしています] と表示されたので内容を確認して [許可] をクリック

[このコードをコピーし、アプリケーションに切り替えて貼り付けてください] に続き、コードが表示された

コマンドの画面に戻り、[Enter verification code] にブラウザで表示されたコードを張り付け

[Pick cloud project to use] が表示されたので [mytest-20161229] を選択


App Engine アプリのソースコードを編集

リポジトリを確認

Google Developers Console にアクセス

プロジェクトを選択

左上のメニューアイコンをクリックし [開発] を選択

左側のメニューで「レポジトリ」をクリック

以前にデプロイしたサンプルアプリのリポジトリ名 [python-gae-quickstart] を確認できたのでこのリポジトリのソースコードを編集します。

Cloud Repository をローカルにクローン

$ gcloud source repos clone python-gae-quickstart --project=mytest-20161229

ローカルの Git リポジトリに移動

$ cd python-gae-quickstart/

ディレクトリの内容を確認

$ ls -la
total 60
drwxrwxr-x 4 ubuntu ubuntu  4096 Jan 28 21:08 .
drwxrwxr-x 3 ubuntu ubuntu  4096 Jan 28 21:08 ..
-rw-rw-r-- 1 ubuntu ubuntu   247 Jan 28 21:08 appengine_config.py
-rw-rw-r-- 1 ubuntu ubuntu   170 Jan 28 21:08 app.yaml
-rw-rw-r-- 1 ubuntu ubuntu  3045 Jan 28 21:08 CONTRIB.md
drwxrwxr-x 8 ubuntu ubuntu  4096 Jan 28 21:08 .git
drwxrwxr-x 4 ubuntu ubuntu  4096 Jan 28 21:08 lib
-rw-rw-r-- 1 ubuntu ubuntu 11357 Jan 28 21:08 LICENSE
-rw-rw-r-- 1 ubuntu ubuntu   424 Jan 28 21:08 main.py
-rw-rw-r-- 1 ubuntu ubuntu   342 Jan 28 21:08 .playground
-rw-rw-r-- 1 ubuntu ubuntu  2761 Jan 28 21:08 README.md
-rw-rw-r-- 1 ubuntu ubuntu   275 Jan 28 21:08 requirements.txt
-rw-rw-r-- 1 ubuntu ubuntu  2812 Jan 28 21:08 vendor.py

Git のメールアドレスとユーザー名を設定

$ git config --global user.email "Gmail のメールアドレス"

$ git config --global user.name "名前"

試しに main.py を編集

編集した箇所を確認

$ git diff
diff --git a/main.py b/main.py
index 0438961..72d3af2 100644
--- a/main.py
+++ b/main.py
@@ -9,7 +9,7 @@ app.config['DEBUG'] = True
 @app.route('/')
 def hello():
     """Return a friendly HTTP greeting."""
-    return 'Hello World!'
+    return 'Hello Python!'


 @app.errorhandler(404)

インデックスに編集した main.py を追加

$ git add main.py

コミット

$ git commit -m 'test edit'

Cloud Repository に push

$ git push -u origin master

Cloud Repository を GAE アプリに反映

Google Cloud Shell を開始

Google Developers Console にアクセス

プロジェクトを選択

上部にあるナビゲーションバーで Cloud Shell のアイコンをクリック

Cloud Shell でプロジェクトのディレクトリに移動

$ cd src/mytest-20161229/

Cloud Repository からクローン

$ gcloud source repos clone python-gae-quickstart --project=mytest-20161229

ディレクトリを確認

$ ls -la
total 16
drwxr-xr-x 4 fishrimper fishrimper 4096 Jan 28 23:29 .
drwxr-xr-x 4 fishrimper fishrimper 4096 Jan 28 16:03 ..
drwxr-xr-x 4 fishrimper fishrimper 4096 Jan 28 23:29 python-gae-quickstart
drwxr-xr-x 4 fishrimper fishrimper 4096 Jan 28 22:31 python_gae_quickstart-2016-12-29-22-39
  • python-gae-quickstart/ が今回クローンしたディレクトリ
  • python_gae_quickstart-2016-12-29-22-39/ が前回クローンしたディレクトリ

今回クローンしたディレクトリを確認

$ cd python-gae-quickstart/

$ ls -la
total 60
drwxr-xr-x 4 fishrimper fishrimper  4096 Jan 28 23:29 .
drwxr-xr-x 4 fishrimper fishrimper  4096 Jan 28 23:29 ..
-rw-r--r-- 1 fishrimper fishrimper   247 Jan 28 23:29 appengine_config.py
-rw-r--r-- 1 fishrimper fishrimper   170 Jan 28 23:29 app.yaml
-rw-r--r-- 1 fishrimper fishrimper  3045 Jan 28 23:29 CONTRIB.md
drwxr-xr-x 8 fishrimper fishrimper  4096 Jan 28 23:29 .git
drwxr-xr-x 4 fishrimper fishrimper  4096 Jan 28 23:29 lib
-rw-r--r-- 1 fishrimper fishrimper 11357 Jan 28 23:29 LICENSE
-rw-r--r-- 1 fishrimper fishrimper   425 Jan 28 23:29 main.py
-rw-r--r-- 1 fishrimper fishrimper   342 Jan 28 23:29 .playground
-rw-r--r-- 1 fishrimper fishrimper  2761 Jan 28 23:29 README.md
-rw-r--r-- 1 fishrimper fishrimper   275 Jan 28 23:29 requirements.txt
-rw-r--r-- 1 fishrimper fishrimper  2812 Jan 28 23:29 vendor.py

$ cat main.py
from flask import Flask
app = Flask(__name__)
app.config['DEBUG'] = True

# Note: We don't need to call run() since our application is embedded within
# the App Engine WSGI application server.


@app.route('/')
def hello():
    """Return a friendly HTTP greeting."""
    return 'Hello Python!'


@app.errorhandler(404)
def page_not_found(e):
    """Return a custom 404 error."""
    return 'Sorry, nothing at this URL.', 404

アプリをテスト

プレビューインスタンスの開始

$ dev_appserver.py ./app.yaml

「ウェブでプレビュー」でアプリをプレビュー

Cloud Shell 上部の「ウェブでプレビュー」アイコンをクリック

「ポート上でプレビュー 8080」を選択

ブラウザでプレビューが開かれ、「Hello Python!」と表示されました。

プレビューインスタンスの終了

Cloud Shell で Ctrl+C キーを押して、アプリケーションのインスタンスを終了

アプリをデプロイ

$ gcloud app deploy app.yaml --project mytest-20161229
You are about to deploy the following services:
 - mytest-20161229/default/20170128t234354 (from [/home/fishrimper/src/mytest-20161229/python-gae-quickstart/app.yaml])
     Deploying to URL: [https://mytest-20161229.appspot.com]
Do you want to continue (Y/n)?

Y 入力して続けました。

変更されたこと確認

$ w3m -dump https://mytest-20161229.appspot.com
Hello Python!

2017年1月8日日曜日

LXC ホストのディレクトリをコンテナでマウント

環境

Ubuntu 16.04 LTS (Xenial) Server

LXC ホストの /some/where/dir ディレクトリを lxc_ubuntu コンテナの /mnt/test ディレクトリにマウントします。

コンテナで /mnt/test マウントポイントを作成

$ sudo mkdir /mnt/test

ホストで /some/where/dir ディレクトリ作成

$ sudo mkdir -p /some/where/dir

ホストでコンテナの config ファイルの最後に以下追加

# pwd
/var/lib/lxc/lxc_ubuntu

# diff -u config.org config
--- config.org  2017-01-08 20:14:33.727390784 +0900
+++ config      2017-01-08 20:16:04.865214903 +0900
@@ -21,3 +21,5 @@
 lxc.network.link = lxcbr0
 lxc.network.flags = up
 lxc.network.hwaddr = 00:16:3e:22:22:ef
+
+lxc.mount.entry = /some/where/dir mnt/test none bind,create=dir 0 0

コンテナを再起動すると以下のようにマウントされました。

$ mount | grep test
/dev/sda1 on /mnt/test type ext4 (rw,relatime,errors=remount-ro,data=ordered)

LXC ホスト OS 起動時にコンテナも自動起動

環境

Ubuntu 16.04 LTS (Xenial) Server

LXC コンテナをリストして確認すると、デフォルトでは AUTOSTART が 0 となっておりホスト OS 起動時にコンテナはシャットダウンされています。

$ sudo lxc-ls --fancy
NAME       STATE   AUTOSTART GROUPS IPV4 IPV6
lxc_clone  STOPPED 0         -      -    -
lxc_ubuntu STOPPED 0         -      -    -

lxc_ubuntu コンテナの AUTOSTART を 1 にし、ホスト OS 起動時に自動起動するようにします。

コンテナの config ファイルの最後に lxc.start.auto = 1 を追加

# pwd
/var/lib/lxc/lxc_ubuntu

# diff -u config.org config
--- config.org  2017-01-02 15:30:59.557679188 +0900
+++ config      2017-01-08 17:49:43.151352672 +0900
@@ -21,3 +21,5 @@
 lxc.network.link = lxcbr0
 lxc.network.flags = up
 lxc.network.hwaddr = 00:16:3e:22:22:ef
+
+lxc.start.auto = 1

AUTOSTART が 1 になりました。

$ sudo lxc-ls --fancy
NAME       STATE   AUTOSTART GROUPS IPV4 IPV6
lxc_clone  STOPPED 0         -      -    -
lxc_ubuntu STOPPED 1         -      -    -

ホスト OS を再起動すると、lxc_ubuntu コンテナも起動しています。

$ sudo lxc-ls --fancy
NAME       STATE   AUTOSTART GROUPS IPV4      IPV6
lxc_clone  STOPPED 0         -      -         -
lxc_ubuntu RUNNING 1         -      10.0.3.69 -