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を振り分けている


  • このエントリーをはてなブックマークに追加
PAGE TOP