Python Mecab〜日本語を分解してみよう〜

イントロダクション

Javaの基本がわかったら今度は何か作ってみたいのが人情。。。今回は日本語を品詞分解してくれるライブラリ「Mecab」があったのでそれを使用する方法→開発環境のセットアップ方法を記載します。

Mecab本体のダウンロード

本家のホームページ

<手段1>:ブラウザにURLの部分に「https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7cENtOXlicTFaRUE」を入力してEnterキーを押下するとダウンロードできます。(tar.gz)ファイルなのでそれを解凍します。

展開したら下の様にコマンドを叩いてインストールします。(Mac & Linux)

    • 一般的なフリーソフトウェアと同じ手順でインストールできます。
       % tar zxfv mecab-X.X.tar.gz
       % cd mecab-X.X
       % ./configure 
       % make
       % make check
       % su
       # make install
      

辞書のインストール

% tar zxfv mecab-ipadic-2.7.0-XXXX.tar.gz
% mecab-ipadic-2.7.0-XXXX
% ./configure
% make
% su
# make install

Pythonから使える様にする

ダウンロードして展開したフォルダの直下に「README」ファイルがあるのでそれを開きます。自分のところにあったのは下の様に書いてありました。

MeCab python module

$Id: README,v 1.1.1.1 2005/12/03 14:18:50 taku-ku Exp $;

1. Installation

  % python setup.py build
  % su
  # python setup.py install
  
  You can change the install directory with the --prefix option. For example:

  % python setup.py install --prefix=/tmp/pybuild/foobar
  
2. How to use?

   see 'test.py' as a sample program.

このファイルがあるディレクトリ(フォルダ)と同じ場所に「setup.py」があるのでそれを叩けばオッケ!ターミナルを開いてこのディレクトリに移動します。ターミナルの細かい使用方法に関してはこちら

python setup.py

これで完了です。

ちょっと動かして見る。「python」コマンドでpythonコマンドの入力モードに入ります。ここでコードを作成して実行できます。

$python
>>> import MeCab
>>> m = MeCab.Tagger("-Ochasen")
>>> print m.parse("大好評!ハンコック KMMEESS")
大	ダイ	大	接頭詞-名詞接続		
好評	コウヒョウ	好評	名詞-一般		
!	!	!	名詞-サ変接続		
ハンコック	ハンコック	ハンコック	名詞-一般		
KMMEESS	KMMEESS	KMMEESS	名詞-固有名詞-組織		
EOS

とりあえずこんな感じでした。

MeCab インストール〜Pythonバインディングも〜

イントロダクション

前回は、楽天APIをやりました。なんとか検索〜結果の取得まで行きました。が「デザイン」で切羽詰まったのでアプローチを変更します。

動的ブログ生成

ブログを生成する様にプログラムを作成しようと思います。手順は以下の様にやろうと思っています、※できなかったら他の方法をやります。

  1. 自分で作成したカテゴリから乱数でどれかを選択する
  2. 指定されたカテゴリをキーワードにしてTwitter検索をかける
  3. 取得したツイートから初めの10件文のデータ(つぶやき)からキーワードになる値を取得する
  4. 取得したキーワードで楽天APIから商品候補を取得〜表示

この様に考えています。そして3の部分で使用するのが「Mecab」です。京都大学情報学研究科−日本電信電話株式会社コミュニケーション科学基礎研究所 共同研究ユニットプロジェクトで作成された様です。よーしいいぞ!日本!

そしてインストールして実行した結果

品詞分解してくれます。。。そしてこいつをPHPでしようしようじゃないかというわけです。

参考にしたサイトはこちら

とりあえず調べて見るとPHPでのバインディングなありませんでした。。。つまりPHPでは使用できないというわけです。。。駄菓子菓子!PHPもPythonもすでに触っているし、厄介なのは言語のナマリくらいだしPythonの方が親しみがあるのでそのまま行きます。ちなみにPHPでPythonを使用するときは以下の様にやります。

<?php 
   $command = "python XXXX.py"
   $res = exec($command);
?>

シンプルなものです。

MeCabPythonのインストール

ここからPythonバインディングをダウンロードします。ダウンロードした中にREADMEファイルがあるのでそれをみます。自分がみたものは下の様に書いてありました。

MeCab python module

$Id: README,v 1.1.1.1 2005/12/03 14:18:50 taku-ku Exp $;

1. Installation

  % python setup.py build
  % su
  # python setup.py install
  
  You can change the install directory with the --prefix option. For example:

  % python setup.py install --prefix=/tmp/pybuild/foobar
  
2. How to use?

   see 'test.py' as a sample program.

その通りにインストールします。そしてそれをサーバー上にアップロードします。あとはPHPからPythonにアクセスするだけで良い様にします。→Pythonでその様な処理を実装するという意味です。

でわでわ。。。


Python websocket client〜WebSocket送信処理を作る〜

イントロダクション(Introduction)

今まで悪戦苦闘してきましたが、ついに糸口を見つけました。(i was struggling to websocket)

人に聞いたりしてわかったこと(i found out by ask to my friends)

  1. Python2.Xは終わるらしいのでPython3.X以上を使う方が良い
  2. レンタルサーバーでやるならJS + PHPの方が早いかも?
  3. 人間諦めも必要だ

というわけで、サーバー、表示するクライアント画面はPHPで実装(i decided to use PHP)

Microbitでのシリアルデータの受信〜Webサーバーへの送信はPython3でやることにしました。

Python3.XならWebSocketクライアントを作れるので以下を参考に作成

https://websockets.readthedocs.io/en/stable/

Python WebSocket!

自分の環境では以下のモジュールが必要でした。ので下のコマンドでインストールします。(i had to install follow ing modules)

  1. asyncio
  2. websockets

ただ、上記のサイトには

pip install websockets

の様にコマンドを実行する様に記載してあったけど(i had used following command)

pip3 install websockets

の様にPython3を指定してやる必要がありました。

いざ!実装(Implementation)

<websocketSender.py>

import asyncio
import websockets
import json

async def hello():
    async with websockets.connect("ws://zenryokuservice.com:9000/demo/server.php") as websocket:
        mes = {
            'message': 'MicrobitData',
            'name': 'WebSocket.py',
            'color': '#0B4C5F'}
        await websocket.send(mes)
        print(mes)

asyncio.get_event_loop().run_until_complete(hello())

実行結果(Results)

アクセスするURLは

http://zenryokuservice.com/project/index.php

データやキャッシュを保存していないので一度画面を閉じると何も残りません。

そして、現状ではメッセージが全部「null」になっています。

修正しなくては。。。原因は送信するJSONデータがちゃんとJSONしていない様に睨んでいます。


関連ページ一覧

お手製リクエストを飛ばす〜HTTPメッセージに関して〜

イントロダクション

Socketでリクエストを飛ばす方法を探していて見つけたのでメモ

HTTPリクエストの中身

要点1:HTTPリクエストとは?

「HTTPリクエストはクライアントが送信してサーバーにアクションを起こさせるリクエストと、サーバーの回答であるレスポンスの、2 種類のメッセージがあります。」

要点2:HTTPリクエストのデータ形式

「HTTP メッセージは ASCII でエンコードされたテキスト情報で構成されており、複数の行にまたがります。」

<HTTPメッセージ>

POST / HTTP/1.1
Host: localhost:8000
Connection: keep-alive
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36
Sec-Metadata: destination=image, site=same-origin
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Referer: http://localhost:8000/
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.9,en;q=0.8

<メソッド>

・POST / HTTP/1.1
・GET /background.png HTTP/1.0

・HEAD /test.html?query=alibaba HTTP/1.1
・OPTIONS /anypage.html HTTP/1.0

ちょっと試してみる

通常HTTPヘッダなどを直接指定することはない(だいたいアプリケーション(フレームワークなど)側でやっている)ので今まで触らなかったがヘッダ情報にオリジナルのヘッダを加えてみた。

オリジナルヘッダ追加リクエスト

>>>> Testing <<<<<
127.0.0.1 - - [13/Dec/2018 14:54:35] "GET / HTTP/1.1" 200 -
Created Header!
File CLosed!
*** POST ***
Content-Length: 16
Content-Type: text/plain
Message: Hello

「Hello」は引数で与えたもので、実際に渡す値はなんでも良い(テキストであれば)



<オリジナルヘッダを入れた場合>

*** POST ***
Content-Length: 16
Content-Type: text/plain
Message: Hello

*** BODY ***
Hello

<オリジナルヘッダを入れない場合>

*** POST ***
Content-Length: 0
Content-Type: text/plain

*** BODY ***
None

 

Python HTTPServer 〜Soket送信時のエラー対処〜

イントロダクション

PythonのSocketからHTTPServerへのデータ送信後にレスポンスを返そうとするとエラーになる、ちなみにURLにブラウザでアクセスしたときは問題なく表示する。

<エラーメッセージ>

Exception happened during processing of request from ('127.0.0.1', 50519)
  ・
  ・
self._sock.sendall(view[write_offset:write_offset+buffer_size])
error: [Errno 32] Broken pipe

<HTTPServer>

class MyMinimumServerHandler(BaseHTTPRequestHandler):
    def do_PSOT(self):
        print(self.headers)
        file_path = os.getcwd() + "/first.html"
        print("*******" + file_path + "********")
        print("*******" + self.path + "********")
        try:
            self.path = os.getcwd()
            print("File Open: " + file_path)
            #file = open(file_path)
            self.send_response(200)
            self.send_header('Content-type','text-html')
            self.end_headers()
            print("Created Header!")
            self.wfile.write("Hello")
            #self.wfile.write(file.read())
            #file.close()
            print("File CLosed!")
            return
        except  IOError:
                self.send_error(400, 'File Nout Found...')

<送信側:Socket>

def sendServer(msg):
    HOST = "localhost"
    PORT = 8000
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((HOST, PORT))
    s.send("GET / HTTP/1.1\r\n\r\n")
    s.send(msg)
    data = s.recv(1024)
    print(repr(data))
    s.close()

このエラーは、上の赤い字の部分に原因がありエンコードを指定しないといけないようでした。

解決1

self.wfile.write("Hello") → self.wfile.write(message.encode('utf-8')

※「message」は変数です。出力する文字をエンコード処理すると言うことです。

エラー2

一難去ってまた一難。。。

code 501, message Unsupported method ('POST')

上のようなエラーメッセージが出ました。

解決2

メソッドの定義ミスでした。サーバー「do_PSOT」→「do_POST」が正しい

エラー3

error: [Errno 32] Broken pipe

これはこのサイトを参照しました。が解決には至らず。。。

これは、ブラウザに返信の処理を行う場合はエラーが出ず、Socket送信した時に出るエラーなのですが、よく考えてみれば表示(出力)先がないならエラーになるよなぁ。。。

結果

レスポンスを返却する時に受けるもの(ブラウザなど)がないとエラーになる!当たり前か。。。


関連ページ一覧

Python Socket Server〜Python低水準ソケット通信〜

イントロダクション

タイトルにある「低水準」を見て「しょっぱそうな。。。」と感じた方、大外れでございます。

最近の言い方だと「ローレベルAPI」に属するAPI(クラス)で低水準(ローレベル)=細かい設定がいらないと言うことです。

その代わり、高レベルAPI(クラス)と違い、便利な機能が付いていないため自分で実装する必要があります。今回使用する「socket」に関しても同様なことが言えます。

いざSocket通信

もしかしたら「pip install socket」とコマンドを打つ必要があるかもしれません。今までに色々とインストールしたもので。。。

今回は、簡単なソケット通信を行い(実装し)ます。ソケット通信は古い技術です、細かいことはPyhonドキュメントを参照されたし。

概要

ソケットサーバーとクライアントを作成して以下のことを確認します。

  1. クライアントからデータを飛ばす
  2. サーバーで受け取ったものをコンソールに表示
  3. クライアントでレスポンスを受ける

実際に実行するときは、pythonを2つ起動するのでコンソール(ターミナル)も2つ立ち上げた状態になります。※背景にワードプレスくさいのがありますが、気にしないでください。。。

<実行結果:クライアント>

<実行結果:ソケットサーバー>


これは、Pythonだけで完結することができますが今までの経緯もあり、Microbitからの入力を受け付けてソケットサーバーへ通信しました。

  1. MicrobitでHttpリクエストを飛ばすためのメモ
  2. Microbitで遊ぶ〜ボタンを押す〜
  3. Microbitで遊ぶ〜シリアル通信をする〜
  4. Microbit Python 〜シリアル通信データを受け取る〜

<クライアントサイドのPythonコード>

import serial
import time
import socket

import socketTest

def main():
    # マイクロビットからシリアル通信を受け取る処理
    ser = serial.Serial('/dev/tty.usbmodemFA132', 115200,  timeout=3)
    ser.flushInput()
    ser.flushOutput()
    while True:
        try:
            print("Send data from Micro Bit with in 3 seconds!")
            data_raw = ser.read(10)
            if (data_raw != ""):
                print(data_raw)
                # シリアル通信で受け取ったデータをソケットサーバーへ
                sendServer(data_raw)
            else:
                print("It is Time out try one more!")

        except:
            print("Error")
        else:
            print("End Program")
            ser.close()
            break

def sendServer(msg):
    HOST = "localhost"
    PORT = 8000
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((HOST, PORT))
    s.send(msg)
    # サーバーからの返信を受け取る
    data = s.recv(1024)
    print(repr(data))
    s.close()

if __name__ == '__main__':
    # 「__name__」の値がメインの時※「__name__」にはいろんな値が入ってくる
    main()

<サーバーサイドのPythonコード>

import socket
import time

def main():
    print("Exe MySocket.py")
    server = initSocket()
    #s.connect( ( "localhost", 8000 ) )
    # ソケットサーバーの受信開始処理
    con, addr = server.accept()
    print("Got connection: ")
    print(addr)
    while True:
        #クライアントからのデータ受信
        data = con.recv(1024)
        print(data)
        if not data:
            print("there is no data...")
            break
        con.send("getMessage!: " + data)

    print("Good bye!")
    con.close()

def initSocket():
    # ソケットの初期処理
    port = 8000
    sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
    sock.bind(('', port))
    sock.listen(5)
    print("start listen...")
    return sock

if __name__ == '__main__':
    main()

あとは改造して、何をやろうかな?といった感じです。

関連ページ一覧

Python Http リクエスト メモ

イントロダクション

pythonでhttpサーバを起動出来るようだ。早速試してみるがimportに失敗する。

打開策

仕様してるpythonのバージョンにより以下の2種類のクラスを使う

  1. http.server
  2. SimpleHttpServer

2.の方は直接クラスをインポートするのに対し1.はパッケージをインポートする。

作成するサーバのルートディレクトリ(フォルダ)は作成したpyファイルのあるディレクトリになるようだ。

pythonでhttpサーバを作る方法はインターネット上に結構あるので問題なさそうだ(日本語のページがある)

あとは、画面のデザインを考える必要がある…一番の難敵だな…

インポートしたもの(Python)

pip install http.server

pip install SimpleHttpServer

python socket programming

リクエストの送信方法

上記の実装を行なったが、web socketのような処理は実現出来なかった。

リクエストに対して、ハンドルを行う「do_GET」メソッドに返信用のソケットを使用するつもりだったが同じURLに複数のソケットはバインドできない。(当然だな…)ので他の方法を考える