python (2)


WSGIDaemonProcessの謎

mod_wsgiを設定してみた。
環境は FreeBSD11 + Apache24。

ハマったのは、venv のパス。

/usr/local/lib/python3.6/venv

とかに設定してもダメ。encodings というモジュールがないです、と言われてしまう。

どうも大事なのは以下のコマンド。バーチャルホストのホームディレクトリ(あるいはApacheのドキュメントルートのひとつ上あたりのディレクトリ。要するにPythonアプリケーションをインストールしたあたり)で以下を実行する。

$ python -m venv ./venv

したらば、Apacheの設定ファイルに以下のような設定を書く。

<VirtualHost 127.0.0.1:80>
    ServerName www.example.com
    DocumentRoot /path/to/www.example.com/htdocs
    WSGIDaemonProcess www.example.com python-home=/path/to/www.example.com/venv threads=5
    WSGIProcessGroup www.example.com
    WSGIScriptAlias /myapp/ /path/to/www.example.com/myapp/myapp/wsgi.py process-group=www.example.com
    WSGIScriptReloading On
    <Directory /path/to/www.example.com/pyapp/pyapp>
        <Files wsgi.py>
            Require all granted
        </Files>
    </Directory>
</VirtualHost>

python-home=/path/to/www.example.com/venv は、さっき作った venv ディレクトリの絶対パス。

これでなんとか動きました。
が…。
今度は、djangoが認識されない。アプリをウェブから叩いて動かそうとすると、「djangoモジュールが見つからないです」(意訳)とapacheのエラーログに吐き出される。

どうして!? Django公式ドキュメント通りにやってるのに!
と悩むことしばし。

ふと基本に立ち返って「rootじゃダメだよなぁ」と、バーチャルホストのユーザーに切り替えて、バーチャルホストのユーザーディレクトリであれこれコマンドを打ち込んだら、なんとかなった。

わたしがハマった最大の要因は、すべての作業を root で行ったこと。
本来はバーチャルホストのユーザーで行わなくてはいけない。
(わたしはバーチャルホストごとにユーザーを分けています)

そして、バーチャルホストのユーザーディレクトリで完結するように「環境」を整えないといけない。
さすがはPython! PHPとは違う。

$ cd www.example.com
$ python -m venv ./venv
$ ./venv/bin/pip install django
$ ./venv/bin/django-admin startproject myapp
$ ... (以下python公式ドキュメントと同じ。)

こんな感じで、バーチャルホストのディレクトリで作業を完結させる。
すると、「モジュールないですエラー」は出なくなる。

次の問題は…「myappモジュールないですエラー」
わけがわからない…。




MeCab+python+JavaScriptでサイトにルビを振る

標題の通り。意外と簡単にできたので共有します。


※正規表現で先読みと後読みのアサーションを使っているため、最新のEcmaScriptでないと動作しません…PC版Chromeでしか動作しません…なんとかしたい…。


ではさっそく。

python:


#coding: utf-8

from mod_python import apache, util
import re
import json
import MeCab

def handler(req):
    # テキスト取得
    fs  = util.FieldStorage(req, True)
    q   = fs.getfirst("q", "")

    if q:
        tagger  = MeCab.Tagger("-Oyomi")
        node    = tagger.parseToNode(q)

        wordTable   = []
        a2n_regexp  = re.compile("^[あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわゐゑをんがぎぐげござじずぜぞだぢづでどばびぶべぼぱぴぷぺぽぁぃぅぇぉっゃゅょアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヰヱヲンガギグゲゴザジズゼゾダヂズデドバビブベボパピプペポァィゥェォッャュョヴ]+$")
        while node:
            wordTypes   = node.feature.split(',')
            if node.surface != "" and \
                len(wordTypes) >= 8 and \
                not a2n_regexp.match(node.surface) and \
                wordTypes[7] != node.surface:
                wordTable.append({
                    "y": wordTypes[7] or "*",
                    "k": node.surface or ""
                })
            node    = node.next
        sendJson(req, True, wordTable)

    else:
        sendJson(req, False)
    
    return apache.OK

# JSON形式で返答を返す。
def sendJson(req, result = False, returnValue = []):
    req.content_type    = "application/json; charset=utf-8"
    req.write(json.dumps({"result": result, "words": returnValue}, False, False))



JavaScript:

"use esversion:6";

(function($, d, w, undef) {
    "use strict";

    $(d).on("click", ".furigana-toggler", function(e) {
        if (!$(this).hasClass("on")) {
            $(this).remove();
            furiganaOn();
        }
        e.preventDefault()
    })

    function furiganaOn() {
        $("body").find("*:not([nodeType=1])").each(function() {
            let node = $(this);
            if (node.text() !== "") {
                $.post(
                    "/py/mecab.py/getFurigana",
                    {
                        q : node.text()
                    },
                    function(json) {
                        if (json.result === true && json.words !== undef) {
                            let text  = node.html();
                            let max   = json.words.length;
                            for (let i = 0; i < max; i++) {
                                let regex = new RegExp("(?<!<ruby>[^<>]*)" + json.words[i].k + "(?![^<]*<rt>" + json.words[i].y + "</rt></ruby>)");
                                text = text.replace(
                                    regex,
                                    "<ruby>" + json.words[i].k + "<rp>[</rp><rt>" + json.words[i].y + "</rt><rp>]</rp></ruby>"
                                );
                            }
                            node.html(text);
                        }
                    },
                    "json"
                );
            }
        });
    }
    
    function furiganaOff() {
        $("ruby.furigana, rp.furigana, rt.furigana").unwrap();
    }
})(jQuery, document, window);

pythonの方には何らかの認証機構をつけなければいけませんが、ひとまずこんな感じです。