Python タグの一覧です(49 件)

Flaskでog:imageを動的に切り替える

FaceBookなどにブログをシェアした時にサムネイルとして使用されるog:imageを動的に切り替えたい
具体的には

  • エントリーに画像リンクが一つ貼られている場合はその画像URLを使用する
  • エントリーに画像リンクが複数貼られている場合は一番最初に貼られている画像URLを使用する
  • エントリーに画像リンクが一つもない場合、あらかじめ用意した画像URLを使用する
  • トップページの場合も同じくあらかじめ用意した画像URLを使用する

このブログはFlaskを使用した自作ブログなので、このような機能を追加する場合は自力でなんとかするしかなくて(まあそれが楽しいんだけど)他に困っている人がいるとも思えないけれども一応メモしておく

ブログの本文を取り出す

SQLAlchemyを使っているのでこのような感じで個別エントリーを取り出す

entry = Entry.query.filter_by(id = post_id).one()

ブログの本文からimgタグのsrcを取り出す

これはbs4を使う。find_allでなくfindを使うことによって目的のタグが見つかったらそこでパースをやめるようにした(処理時間の短縮)

def get_src_tag(e):
    """get first img src tag"""
    soup = BeautifulSoup(e.text, 'html.parser')
    img = soup.find('img')
    if img:
        return img['src']
    else:
        return None

view関数の作成

@mod.route('/entry/<int:post_id>/')
def show_entry(post_id):
    entry = Entry.query.filter_by(id = post_id).one()
    flash(u'%s' % entry.pub_date.strftime('%Y-%m-%dT%H:%M:%S+09:00'), 'alert-success')
    return render_template('show.html',
        entries=Entry.query.filter_by(id=post_id).all(), tags=show_tags(),\
                                      archives=count_archives(), src=get_src_tag(entry))

本件とは関係ないものも混じっているけれどだいたいこんな感じ
entry = Entry.query.filter_by(id = post_id).one() と src=get_src_tag(entry) のところが今回追加したところ

テンプレート(jinja2)の変更

とりあえずヘッダー部分だけ貼り付け

<html lang="ja">
    <head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# article: http://ogp.me/ns/article#">
        {% if request.endpoint == 'entry.show_entries' %}
        <title>aoshiman.org</title>
        <meta property="og:title" content="aoshiman.org" />
        <meta property="og:url" content="https://blog.aoshiman.org" />
        <meta property="og:image" content="https://static.flickr.com/3604/3281177662_70807f7065.jpg" />
        {% elif request.endpoint == 'entry.show_entry' %}
        {% for entry in entries-%}
        <title>{{entry.title|safe}} | aoshiman.org</title>
        <meta property="og:title" content={{entry.title|safe}} | aoshiman.org />
        <meta property="og:url" content="https://blog.aoshiman.org{{url_for('entry.show_entry', post_id=entry.id)}}" />
        {% if src != None %}
        <meta property="og:image" content={{src}} />
        {% else %}
        <meta property="og:image" content="https://static.flickr.com/3604/3281177662_70807f7065.jpg" />
        {% endif %}
        {%-endfor %}
        {% else %}
        <meta property="og:title" content="aoshiman.org" />
        <meta property="og:url" content="https://blog.aoshiman.org" />
        <meta property="og:image" content="https://static.flickr.com/3604/3281177662_70807f7065.jpg" />
        <title>aoshiman.org</title>
        {% endif %}
        <meta property="og:type" content="article" />
        <meta property="og:site_name" content="aoshiman.org" />
        <meta property="fb:app_id" content="1842519809295747" />
        <meta name="twitter:card" content="summarylargeimage" />
        <link rel="stylesheet" href="{{url_for('static', filename='bootstrap/css/bootstrap.min.css')}}" media="screen">
        <link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
        <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="alternate" title="RSS" href="https://blog.aoshiman.org/rss/" type="application/rss+xml">
        <link rel="shortcut icon" href="{{ url_for('static',filename='favicon.ico') }}" />
        <script type="text/javascript">
            var _gaq = _gaq || [];
            _gaq.push(['_setAccount', 'UA-*******-*']);
            _gaq.push(['_trackPageview']);

            (function() {
             var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
             ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
             var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
             })();
         </script>
    </head>

ちょっと長いんだけど、request.endpointで個別記事かそうでないかを判別。srcがNoneかそうでないかで画像URLを振り分けている


[Python]Shizuoka.py #6 and shizudev に参加しました

昨年7月以来、7ヶ月ぶりの Shizuoka.py #6 and shizudev に参加及び発表してきました。今回は and shizudev とタイトルにある通り、shizudevの2016年題材がTensorFlowだった為、Shizuoka.pyと共催出来ますねという話で2016年内に実施する予定だったものが、ずれ込んだものです。shizudevに関してはこちらのスライドの4ページ目をご参照願います。因みに、最終的に11人参加して頂きました。わざわざ遠方(横浜)からいらっしゃった方がいたり、学生さんも参加してくれたりありがとうございました。

今回の発表一覧です

私の発表はAWS Lambda Pythonについてでしたが、AWS Lambdaに興味をもってくれた人もいたりして頑張ってまとめてよかったです。あとPythonでAWS Lambda書くならLamvery使いましょう。

個人的に嬉しかったこと

  • お会いしたいなと思っていた@tomofさんにようやく会えました。また@tomofさん自身も今回の勉強会を楽しんでもらえたようで良かったです。
  • @ike_jpnさんのTensorFlow x キュウリの仕分けの話が念願叶って聴けました。ハード、ソフト両方弄れる人は強いと感じました
  • 自分を含めてですが、農業関係者が4人も集まりました。地方都市らしくもあり、IT勉強会らしからぬようでもあり、不思議な感覚でしたが、楽しかったです。

最後に会場準備やイベント管理を行ってくれた@yajuさん、@fmkz___さんありがとうございました。特に@yajuさんのQiita渾身のエントリ、なぜ機械学習にPythonが選ばれるのかのお陰で参加者が増えた(!)のは凄い事だと思います。私もアウトプット頑張ろうと思いました。


[Python] ast.literal_evalを使って文字列を評価する

辞書型の文字列をPythonで評価する場合、他言語同様evalが使えます。

In [1]: s = eval("{'a':'aaa', 'b':'bbb', 'c':'ccc'}")

In [2]: s['a']
Out[2]: 'aaa'

evalは便利ですが、強力故にこのような文字列も評価可能です。

In [3]: ls -l
total 8
-rw-r--r--   1 aoshiman  staff    79 11 24 21:39 README.tmpenv
drwxr-xr-x   2 aoshiman  staff    68 11 24 21:40 a-path-you-really-care-about/
drwxr-xr-x  36 aoshiman  staff  1224 11 24 21:39 bin/
drwxr-xr-x   3 aoshiman  staff   102 11 24 21:39 include/
drwxr-xr-x   3 aoshiman  staff   102 11 24 21:39 lib/
drwxr-xr-x   3 aoshiman  staff   102 11 24 21:39 share/

In [4]: eval("__import__('os').system('rm -rf ./a-path-you-really-care-about')")
Out[4]: 0

In [5]: ls -l
total 8
-rw-r--r--   1 aoshiman  staff    79 11 24 21:39 README.tmpenv
drwxr-xr-x  36 aoshiman  staff  1224 11 24 21:39 bin/
drwxr-xr-x   3 aoshiman  staff   102 11 24 21:39 include/
drwxr-xr-x   3 aoshiman  staff   102 11 24 21:39 lib/
drwxr-xr-x   3 aoshiman  staff   102 11 24 21:39 share/

もう一つのやり方としてast.literal_evalを使う方法があります。literal_evalは文字列、バイト列、数、タプル、リスト、辞書、集合、ブール値など評価対象が限定されているのでevalより安全に評価出来ます。
rmコマンドを評価させると例外を発生させます。


In [8]: mkdir a-path-you-really-care-about

In [9]: ls -l
total 8
-rw-r--r--   1 aoshiman  staff    79 11 24 21:39 README.tmpenv
drwxr-xr-x   2 aoshiman  staff    68 11 24 21:48 a-path-you-really-care-about/
drwxr-xr-x  36 aoshiman  staff  1224 11 24 21:39 bin/
drwxr-xr-x   3 aoshiman  staff   102 11 24 21:39 include/
drwxr-xr-x   3 aoshiman  staff   102 11 24 21:39 lib/
drwxr-xr-x   3 aoshiman  staff   102 11 24 21:39 share/

In [10]: import ast

In [11]: s = ast.literal_eval("{'a':'aaa', 'b':'bbb', 'c':'ccc'}")

In [12]: s['a']
Out[12]: 'aaa'

In [13]: ast.literal_eval("__import__('os').system('rm -rf ./a-path-you-really-care-about')")
    ...:
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-14-2546c9cde63c> in <module>()
----> 1 ast.literal_eval("__import__('os').system('rm -rf ./a-path-you-really-care-about')")

/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/ast.py in literal_eval(node_or_string)
     82                 return left - right
     83         raise ValueError('malformed node or string: ' + repr(node))
---> 84     return _convert(node_or_string)
     85
     86

/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/ast.py in _convert(node)
     81             else:
     82                 return left - right
---> 83         raise ValueError('malformed node or string: ' + repr(node))
     84     return _convert(node_or_string)
     85

ValueError: malformed node or string: <_ast.Call object at 0x106c53c88>

In [14]:

そもそも辞書形式の文字列を使う場面なんかあるのかという疑問なのですが、 例えばAWS Lambdaで機密情報を取り扱う場合、KMSを利用して暗号化してしまうのが手っ取り早く且つ良い方法だと思うのですが、機密情報を辞書形式の文字列で暗号化しておくと復号後の値の取り扱いがやりやすくなります。

先ずSIDとSECRETをkeyに持つ辞書型文字列をKMSを使って暗号化します。ここでは暗号化、デプロイ、実行にLamveryを使っています。

$ lamvery encrypt -s -n conf "{'SID':'1234567890','SECRET':'abcdefghijklmn'}"

cipher_textsを確認すると暗号化されています。

$ cat .lamvery.secret.yml
cipher_texts:
  conf: AQECAHgtwl2B8ygtOB4TH6X5x0TAaeSX4r7lIOFdxo1SFZyMAgAAAI0wgYoGCSqGSIb3DQEHBqB9MHsCAQAwdgYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAx5ehDOIvYwyaZLmE8CARCASaNQOkC3tKi5tMpOAmEy0ChRkrrB7y0yJz1ldwtFBI2O6Kq1oWpsTbQJNAEbbxB4uvWXrR0vOid0G8hQAdy6lKy0D0FlFHzFoKg=
secret_files: {}

次に以下のようなコードを書き、AWS Lambdaにデプロイします。

import ast
import lamvery

def lambda_handler(event, context):
    conf = ast.literal_eval(lamvery.secret.get('conf'))
    print(conf['SECRET'])
$ lamvery deploy
lamvery: [Function-VPC] subnets: None -> []
lamvery: [Function-VPC] security_groups: None -> []
lamvery: [Function] Capacity: 7,594,304 Bytes -> 7,593,926 Bytes
lamvery: [Function] Deployed version: $LATEST

Lambdaを実行させるとSECRETの値が出力されているのがわかります。

$ lamvery invoke {}
START RequestId: 3b8da74d-b247-11e6-a8a7-45bdd8f2a5bd Version: $LATEST
abcdefghijklmn
END RequestId: 3b8da74d-b247-11e6-a8a7-45bdd8f2a5bd
REPORT RequestId: 3b8da74d-b247-11e6-a8a7-45bdd8f2a5bd	Duration: 725.51 ms	Billed Duration: 800 ms 	Memory Size: 128 MB	Max Memory Used: 32 MB

参考サイト
Using python's eval() vs. ast.literal_eval()? - Stack Overflow
marcy-terui/lamvery: User-friendly deployment and management tool for AWS Lambda function

Lamveryのzsh補完関数を書いた

最近個人的な用途でAWS Lambda(Python)を使うことが増えてきました。最初の頃はPythonスクリプト書き、zipで固めて動作確認の様に一つ一つ手動でやっていましたが、さすがに辛くなってきて今はLamveryを使っています。

marcy-terui/lamvery: User-friendly deployment and management tool for AWS Lambda function

Lamveryについては作者様のこのQiita記事が詳しいです
AWS Lambda向けデプロイ・管理ツール「Lamvery」について - Qiita

Lamveryはpipで入ること、設定ファイルがjsonじゃなくてyamlなことなど嬉しいことが多いので、結構使うようになってきたのですが、zsh補完が無く、探してもなさそうなので他の方々の自作補完関数を参考にしながら作成してみました。サブコマンドは動的に作成する(sed等で抽出する)方法を採用している方が多いのですが、今回はべた書きです。

使い方の一例です

Gistコードをcloneして適当なところに置く

$ cd path/to/zsh-completions
$ git clone https://gist.github.com/d2e93f986802f5a359b4dc6f25eff1a3.git src

fpathを通す

$ vi ~/.zshrc
fpath=(path/to/zsh-completions/src(N-/) $fpath)

sourceする(もしくはターミナルを一度終了してもう一度起動)

$ source ~/.zshrc


現在cron ジョブ等で動いていてAWS Lamdaに移行すべきスクリプトがまだ幾つか残っているのですが、補完もされるようになったので頑張って移したいです(腰が重い)

参考サイト
ghq コマンドの zsh 補完ファイルを修正したので、その過程を解説する - Qiita
zshの補完を自作してFabricのタスクを補完する - Qiita
シェルコマンドでシングルクォートに囲まれたシングルクォートのエスケープ | Firegoby
zshでHomebrewを使用する場合に設定しておいたほうが良いこと - よんちゅBlog←fpathとか


Pythonista for iOS のスクリプトを通知センターに登録する

以前、Pythonista for iOS で Nowplaying する という記事を書いたのですが、iOS10にアップデートしたところ、Musicアプリの共有メニューからPythonistaのスクリプトを呼び出せなくなりました(出来るのかもしれないけれど現状やり方がわからず)。仕方がないので Launcher を使って通知センターにスクリプトを登録しました。


iOS10のMusicアプリでは共有メニューにRun Pythonista Scriptが出てこない

IMG_4185

Launcherへの登録は画像の通りで難しくなく、新規追加から進めていく

IMG_4182

URLの項目には以下のような感じで登録。名前とアイコンは適当に

pythonista3://<スクリプト名>?action=run
IMG_4183

PAGE TOP