投稿者「nktk」のアーカイブ

BeautifulSoupにてあるタグ配下のhtmlをそのまま出力したい

あるタグ配下の文字列を取得したい場合は、.stringを用いて以下のように書ける。
例:

from bs4 import BeautifulSoup

html = "<div>test</div>"
soup = BeautifulSoup(html, "html.parser")
print(soup.find("div").string)
出力結果test

ただし、取得したタグ配下に、さらにほかのタグがあると.stringプロパティはNoneを返す。
そのような場合は、
1. .textプロパティを用いる(配下のタグはすべて削除される)
2. str関数で文字列に変換する(自身のタグも出力される)
3. .contentsにて、配下のタグを全て取得し文字列に変換する(自身のタグは出力されない)
などが考えられると思う。

例 :

from bs4 import BeautifulSoup

html = "<div>test <br>hoge1 <div><div>hoge2</div></div> <br>hoge3</div>"
soup = BeautifulSoup(html, "html.parser")
first_div = soup.find("div")

print("0 : " + str(first_div.string))
print("1 : " + first_div.text)
print("2 : " + str(first_div))
print("3 : " + "".join(map(str, first_div.contents)))
出力結果0 : None
1 : test hoge1 hoge2 hoge3
2 : <div>test <br/>hoge1 <div><div>hoge2</div></div> <br/>hoge3</div>
3 : test <br/>hoge1 <div><div>hoge2</div></div> <br/>hoge3

3に関してはもう少しスマートなやり方がありそうな気がする。

paizaスキルチェックに挑戦

Sランク取ったった😎

https://paiza.jp/challenges/share/D5oo984MrCofrPA34Q1chyAIG73KEvT10ZKrIgEz3Bg?source=social

想定回答時間40分だから25秒オーバーしてるんだけどね……
オーバーするとスコアが線形に減点されていくらしいけど、切り上げで100点になったぽい。

この順位は、問題解いた人のうち50名を抽出した中での順位のようだ。
ランダムに 50名抽出なら運次第で1位取れるんじゃないかと考えて(実力で1位を取るという発想は無かった)、何問かSランクの問題解いてみたけど、最高5位だった。
競技プログラミングやってるような人は、自分が40分かけて解いた問題を平気で10分台で解いてくるから怖い。どんな頭してんだ。
その手の人が結構いる感じで、運だけで1位取るのは相当厳しそうだ。

それともランダムに50名抽出じゃなくて、得点の分布から均一に50名抽出してたりするのだろうか。
もしそうだったら自分の実力だとどう頑張ってもこれ以上順位上げられそうにない。
蟻本を買えということだろうか。

問題は巷で言われてるほど簡単だとは思わなかったけど、paiza公式にあるようにプログラマーの2%しか解けないってことはさすがに無いように思う。
登録だけして放置してあるアカウントとかを含めると2%しか解けてないってことなのかな。
情報系の学校卒業した人の7割ぐらいなら、時間をかければ解ける難易度に感じた。

そろそろ再就職しないといけないから挑戦してみたんだけど、実際どれくらいの効果あるんかな…
どっか拾ってくれれば良いんだけどね(´・ω・)

囲碁の棋譜を検索できるサイト「101围棋网」が便利

中国語だけど、以下のサイトが中々便利。
布石から、それに対応する棋譜を検索することができる。
https://www.101weiqi.com/

左のメニューにある「棋形搜索」から棋譜の検索を行うことが出来る。
例えば小林流の布石を閲覧したい場合、以下の画像のように石を配置したのち、「 棋形搜索 」ボタンを押下すると対応する棋譜が表示される。

手順に関わらず、最終的にこの配置に石が置かれた棋譜を検索してるっぽいので、関係ない布石の棋譜が表示されることもあるみたいだけど、かなり参考になる。

three.jsにて法線情報がない.objファイルを読み込んだ際のメモ

何もしなくても.objファイルを読み込んだ際に法線を自動計算してくれたが、面ごとに法線を出してるらしく、以下のような法線が設定される。

頂点ごとに平均化された法線が欲しい場合は、setUseIndicesを設定してインデックスを保持したままファイルを読み込む設定にすればよい。

    const objLoader = new THREE.OBJLoader2();

    // インデックスを保持したまま読み込むように設定
    objLoader.setUseIndices(true);

    const callbackOnLoad = (event) => {
        let rootNode = event.detail.loaderRootNode;
        rootNode.children[0].material = new THREE.MeshNormalMaterial();
        scene.add(rootNode);
    };

    objLoader.load( 'model/teapot.obj', callbackOnLoad, null, null, null, false );

出力結果

頂点ごとに法線が計算されていることが分かる。
なんかティーポット下部の中心あたりがスムーズじゃないけど、元のファイルが悪いんかな。


追記
やっぱファイルが悪かったみたい。
Blenderで重なってる頂点削除してやったらスムーズになった。

スライムくんゲーム

Phaser3の練習にちょっとしたゲームを作ってみた。
リファクタリングはまた今度する(しない)。
以下からプレイ可能

スライムくんゲーム

スライム君を会社に戻そうと追ってくるタコから逃げるゲーム。
方向キーで移動、スペースキーでゲームのカードを落とせる。
PC専用で、IEだと動かない。

Phaser3の概要はかなり掴めたかな。
シーン遷移周りのベストプラクティスなんかはちょっと考えたい。
今のやり方だとメモリリーク起こしてないかちょっと心配。

JavaScriptのゲームライブラリ「Phaser」が便利

JavaScriptのゲームライブラリについて少し調べてみたが、Phaserが中々便利そう。
ゲーム制作に必要なものは一通りそろってて、コードも読みやすかった。
2018/10/16現在だと、Phaser3系と、2系でドキュメントが混在してる感じなのがネックかな。

公式のチュートリアルが短い上に分かりやすいので、これで概要が掴めた。

書き始めた時は、公式チュートリアルのcreateとかupdate関数のthisが何を指しているのかいまいち把握できなくて混乱した。
どうもこれはPhaser.Sceneオブジェクトを参照しているようで、PhaserではこのSceneオブジェクトに対する操作を中心にプログラムを書いていくっぽい。
なのでリファレンスのSceneドロップダウンリスト以下を参照すれば、必要な情報は一通り手に入る。
公式の作例も充実しているので、リファレンスと作例見れば大体のことが解決するので助かる。
こんな感じでモダンな書き方にも対応してるようだ。

Eelにて新規ウィンドウをアプリケーションモードで開きたい

Eelで新規ウィンドウを開く際に、単純にhtmlやjavascriptから開くとアプリケーションモードが解除されて、タブやらメニューバーやら表示されてしまう。
別に問題があるわけじゃないんだけど、何となく格好が悪い。

ということで、Pythonから新規ウィンドウを開けないか試してみた。
単純にeel.start()をもう一度呼べばいいのではないかと試してみる。

フォルダ構成main.py
web
 └─ main.html

main.pyimport eel

def main():
    eel.init("web")
    eel.start("main.html")

"""新しいウィンドウを開く"""
@eel.expose
def open_window():
    eel.start("main.html")

if __name__ == '__main__':
     main()

main.html<html>
<head>
    <meta charset="UTF-8">
    <title>eel_exsample</title>
    <script type="text/javascript" src="/eel.js"></script>
    <script type="text/javascript">
        // 新しいWindowを開くPythonスクリプトを実行する
        function openWindow() {
            eel.open_window();
        }
    </script>
</head>

<body>
    <a href="#" onclick="openWindow()">openWindow</a>
</body>
</html>

・実行結果


openWindowのリンクを押下すると新しいウィンドウが開いた。
問題なく動作しているようだが、コンソールに以下のエラーが出ている。

OSError: [WinError 10048] 通常、各ソケット アドレスに対してプロトコル、ネットワーク アドレス、またはポートのどれか 1 つのみを使用できます。: ('localhost', 8000)
2018-10-04T01:58:57Z  failed with OSError

同じポートでもう一つWebサーバーを立てようとして怒られてるようだ。
1回目のeel.start()ですでにサーバーは立ってるから問題ないんだけどちょっと気持ちが悪い。

以下のように立てるwebサーバーのポートに0を指定してやって、空いている任意のポートを取得するようにしてやればエラーは発生しなくなる。

main.pyimport eel

def main():
    eel.init("web")
    eel.start("main.html", options={"port" : 0,})

"""新しいウィンドウを開く"""
@eel.expose
def open_window():
    eel.start("main.html", options={"port" : 0,})

if __name__ == '__main__':
     main()


ただ、新しいウィンドウを開くたびにサーバーが立つのでこれは無いかな。

Eelのソースを読んだところ、eel.browsers.open()にてよしなにchromiumのウィンドウを開いてくれているようだ。。。たぶん。
なので、以下のように直接eel.browsers.open()を呼び出してやれば、エラーメッセージも出てこず、サーバプロセスは一つのみで動作させることができる。
注意点として、1回目にeel.start()に渡したオプションを使いまわすようにすること (eel.start()にて必要なオプションを詰めてくれるので、それを使いまわす)。

main.pyimport eel

web_app_options = {
	'port': 0,
}

def main():
    eel.init("web")
    # eel.start()では、引数に渡したオプションに未指定のものがあった場合、デフォルトの値を詰めてくれる。
    eel.start("main.html", options=web_app_options)

"""新しいウィンドウを開く"""
@eel.expose
def open_window():
    # 第一引数は開きたいURLのリスト、第二引数はeel.start()に渡したオプション
    eel.browsers.open(["main.html",], web_app_options)

if __name__ == '__main__':
     main()

ちょっと無理やり感があるかな。

その他の注意点として、開いたばかりのウィンドウのjavascriptの関数をPythonから呼び出せないことに注意する。
eel.sleep()などで開き終わるまで待ってやれば、新規ウィンドウのjavascriptの関数を呼び出せるようになる。

また、同じhtmlを複数ウィンドウ開いている場合、そのhtmlに含まれるjavascriptの関数をPythonから呼び出したら、すべてのウィンドウでその関数が実行される。
一つのウィンドウのみ対象にしたい場合は、javascriptに変数として任意のIDを持たせるなどの工夫が必要になりそう。

と色々はまりどころがあること考えると、Eelで複数ウィンドウ開くのは悪手くさいな。
少なくとも複数ウィンドウに同じ名称のjavascriptの関数が含まれる状況は避けた方がいい(Pythonから呼ばれないなら問題ない)。
複数ウィンドウが必要な場合は、javascriptのモーダルダイアログ扱うようなライブラリ使って、あんまりポカスカ新規ウィンドウが作られないようにした方がいいかな。
大体の機能はモーダルダイアログで済みそうだし、それならアプリケーションモードの見た目との相性も悪くないはず。

PythonのちょっとしたGUIにEelが便利

自分用にちょっとしたGUIをPythonで作りたいときのライブラリにしっくりくるものが無かったんだけど、最近Eelというライブラリを試してみたらこれが中々良い感じだった。
Electronを軽くした感じのライブラリで、GUIをhtmlで作成できる。
内部的にはbottleでサーバーを立てて、それにChromiumからリクエストを送るような作りになっているようだ。

使い方は公式のgitや、Qiitaの記事を参照。

例えば、リンクをクリックした際にPythonのスクリプトを起動したい場合は以下のようにする。

フォルダ構成main.py
web
 └─ main.html

main.pyimport eel

def main():
    eel.init("web")
    eel.start("main.html")


"""link1が押下された際に呼び出すスクリプト"""
@eel.expose
def link1_click():
    print("link1_clicked")

"""link2が押下された際に呼び出すスクリプト"""
@eel.expose
def link2_click(args):
    print(args)
    return "link2_clicked"

if __name__ == '__main__':
     main()

main.html<html>
<head>
    <meta charset="UTF-8">
    <title>eel_exsample</title>
    <script type="text/javascript" src="/eel.js"></script>
    <script type="text/javascript">
        // 非同期でPythonスクリプトを実行する
        function link1Click() {
            eel.link1_click();
        }
        
        // Pythonスクリプトに引数を渡し、結果の帰り値を待つ例
        async function link2Click() {
            let val = await eel.link2_click("args-test")();
            alert(val);
        }
    </script>
</head>

<body>
    <a href="#" onclick="link1Click()">Link1</a>
    <br>
    <a href="#" onclick="link2Click()">Link2</a>
</body>
</html>

・実行結果


Link1は単純にPythonスクリプトを実行する例、Link2はPythonスクリプトに引数を渡し、その帰り値を待つ実行例。

・Link2押下結果


非常にシンプルである。
自分用に作ったスクリプトにちょっとしたGUIを付けたいときなんかは非常に重宝しそう。
作ったソフト公開するには作りが素朴すぎるかな。少し使い込んでみてここら辺の感覚はつかみたい。

これとPygletぐらいあれば、自分のやりたいことは一通り簡単に実装できそうだ。

Djangoの管理サイトにログインしようとすると500エラーが発生する

Djangoでadmin以下の管理サイトにログインしようとすると500エラーが発生した。
開発環境では上手く動いており、デプロイ後も管理サイト以外は問題なく動作していて、また管理サイトのログイン画面までは問題なく表示できる。

とりあえずsettings.pyのDebugフラグを立ててやってエラーメッセージを見てみたら、どうもsqliteのDBファイルのパーミッションがおかしいみたいで以下のエラーが出ていた。

Exception Type: OperationalError
Exception Value: attempt to write a readonly database

パーミッションを確認してみると、rootユーザーがオーナーになっており、apacheユーザはDBに書き込みができない状態だった。
オーナーをapacheに変更してみたが、やはりエラーは変わらず。。。
どうもDBのファイルだけでなく、その親ディレクトリにも書き込み権限がいるらしい。
DB操作する時に新しく一時ファイル作ったりするんかな。
ということで親ディレクトリのオーナーも変更してやったらエラーは解消した。

管理サイト動くようになったんで、写真まとめてる以下のサイトにいくつか画像追加した。
https://nktk-tech.com/app/gallery/
松江方面の画像が多いね。
画像増えてきたら改ページとかも考えんといけんな。

追加した画像抜粋 :




Witcher3のフリーズ対策

Witcher3を購入。
プレイしようとするが、起動数十秒でOS巻き込んでフリーズする。
Core i7-3770KにGTX970だからスペックは何とか足りてると思うんだけどな。

イベントログ見てみたら案の定KP41のエラー吐いてて、他にはそれっぽいエラーがない。
原因が特定しにくくて非常に面倒である。

たぶんGPU周りに原因があると踏んで、GPU-Zでログを出力するよう設定して落ちる際の負荷を確認してみる。
ログ見てみると、どうも定格以上にオーバークロックしようとして落ちてる臭いんだけどいまいち確信が持てない。
前にFarcry3やってた時に同じような症状で落ちることがあったが、その時は以下のURLの対処法に従えば問題を解消できた。
http://awgsfoundry.com/blog-entry-409.html
GPU-Zのログ見てもTDPは設定値以上にはなっておらず、設定はうまいこと効いてるのが分かる。

あんま気が乗らないけど、NVIDIA InspectorでGPUのクロック数を150MHzほど下げてやり、
GPUがフル稼働しても定格以上にオーバークロックされないようにしてやったらフリーズしなくなった。
うーん……