ラベル Python の投稿を表示しています。 すべての投稿を表示
ラベル Python の投稿を表示しています。 すべての投稿を表示

2018年10月26日金曜日

paizaスキルチェックを攻略したい

paizaスキルチェックを攻略したい!

1.TDD覚えた!
2.何かプログラミングしたいなぁ...
3.そういえばpaizaにちょうど問題があるじゃん
4.とりあえず、TDDは置いといてpaizaってどんな問題があるんだろ?
5.やってみた
クリアできなかったTAT

悔しいから、クリアする方法を考える。

<考えたこと>
早さが足りなかった...
ただ早さのために、ソースコードの質は落としたくない
アルゴリズムを考える速度はあまり変わらない気がする
プロセスを見直すべきでは?
・そもそも、普段ブラウザ上でプログラミングしないじゃん
・ついでにTDDによる、小さなサイクルも取り入れたい

ということで、
今回の目標は
ローカル環境でプログラミングし、コピペで提出したい


ところで、ローカル環境でプログラミングするとき、paizaのブラウザ上で行うのと明確に違う部分が一つあります。
完成したプログラムがテストできない!
プログラミングの後半では、入出力のチェックが欠かせないけど、ローカル環境だと、テストできない。
テストケースは、問題に書いてあるけど、いちいち写してられない。

これは簡単に、テストケースをコピペできて、テストができるテストドライバが必要だなーってことでプログラミング。

ファイル構成
main.py - Paizaの課題を書くファイル
mini_test.py - TDD用のユニットテストを書くファイル
testTool.py - テストドライバを書くファイル
test_paiza.py - プログラムの完成を確認するテストを書くファイル
testcase.py - Paizaのテストケースをコピペするファイル
TODOLIST.txt ー 仕様や気になることをメモするファイル


このファイルをコピーして使うことを想定。
基本的に、main.pyとmini_test.py、testcase.txt、TODOLIST.txtは空のファイルで、ここに課題のプログラムを書く感じ。

test_paiza.pyにテストコードを書いて、テストに使うこまごまとした、インプットやアウトプットのメソッドはtestTool.pyにって感じで。
テストの成功判定にはPytestを使います。

まずは、paizaの出題形式を再現しないといけない。
paizaでは標準入力としてinput()の形でデータが流し込まれる。
さらに、その入力は1度ではなく複数回行われる。

例えば、こんな感じの割り算をして、商とあまりを答えさせるプログラムなら。
入力例
5
3
出力例
1
2
と、こんな感じ。pytestでテストを書くとなんとなくこんな感じになりそう。

>test_paiza.py
def test(capsys):
    testCase = ["5","3"]
    expected = "1\n2\n"
    test = main.program(input)
    test.start()
    out,err = capsys.readouterr()
    assert out == expected

なるほどなーと。
とりあえずinputとoutputいちいち手動で写してられないから何とかしないとね。
そもそも、ハードコーディングしているから、依存関係ぶっこ抜かないと。
先にハードコーディングのぶっこ抜きから。

inputMessage = "testCase,expected"
detabase = [(["5","3"],"1\n2\n"]),(["8","2"],"4\n0\n")]

@pytest.mark.parametrize(inputMessage,detabase)
def test(testCase,expected):
    test = main.program(input)
    test.start()
    out,err = capsys.readouterr()
    assert out == expected

これで、関数無いの値への依存はなくせた。
そのおかげで1つの関数で複数のテスト値が試せるように。

ただ、まだハードコーディングしているため、このままだと書き写すのに時間がかかってしまう。
テストファイルにコピペして、それを読み込むようにしたいなぁ...
ってことで、どんな感じでデータを扱いたいか決める。
>testcase.txt
5

3

1

2

8

2

4

0

こんな感じなら、すぐにコピペで済みそう。
さてさて、扱うデータの形を決めたら読み込み、変換の関数を...書きました。
(全部書くと長くなるので割愛)
getTestCase()

test_paiza.pyの中身は完成。

>test_paiza.py
import main
import pytest

def getTestCase():
   ..........#ここに読み込む関数を書く

detabase = getTestCase()
inputMessage = "testCase,expected"

@pytest.mark.parametrize(inputMessage,detabase)
def test(testCase,expected):
    test = main.program(input)
    test.start()
    out,err = capsys.readouterr()
    assert out == expected

さてさて、次に考えないといけないのは...
テストができたし、main.pyにどんな感じに課題コードを書くか決めないとなぁ...

さっきの割り算の問題をpaiza環境で書くとこんな感じ

num1 = input()
num2 = input()
print(num1/num2)
print(num1%num2)

ただ、pythonの標準入力関数input()を使っているが、実際にテストするときに手動入力は勘弁願いたい。
というわけで、完全にコピペで済むようにすることはあきらめて、こんな感じにする。

class program:
    def __init__(self.input:list):
        self.testcase =input

    def input(self):
        out = self.testcase[0]
        self.testcase.pop(0)
        return out

    def start(self):
        num1 = self.input()
        num2 = self.input()
        print(num1/num2)
        print(num1%num2)

これなら、start()の部分をコピペして、selfを消せば大丈夫ですね。
とはいえ、少しだけ見た目が悪い...
コンストラクタとinput()は親クラスに持たせてファイルを分割し、継承する形でprogramクラスを実装しましょう。
>main.py
from testTool import Drive

class program(Drive):
    def start(self):
        ・・・・・

あとは、testTool.pyにDriveクラスを移せば本日の作業終了です。

>testTool.py
class Drive:
    def __init__(self.input:list):
        self.testcase =input

    def input(self):
        out = self.testcase[0]
        self.testcase.pop(0)
        return out

    def start(self):
        pass



感想
実際に使ってみた感じ、とてもいい感じでした。
Cクラス問題までは、ブラウザで書きなぐったほうが早いですが、Bクラス問題くらいになると、自分の慣れた環境のほうがいいかなぁと。
今回プログラミングのスキルチェックを行う上で、アルゴリズムを考える能力だけが、プログラマーの実力じゃないなと思いました。
paizaスキルチェックでは、速さと正確さが求められている品質です。
これを達成するために、何をしてもいいと考えたとき(カンニングはだめですよ)、自分がどのようなスキルを持っていて、何ができるか、どうやって解決するかを見極めることも実力なのかなぁと思いました。

2018年10月13日土曜日

Dockerでpython環境を構築したい

Udemyのcomplete-python-bootcamp買っちゃった!(衝動買い)
こんな感じの
ついでに、講師のgitHubから飛んで買えば安くなるかも?よくわかんないけど

というわけで、環境構築
動画だと、Anaconda使うみたいっすね
ただ、動画通りにやっても面白くないし、自分のパソコンにはすでにAnaconda入ってるし
そして何より、環境分離したいし

てことで、今回はDockerつかってやろうかなーと

(現在2018/10/13)
(基本すべての作業をPowerShellで行っています)

今回の最終目標
1.Python3.7が使えるlinux環境を作る
2.Anacondaを使えるようにする
3.Jupyter notebookを使えるようにする
4.docker内でやる


2018年9月15日土曜日

Pythonでヤフーニュースをスクレイピング

最近スクレイピングの勉強しているから、目標を立てて使ってみる。
スクレイピングとは、ウェブサイトから情報を抽出するコンピュータソフトウェア技術のこと。らしいです。Wikipediaによると。

というわけで、情報集めを自動化できるようになりたいなぁってことで、練習練習。

目標:yahooニュースから更新されている記事の本文を取得する。

今回使うのはseleniumですね。ブラウザを自動操作できるテストツールらしいです。

水銀中毒に効きそうないい名前ですね!

pip install seleniumでインストールして、動かすためのブラウザも用意します。

このページからchromedriver.exeをダウンロード、カレントディレクトリーに置いておきます。



まずは必要そうなライブラリーをimportして、googlechromeでヤフーニュースのゲームタグを開きました。

"https://news.yahoo.co.jp/hl?c=game"

URLを変えれば好きなページでスクレイピングできます。

さて、開いたページから欲しそうな情報をどんどん引き抜いていきす。
とりあえず、記事のタイトルとURLが欲しいかな?
欲しい要素を右クリックして、検証を選んで



これだって感じのhtmlの行を見つけたら右クリックして、CSSセレクタをゲット。
CSSセレクタは要素を選択するための条件式みたいなものっぽい。
GoogleChromeは、html読まなくても、見つけられるから便利便利。



URL
#main > div.epCategory > div > ul > li:nth-child(1) > a
タイトル
#main > div.epCategory > div > ul > li:nth-child(1) > a > div > div.listFeedWrapCont > dl > dt

こんな感じのCSSセレクタがゲットできました。

find_elements_by_css_selector()という関数で、htmlを手に入れられるのでこんな感じで。


これ、取り出す要素が一つでもリストで帰ってくるのか...
li:nth-child(1)の1って数字が記事の1番目を指している気がするので、ここを変えれば全部の記事のタイトルとURLが手に入れられる気がする。
なんか、参考書で似たようなことをやるときにnth-of-type(n)って表記していたから、数字の代わりにnを入れれば、全部の要素を取り出せそう。

いいかんじ
このURLにをgooglechromeで開いて、記事の本文を見つければよさそう。
さっきやったことを繰り返して。

手に入れたURLをdriver.get()でページを開く。
タイトルと本文をリストに追加して、ページの情報をゲットです。



やっとできた。


<おまけ>
・前回起動したときなかった記事だけ欲しい
・記事をデータベース化して保存しておきたい
・ボイスロイドに読ませたい
って感じでコーディング


2018年9月5日水曜日

Pythonでしゃべっているときだけ録音する

VOICEROIDをプログラムに組み込めるようになったわけだし何か作ってみよう!

VOICEROIDをプログラムで動かせる方法を手に入れたわけだけど、どういうときに使うのがいいんだろうか...

しゃべることが決まっているなら、wavファイルにして、再生した方がいいです。
考えてみたところこんなことろかなぁと
1.人が出力する文章
2.自動で生成される文章

1だと、ゆかりねっととか、ブログやネット上の記事をスクレイピングとかでしょうか。
2だと、マルコフ連鎖とか、LSTMとか?

というわけで、まずは前例に倣って「音声認識して、VOICEROIDにしゃべらせる」を目指していこうかと。

流れ的には、録音→解析→VOICEROIDに投げる、の流れですね。

今回は録音できるようにソースコードを書いてみます。

Pythonで音を監視して一定以上の音量を録音する-Qiita

こちらの記事を参考に、
・一定音量を超えたら録音する
・録音状態で一定の音量を下回った時間が1秒を超えたら録音を終了する
を実現できるように少しだけ改良します。


import pyaudio
import wave
import numpy as np

threshold = 0.03
thresholdmin = 0.02
chunk = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
blank = 1
p = pyaudio.PyAudio()

stream = p.open(format = FORMAT,                            #(1)
    channels = CHANNELS,
    rate = RATE,
    input = True,
    frames_per_buffer = chunk
    )

sound=[]
while True:
    data = stream.read(chunk)                                      #(2)
    x = np.frombuffer(data, dtype="int16") / 32768.0
    if x.max() > threshold:                                            #(3)
        rec = 0
        filename = "test.wav"
        sound=[]
        sound.append(data)
        while rec < int(blank * RATE / chunk):
            data = stream.read(chunk)
           
            sound.append(data)
            x = np.frombuffer(data, dtype="int16") / 32768.0
            if x.max() < thresholdmin:                               #(4)
                rec += 1
            else:
                rec = 0
           
        data = b''.join(sound)
       
        out = wave.open(filename,'w')                              #(5)
        out.setnchannels(CHANNELS)
        out.setsampwidth(2)
        out.setframerate(RATE)
        out.writeframes(data)
        out.close()
       
        break

stream.close()
p.terminate()




こんな感じですね。
処理的には
(1)pyaudio.PyAudioのインスタンスstreamを生成
(2)streamのデータを手に入れる
(3)音量を調べて、threshold以上の音量ならばstreamのデータをsoundリストに保存
(4)thresholdmini以下の音量ならばカウントを初めて、1秒超えたらループから抜けるように
(5)wavファイルに保存

と、こんな感じでしょう。
(4)が少し変更した部分ですね。動かしてみて、マイクに話しかけるとtest.wavという音声ファイルができているはずです。

今回はここまでにしましょう。
次は、wavファイルを解析して、日本語にする感じですかね。



実は、「音声認識して、VOICEROIDにしゃべらせる」という、部分はもうずいぶん前にコードを書いて、すでに魔改造まで終わっちゃっているんですよね。
備忘録気分で始めたブログなので、最近やっていることも書きたいのに、たまりにたまったアウトプットしていないソースコードたちががが...

2018年9月4日火曜日

PythonでVOICEROIDを使う簡単な方法

VOICEROIDをプログラミングでしゃべらせたい!
というわけで、簡単に動かす方法を紹介します。
※Windows only


2018年9月3日月曜日