ひとり部長のひとりごと

社会人1年目で社内起業を始めたひとり部長がその経験を語ります。Mac関連もつぶやきます。映画のレビューはサブブログに移行しました。世の中の明るいニュースだけをまとめたエントリーも始めました。

Python3でAIの"上野ふき"ちゃんを作るプロジェクト【初期段階】

ちょっとしたAIを作ってみたいと思う

キャラクター設定は、

  • ガジェットが大好きな女子高生
  • 特にAnker製品を好む
  • 製品の箱は綺麗にとっておくタイプ
  • 最新のプレスリリースを漁るのが得意

名前の由来は、 ガジェット→Gadget→God's Jet→神の噴出→上野ふき

まぁこんな感じで。

最終目標は、ガジェットのプレスリリースを読んで、語彙力や学習内容にしたがってオリジナルのコメントや知識を引き出してくれるものを作りたいと思っている。

素人の自分に何ができるのか、

とりあえず始めたのは、語彙の辞書と製品情報の辞書の二つをコントロールするプログラムを作ること!

用意するファイル

同一ディレクトリ内に、

  • ai.py(メインの実行ファイル)
  • brain.py("ふき"の頭脳となるプログラム集)
  • product_dic.dat(製品情報格納庫としてのバイナリデータ)
  • brain_words.dat(彼女の語彙力バイナリデータ。)
  • backupフォルダ(ここに語彙、製品情報の変更があった場合に1日単位でバックアップ)

メインの「ai.py」

ai.pyでは、必要最小限なコードでやりたいことをスッキリ書きたいと思う。 バカなので、煩雑なコードになればなるほどわけわからなくなり、思考がストップしてしまう。

初心者ゆえ、classの書き方や引き出し方にありえない間違いを犯している可能性もあるので許してほしい。

#ai.py
from brane import Brane #オリジナルのbrane.py

text='''
読ませたい記事の文章をここに。自分のプログラムでは、とりあえずサンプルの記事を置いていますが、最終的にプレスリリースサイトをスクレイピングさせて完成させたい。
'''
b=Brane(text)
#b.add_brain()#語彙の追加
#b.check()#語彙からの文章参照チェックリスト
#b.maintenance()#語彙のメンテナンス
#b.add_profile()#製品情報の要素追加
#b.add_product()#製品追加
#b.product_list()#登録製品リスト

このように、それぞれの機能を試したいときに#を外すだけの状態に持ってきています。

ふきちゃんの頭脳、「brain.py」

import re
import pickle
import time
import datetime

#文章を単文と単語に分けるルールづくり。これが悩ましい。
split_list1= '、|。|\n|また|ほか|として|を追加'
split_list2='×1|な|する|いう|も|が|を|に|へ|と|より|から|で|や|の|は|、|。|!|?|!|「|」|(|)|\n|した|など|ほか|させた'

class Brane():
    def __init__(self, text):
        self.text = text

    def sentence(self):
     #単文の場合、split_list1を使う
        keywords=re.split(split_list1,self.text)
        for absent in range(keywords.count('')):
            keywords.remove('')#空白を切り捨て!
        for short in keywords:
            if len(short) < 2:#短いものは切り捨て!
                keywords.remove(short)
            else:
                pass
        return keywords

    #語彙力強化のための単語抽出
    def words(self):
        keywords=re.split(split_list2,self.text)
        for absent in range(keywords.count('')):
            keywords.remove('')
        for short in keywords:
            if len(short) < 2:
                keywords.remove(short)
            else:
                pass
        return keywords

    #知らない単語を覚えさせるプログラム
    def add_brain(self):
        keywords_list=self.words()
        for key in keywords_list:
            print(key)
            #語彙リストを開いて照合
            r=open('./brain_words.dat','rb')
            vo=pickle.load(r)
            r.close()
            if key in vo:
                print('この単語は知っているよ!')
            else:
                ask=input('ボキャブラリーに加えますか?(y or end):')
                if ask=="y":
                    r=open('./brain_words.dat','rb')
                    vo=pickle.load(r)
                    r.close()
                    vo.append(key)#語彙に単語を追加
                    w=open('./brain_words.dat','wb')
                    pickle.dump(vo,w)#語彙を上書き
                    w.close()
                    #バックアップファイルの作成
                    r=open('./brain_words.dat','rb')
                    vo=pickle.load(r)
                    r.close()
                    a=open('./backup/brain_words_%s.dat' % datetime.date.today(),'ab')
                    pickle.dump(vo,a)
                    a.close()
                elif ask=="end":
                    break
                else:
                    pass

    #語彙と抽出文の照合。語彙力があればあるほど、文章解析能力が高まる。
    def check(self):
        sentence_list=self.sentence()
        brain_words_r=pickle.load(open('./brain_words.dat','rb'))
        for word in brain_words_r:
            for i in range(len(sentence_list)):
                try:
                    sentence_list[i].index(word)
                    print('【%s】:%s' % ( word,sentence_list[i]))
                except:
                    pass

    #語彙のメンテナンス(主に消去)いらない語彙を追加してしまった場合、記憶から消しさる
    def maintenance(self):
        brain_words_r=pickle.load(open('./brain_words.dat','rb'))
        while True:
            print(brain_words_r)
            erase_word= input('消去する単語を入力してください:')
            if erase_word=="end":
                break
            else:
                try:
                    brain_words_r.remove(erase_word)
                    f=open('./brain_words.dat','wb')
                    pickle.dump(brain_words_r,f)
                    f.close()
                except:
                    pass

    '''------------------ここから製品情報----------------------'''
    def add_product(self):
        #辞書を引き出して表示
        pd_r=open('./product_dic.dat','rb')
        product_dic=pickle.load(pd_r)
        pd_r.close()
        #空のフレームを取り出す
        pd_r=open('./product_dic.dat','rb')
        new_product=pickle.load(pd_r)[0]
        pd_r.close()
        print(new_product)
        time.sleep(0.5)
        while True:
            yn=input('製品を追加しますか?(y)')
            if yn=="y":
                keys=list(new_product.keys())
                #全ての要素に対して入力
                name=input('製品名を入力:')
                i=0
                product_num=[]#ここに追加された番号の製品しか削除できない
                for item in product_dic:
                    if name==item['製品名']:
                        print('No.%s:%sはすでに登録してあります。' % (i,name))
                        product_num.append(i)#重複した製品の番号をリストに追加
                        i+=1
                        flag='exist'
                    else:
                        i+=1
                        flag='noexist'
                        pass
                if flag=='exist':#すでに製品が登録されている場合
                    #製品リストを抽出
                    pd_r=open('./product_dic.dat','rb')
                    product_dic=pickle.load(pd_r)
                    pd_r.close()
                    try:
                        delete=int(input('製品を削除しますか?:No.'))
                        if delete in product_num:#入力内容が重複リスト番号に一致するか
                            del product_dic[int(delete)]
                            print('削除しています...')
                            #製品リストを開いて、上書き更新
                            pd_w=open('./product_dic.dat','wb')
                            pickle.dump(product_dic,pd_w)
                            pd_w.close()
                            print('削除しました。')
                            #バックアップファイルの作成
                            r=open('./product_dic.dat','rb')
                            pd=pickle.load(r)
                            r.close()
                            a=open('./backup/product_dic_%s.dat' % datetime.date.today(),'ab')
                            pickle.dump(pd,a)
                            a.close()
                        else:
                            print('削除できませんでした。')
                    except:
                        pass
                else:
                    new_product['製品名']=name
                    for key in keys:
                        if key=="製品名":
                            pass
                        else:
                            new_product[key]=input('%sを入力:' % key)
                    #製品リストを抽出
                    pd_r=open('./product_dic.dat','rb')
                    product_dic=pickle.load(pd_r)
                    pd_r.close()
                    #リストに新しいのを追加
                    product_dic.append(new_product)
                    #製品リストを開いて、更新
                    pd_w=open('./product_dic.dat','wb')
                    pickle.dump(product_dic,pd_w)
                    pd_w.close()
                    #バックアップファイルの作成
                    r=open('./product_dic.dat','rb')
                    pd=pickle.load(r)
                    r.close()
                    a=open('./backup/product_dic_%s.dat' % datetime.date.today(),'ab')
                    pickle.dump(pd,a)
                    a.close()
            else:#追加しますか?のelse
                break
    #製品リスト
    def product_list(self):
        pd_r=open('./product_dic.dat','rb')
        product_dic=pickle.load(pd_r)
        pd_r.close()
        print(product_dic[0])
        print('-'*40)
        for item in product_dic:
            print('製品名:%s' % item['製品名'])

    '''------------------ここから製品情報の要素----------------------'''
    def add_profile(self):
        pd_r=open('./product_dic.dat','rb')
        pd_sample=pickle.load(pd_r)[0]
        pd_r.close()
        print(pd_sample)
        while True:
            yn=input('製品情報の要素を追加しますか?(y/n)')
            if yn=="y":
                #要素を追加
                pd_r=open('./product_dic.dat','rb')
                product_list=pickle.load(pd_r)
                add_profile={input('追加する要素名:'):''}
                #製品リストの全てに新要素を追加
                for item in product_list:
                    item.update(add_profile)
                print(product_list)
                #要素情報を上書き
                pd_w=open('./product_dic.dat','wb')
                pickle.dump(product_list,pd_w)
                pd_w.close()
            else:
                break

また追って、報告します!とりあえずこれで遊んでみてください! (遊ぶ要素ねえええ)

【新幹線の料金表一瞬で出す!】python始めました。練習その1【追記】

https://www.python.org/static/img/python-logo@2x.png

いきなりどうした

どうも、ここ最近javascriptやらブックマークレットがどうのとか、なんやらって関係ない人にはほんっとにいらん記事バッカあげてるんですが、

pythonはじめました

なんだいきなり、pythonってなんぞやって人は、こいつの将来性にギョッとすると思います。

手始めに「新幹線の料金」

練習がてら、さくっと出してくれるプログラムを組んでみました。

import lxml
import codecs
from bs4 import BeautifulSoup
import urllib.request
q = "http://www.shinkansen.co.jp/ryoukin_tokaido_sanyo.html"
html = urllib.request.urlopen(q).read()
soup = BeautifulSoup(html, "lxml")
table = soup.find("table", {"class":"demoTable"}) 
fromStation="品川"#上り駅を入力してください
toStation="新大阪"#下り駅を入力してください
#出発駅リスト
if fromStation == "東京":
    yoko = 2
if fromStation == "品川":
    yoko = 3
if fromStation == "新横浜":
    yoko = 4
if fromStation == "名古屋":
    yoko = 5
if fromStation == "京都":
    yoko = 6
if fromStation == "新大阪":
    yoko = 7
if fromStation == "新神戸":
    yoko = 8
if fromStation == "姫路":
    yoko = 9
if fromStation == "岡山":
    yoko = 10
if fromStation == "福山":
    yoko = 11
if fromStation == "広島":
    yoko = 12
#行き先リスト
if toStation == "品川":
    tate = 1
if toStation == "新横浜":
    tate = 2
if toStation == "名古屋":
    tate = 3
if toStation == "京都":
    tate = 4
if toStation == "新大阪":
    tate = 5
if toStation == "新神戸":
    tate = 6
if toStation == "姫路":
    tate = 7
if toStation == "岡山":
    tate = 8
if toStation == "福山":
    tate = 9
if toStation == "広島":
    tate = 10
print("出発駅:"+table.findAll("th")[yoko].text+"駅")
print("到着駅:"+table.findAll("tr")[tate].th.text+"駅")
price = table.findAll("tr")[tate].findAll("td")[yoko-1].text.replace(",","")

if len(price) == 13:
    ticket = int(price[0:5])
    seat = int(price[5:9])
    none_seat = int(price[9:13])
    print("運賃:"+str(ticket)+"円")
    print("指定席:"+str(seat)+"円(合計:"+str(ticket+seat)+"円)")
    print("自由席:"+str(none_seat)+"円(合計:"+str(ticket+none_seat)+"円)")
if len(price) == 12:
    ticket = int(price[0:4])
    seat = int(price[4:8])
    none_seat = int(price[8:12])
    print("運賃:"+str(ticket)+"円")
    print("指定席:"+str(seat)+"円(合計:"+str(ticket+seat)+"円)")
    print("自由席:"+str(none_seat)+"円(合計:"+str(ticket+none_seat)+"円)")
if len(price) == 11:
    ticket = int(price[0:3])
    seat = int(price[3:7])
    none_seat = int(price[7:11])
    print("運賃:"+str(ticket)+"円")
    print("指定席:"+str(seat)+"円(合計:"+str(ticket+seat)+"円)")
    print("自由席:"+str(none_seat)+"円(合計:"+str(ticket+none_seat)+"円)")
if len(price) == 10:
    ticket = int(price[0:3])
    seat = int(price[3:7])
    none_seat = int(price[7:10])
    print("運賃:"+str(ticket)+"円")
    print("指定席:"+str(seat)+"円(合計:"+str(ticket+seat)+"円)")
    print("自由席:"+str(none_seat)+"円(合計:"+str(ticket+none_seat)+"円)")

こいつを実行すると、こうなります。

出発駅:品川駅
到着駅:新大阪駅
運賃:8750円
指定席:5700円(合計:14450円)
自由席:4870円(合計:13620円)

広島までしか登録してないけどwww

理屈

こちらの「情報新幹線」さんのテーブルから情報を頂いています。 http://www.shinkansen.co.jp/ryoukin_tokaido_sanyo.html

実行環境

python3で書いてます。

使いかたとか、pythonってどうやんねんみたいなことはおいおい僕も知識がついてから、、、説明します・・・。 まだぜんぜんよくわかってないので。

では

追記

inputを知ったので、実行時に入力できるようにしました

import lxml
import codecs
from bs4 import BeautifulSoup
import urllib.request
q = "http://www.shinkansen.co.jp/ryoukin_tokaido_sanyo.html"
html = urllib.request.urlopen(q).read()
soup = BeautifulSoup(html, "lxml")
table = soup.find("table", {"class":"demoTable"}) 
fromStation =input("上り駅:")#
toStation = input('下り駅:')#
#出発駅リスト
if fromStation == "東京":
    yoko = 2
if fromStation == "品川":
    yoko = 3
if fromStation == "新横浜":
    yoko = 4
if fromStation == "名古屋":
    yoko = 5
if fromStation == "京都":
    yoko = 6
if fromStation == "新大阪":
    yoko = 7
if fromStation == "新神戸":
    yoko = 8
if fromStation == "姫路":
    yoko = 9
if fromStation == "岡山":
    yoko = 10
if fromStation == "福山":
    yoko = 11
if fromStation == "広島":
    yoko = 12
#行き先リスト
if toStation == "品川":
    tate = 1
elif toStation == "新横浜":
    tate = 2
elif toStation == "名古屋":
    tate = 3
elif toStation == "京都":
    tate = 4
elif toStation == "新大阪":
    tate = 5
elif toStation == "新神戸":
    tate = 6
elif toStation == "姫路":
    tate = 7
elif toStation == "岡山":
    tate = 8
elif toStation == "福山":
    tate = 9
elif toStation == "広島":
    tate = 10
else:
    yoko = "none_type"
    if yoko == "none_type":
        print("行き先を指定してください")
if yoko != "nonetype":
    price = table.findAll("tr")[tate].findAll("td")[yoko-1].text.replace(",","")

    if len(price) == 13:
        ticket = int(price[0:5])
        seat = int(price[5:9])
        none_seat = int(price[9:13])
        print("運賃:"+str(ticket)+"円")
        print("指定席:"+str(seat)+"円(合計:"+str(ticket+seat)+"円)")
        print("自由席:"+str(none_seat)+"円(合計:"+str(ticket+none_seat)+"円)")
    if len(price) == 12:
        ticket = int(price[0:4])
        seat = int(price[4:8])
        none_seat = int(price[8:12])
        print("運賃:"+str(ticket)+"円")
        print("指定席:"+str(seat)+"円(合計:"+str(ticket+seat)+"円)")
        print("自由席:"+str(none_seat)+"円(合計:"+str(ticket+none_seat)+"円)")
    if len(price) == 11:
        ticket = int(price[0:3])
        seat = int(price[3:7])
        none_seat = int(price[7:11])
        print("運賃:"+str(ticket)+"円")
        print("指定席:"+str(seat)+"円(合計:"+str(ticket+seat)+"円)")
        print("自由席:"+str(none_seat)+"円(合計:"+str(ticket+none_seat)+"円)")
    if len(price) == 10:
        ticket = int(price[0:3])
        seat = int(price[3:7])
        none_seat = int(price[7:10])
        print("運賃:"+str(ticket)+"円")
        print("指定席:"+str(seat)+"円(合計:"+str(ticket+seat)+"円)")
        print("自由席:"+str(none_seat)+"円(合計:"+str(ticket+none_seat)+"円)")

課題は、エラー表示をなくすことと、 if文半分にできるんじゃね?って所。

また追記します。

【超簡単】おしゃれなブログ記事引用ブックマークレットを作ったのでシェア

またかよ

またまたです。

すんません。

今回は、おしゃれな引用カードです。

引用したよ!ということがわかるし、なおかつおしゃれな感じで。

引用しなくても、リンクカードとして。ディスクリプションが表示されます。

そんな風に使えるものを作りました。

サンプル

選択で引用した場合


ざっくりと、どんな商品なの? 大口径望遠単焦点レンズフラッグシップモデル 防塵・防滴性能の強化 第6世代の超音波モーターHSM採用

   「ざっくりと、どんな商品なの? 大口径望遠単焦点レンズフラッグシップモデル 防塵・防滴性能の強化 第6世代の超音波モーターHSM採用」という部分を選択しているので、中に表示されています。

選択で引用しなかった場合


最新ガジェットのニュース、価格、情報をみるならここ。基本的に1〜2ヶ月以内に発売されたもしくは発売予定の家電、PC、スマホなどあらゆる最新電子機器の紹介をしています。

選択部分が見つからなかったので、ディスクリプションを表示しています。

もし、さらにディスクリプションがみつからない場合は、アドレスを表示するように設定しています。

ブックマークレット

なんか過去のブックマークレットは使い物にならないみたいな感じらしいのでちゃんと作りました。

CSSの設定も必要ありません。

どうぞ!

javascript: (function() {
    function productImg() {
        var f = document.evaluate('//link[(@rel=\'icon\') or (@rel=\'shortcut icon\') or (@rel=\'ICON\') or (@rel=\'SHORTCUT ICON\')][1]/@href', document, null, XPathResult.STRING_TYPE, null);
        var u=f.stringValue;var favicon=(u == '') ? 'http://'+location.host+'/favicon.ico' : (u.substring(0, 7) != 'http://') ? 'http://'+location.host+'/'+u : u;var pi = document.getElementsByTagName('meta');
        for (i = 0; i < pi.length; i++) {if (pi[i].getAttribute("property") == "og:image"){
        return pi[i].getAttribute("content");}}return favicon;return "";}
    var ogimg=productImg(),img="";
    if(ogimg.length > 0){var img='<img src="'+ogimg+'" style="float: left;width: 100px;margin: 5px;border: 1px solid #000;">';}
    var title=document.title,sourceurl=location.href,domain=location.host,bqBefore = "",bqAfter ="",selection = getSelection();if(selection.rangeCount==0){var selection=document.getElementsByName('description').item(0) ? document.getElementsByName('description').item(0).content : document.location.href;}
    var bqBefore='<div style="position: relative;border: 2px solid #DADADA;padding:5px;color: #000;margin: 15px 0;background: #fff;background: rgba(255,255,255,0.9);">',bqAfter="</div>";
    var card='<!--'+title+'-->\n<div style="background:url('+ogimg+') no-repeat center;background-size:cover;">'+bqBefore+''+img+'<div style="font-weight: bold;margin-top: 5px;"><a href="'+sourceurl+'">'+title+'</a></div><hr style="margin:3px"><span>'+selection+'</span><div style="text-align:right;color:#000;opacity:0.5;"><a href="//'+domain+'">'+domain+'</a></div>'+bqAfter+'</div>';
    prompt("コピーしてください",card);
})();

ブックマークレットの使い方

簡単です。

手順1

うえのコードをコピーして、適当にブックマークバーにあるリンクのアドレスを編集を行う f:id:hitoribucho:20161117101737p:plain

手順2

f:id:hitoribucho:20161117103036j:plain

貼り付けたら、終了です。

手順3

f:id:hitoribucho:20161117103151p:plain 引用したいページで、引用部分を選択もしくは選択せずにそのまま、先ほど編集したブックマークをクリックします。

手順4

f:id:hitoribucho:20161117103256j:plain

コードが現れるので、そのままコピーして、表示させたい記事に貼り付けるだけです!!!

以上。

もう完成形っぽいから、これからはここのパーツのフィードバック記事を書いていくと思います。

【アプリ】スマホでWordpressを編集するのに「hpb pad」をオススメする5つの理由

どうも、ひとり部長です。

はてなブログ使っていてなんやねんこのタイトルはと思われると思いますが、

最近ガジェットのニュースブログがBANされましてwwww

そんなわけでガジェット速報サイトをワードプレスでこしらえたのです。

しかし、これが使いにくい。

PCからはサクサク編集できるんだけど、なんせiPhoneからの編集がうざい。

うざいったらありゃしない。

というわけで公式アプリをダウンロードしようと思ったら、「iOS9以上のバージョンでないとダウンロードできません」の表示。

脱獄したままの環境に依存しているとこうなります

直ぐにでもiOS10にしてもいいんだけど、初期化がめんどくさい。

というわけでオススメの投稿用アプリの紹介です。

※すべてひとりガジェット速報の画面で説明します

「hpb pad.app」

https://lh4.ggpht.com/-Z7sXSlLU_2PfwKaVCTXuQZjxqYanWRxDo0jE_1K70VYXY1oHh--eF5puudbA-EJjs0=w300

なにができるのか

メイン画面

f:id:hitoribucho:20161116094610p:plain

メイン画面です。

  • ページのスクリーンショット(クリックしたらページにアクセス)

  • メニュー(後述)

  • 投稿
  • 画像アップロード   

の構成です。ここからサクサクっと投稿画面に行きましょう。

理由その1:投稿画面

f:id:hitoribucho:20161116095113p:plain

投稿画面です。

見た感じの通り、タイトル、タグ、カテゴリーがサクサク入力できます

スマホからワードプレスの管理画面で編集すると、カーソル移動できなかったり、画面内のフレームがうまくスクロールできなかったり、イライラしっ放しでした。)

特に最高なのは、カテゴリーです。 感覚的にセレクトできるように作られています。

理由その2:投稿文の編集

f:id:hitoribucho:20161116095457p:plain

ここも単なるキーボードではありません。

よく使いそうな<b>タグや、<blockquote><li>といったタグもサクサク打ち込めるようになっています。

かゆいですね!!!

理由その3:投稿画面下部のメニューがすごい

f:id:hitoribucho:20161116095856p:plain

こいつがこのアプリをオススメする一番の理由です。

投稿設定

f:id:hitoribucho:20161116100741j:plain

ここの設定から、

  • 公開状態
  • 表示状態
  • 公開日時
  • アイキャッチ画像 の設定が直ぐに行えます。

プレビュー

f:id:hitoribucho:20161116101030j:plain

目の形をしたアイコンは、プレビューです。  

とにかく動きが早い!サクサク表示してくれます。  

SEO補助

f:id:hitoribucho:20161116101156j:plain

極め付けはこのメニュー、

なんと、SEO対策のサポートまでしてくれます。

具体的には、投稿文中のキーワード頻出度、タイトル文字数、本文の文字数をカウントして、ブログに適した内容になっているかアドバイスしてくれます。

これは非常に便利。

理由その4:設定メニュー

f:id:hitoribucho:20161116101411p:plain

サイドメニューでは、記事の投稿だけでなく、固定ページの作成、コメントの管理、JetPackと連携したアクセス状況の確認を行うことができます。

理由その5:複数アカウントに対応

f:id:hitoribucho:20161116101515p:plain

なんとまたこれもかゆい機能です。

一つのアカウントだけでなく、複数アカウントにも対応しています。

これで、いちいちログインし直さずとも別のブログが管理できますね!

また、アップロードする画像の自動リサイズ設定なども行うことができます。

めちゃくちゃ便利じゃねーのこれ。

というわけで、神アプリに認定しても良い「hpb pad」のしょうかいでした!

ダウンロード

最後に宣伝

最新ガジェットのみを、まとめたサイトがなかなか見当たらない(あっても更新頻度が低すぎてイライラしたり)ので、1日5件くらいのペースで紹介するブログを立ち上げました。

はてなに依存していないので、カスタマイズし放題で開放感に満ち溢れています。

はてなはてなでメリットもあるし、バランス取りながら更新していけたらいいな。

よろしくお願いします^^

【永久保存版】さらに最強のリンクシェア用ブックマークレットを作った【まだ進化するかも】

こんにちはw

つい2日前に最強のブックマークレットと冠して投稿しましたが、さらに便利なものを作ったので紹介します。

今回は、

ページ内で選択したら、そのblockquoteも合わせて表示してくれるものです。

御託はいらないのでちゃちゃっといきましょう。

一つ前のエントリーで例を出します。

表示例

以下のように表示してくれます。

こいつと、前回のツイッターはてぶシェア機能付きリンクカード生成ブックマークレットと合わせれば、「ツイッターはてぶシェア機能および読者登録ボタン付きリンクカード生成ブックマークレット」が完成します。もちろん、はてなサービスではないページに適用しても、読者ボタンは出てきません。

便利でしょ?^^

超便利でしょ?

アドレスに貼り付けるJSブックマークレット

あとでコピペでおkにしますが、ここでちょっとだけ解説

javascript: (function() {
 //はてなブログの情報を取得して、読者ボタンにする。
    function author() {
        var pi = document.getElementsByTagName('html');
        for (i = 0; i < pi.length; i++) {
            if (pi[i].getAttribute("data-admin-domain") == "http://blog.hatena.ne.jp") {
                return pi[i].getAttribute("data-author");
            }
        }
        return "";
    }
    function blog() {
        var pi = document.getElementsByTagName('html');
        for (i = 0; i < pi.length; i++) {
            if (pi[i].getAttribute("data-admin-domain") == "http://blog.hatena.ne.jp") {
                return pi[i].getAttribute("data-blog");
            }
        }
        return "";
    }
 //Facebook用のサムネイルを取得。何もなかった場合、ファビコンを取得、それもなかった場合、空で表示
    function productImg() {
        var f = document.evaluate('//link[(@rel=\'icon\') or (@rel=\'shortcut icon\') or (@rel=\'ICON\') or (@rel=\'SHORTCUT ICON\')][1]/@href', document, null, XPathResult.STRING_TYPE, null);
        var u = f.stringValue; 
        var favicon = (u == '') ? 'http://' + location.host + '/favicon.ico' : (u.substring(0, 7) != 'http://') ? 'http://' + location.host + '/' + u : u;
        var pi = document.getElementsByTagName('meta');
        for (i = 0; i < pi.length; i++) {
            if (pi[i].getAttribute("property") == "og:image") {
                return pi[i].getAttribute("content");
            }
        }
        return favicon;
        return ""; //←ここの""の中に好きな画像をいれれば何もなかった場合の表示ができます。Noimageの画像とか。
    }
    var author = author();
    var blog = blog();
    var ogimg = productImg();
 //ページのタイトルを取得します
    var title = document.title;
 //ページの説明を取得します何もなかった場合、urlを記載します
    var desc = document.getElementsByName('description').item(0) ? document.getElementsByName('description').item(0).content : document.location.href;
   //URLを取得します 
 var url = window.location.href;
 //引用部分の取得です。何も選択されない状態だと、表示されないようにしています。
    var bqBefore = "";
    var bqAfter ="";
    var selection = getSelection();
      if(selection.rangeCount > 0){
        var bqBefore = "<blockquote>";
        var bqAfter ="</blockquote>"+'\n\n';
      }
    var blockquote = bqBefore+selection+'\n\n';
 //ブックマークレットを押した時に抽出するhtmlコードを設定しています。
    var card = '\n'+blockquote+'<!--' + title + '--><div class="article"><div class="image"><a href="' + url + '"><img src="' + ogimg + '"></a></div><div class="caption"><div class="pagetitle"><a href="' + url + '">' + title + '</a></div><div class="description"><a href="' + url + '">' + desc + '</a></div></div><div class="tweet"><a href="javascript:window.location=\'twitter://post?message=\'+encodeURIComponent(\'' + title + '%20' + url + '\');"><img src="https://goo.gl/Y4BWro"></a></div><div class="hatena"><a href="javascript:window.open(\'http://b.hatena.ne.jp/entry/' + url + '\');"><img src="https://goo.gl/5zeLZG"></a></div><div class="line"><a href="javascript:window.location=\'line://msg/text/\'+encodeURIComponent(\''+title+'\')%20+encodeURIComponent(\''+url+'\');"><img src="https://goo.gl/1u9vcm"></a></div><div class="iframe"><iframe src="http://blog.hatena.ne.jp/' + author + '/' + blog + '/subscribe/iframe" allowtransparency="true" frameborder="0" scrolling="no" width="150" height="28"></iframe></div></div>'+bqAfter+'\n';
   //ブックマークレットを押した時にポップアップでコピーできるように表示します 
 window.prompt("コピー", card);
})();

と、こんな感じで必要な要素が諸々盛り込まれています。 本当はもっと記述内容をへらすことはできるんだけど ・・・・疲れた。

というわけで、コピペーで簡単にできるように一行に直したのが次です。どうぞ。

javascript: (function(){function author() {var pi = document.getElementsByTagName('html');for (i = 0; i < pi.length; i++) {if (pi[i].getAttribute("data-admin-domain") == "http://blog.hatena.ne.jp") {return pi[i].getAttribute("data-author");}}return "";}function blog() {var pi = document.getElementsByTagName('html');for (i = 0; i < pi.length; i++) {if (pi[i].getAttribute("data-admin-domain") == "http://blog.hatena.ne.jp") {return pi[i].getAttribute("data-blog");}}return "";} function productImg(){var f = document.evaluate('//link[(@rel=\'icon\') or (@rel=\'shortcut icon\') or (@rel=\'ICON\') or (@rel=\'SHORTCUT ICON\')][1]/@href', document, null, XPathResult.STRING_TYPE, null);var u = f.stringValue;var favicon = (u == '') ? 'http://' + location.host + '/favicon.ico' : (u.substring(0, 7) != 'http://') ? 'http://' + location.host + '/' + u : u;var pi = document.getElementsByTagName('meta');for (i = 0; i < pi.length; i++) {if (pi[i].getAttribute("property") == "og:image"){return pi[i].getAttribute("content");}} return favicon; return "https://goo.gl/p73TWY"; } var author = author(); var blog = blog();var ogimg = productImg();var title = document.title;var desc = document.getElementsByName('description').item(0) ? document.getElementsByName('description').item(0).content : document.location.href; var url = window.location.href; var bqBefore = ""; var bqAfter =""; var selection = getSelection(); if(selection.rangeCount > 0){ var bqBefore = "<blockquote>"; var bqAfter ="</blockquote>"+'\n\n';} var blockquote = bqBefore+selection+'\n\n';var card = '\n'+blockquote+'<!--' + title + '--><div class="article"><div class="image"><a href="' + url + '"><img src="' + ogimg + '"></a></div><div class="caption"><div class="pagetitle"><a href="' + url + '">' + title + '</a></div><div class="description"><a href="' + url + '">' + desc + '</a></div></div><div class="tweet"><a href="javascript:window.location=\'twitter://post?message=\'+encodeURIComponent(\'' + title + '%20' + url + '\');"><img src="https://goo.gl/Y4BWro"></a></div><div class="hatena"><a href="javascript:window.open(\'http://b.hatena.ne.jp/entry/' + url + '\');"><img src="https://goo.gl/5zeLZG"></a></div><div class="line"><a href="javascript:window.location=\'line://msg/text/\'+encodeURIComponent(\''+title+'\')%20+encodeURIComponent(\''+url+'\');"><img src="https://goo.gl/1u9vcm"></a></div><div class="iframe"><iframe src="http://blog.hatena.ne.jp/' + author + '/' + blog + '/subscribe/iframe" allowtransparency="true" frameborder="0" scrolling="no" width="150" height="28"></iframe></div></div>'+bqAfter+'\n';window.prompt("コピー", card);})();
CSSの設定

登場するCSSの設定はこちらです

.article {position:relative;width:100%;height:115px;border-radius:4px;border:2px solid #000;margin-bottom:5px;background:#fff;}
.article a {display:block;width:100%;height:100%;text-decoration:none;color:#000;}
.article:hover {margin-left: 3px;}
.article div.image{width:70px;height:70px;float:left;margin:5px 5px;}
.image img {width: 100%;height: 100%;}
.caption {height:80px;margin:5px 5px;overflow:hidden;}
.pagetitle {font-size:80%;font-weight:bold;}
.pagetitle a{line-height:1.2rem;}
.description {font-size:70%;color:#444;}
.description a{line-height:1.1em;}
.tweet{position:absolute;width:24%;height:25px;bottom:5px;left:1%;background:#2AA4F0;border-radius:2px;text-align:center;border-bottom:2px solid #1F7EBE;}
.hatena{position:absolute;width:24%;height:25px;bottom:5px;left:26%;background:#1EB9DC;border-radius:2px;text-align:center;border-bottom:2px solid #2AA4F0;}
.line{position:absolute;width:24%;height:25px;bottom:5px;left:51%;background:#54CB24;border-radius:2px;text-align:center;border-bottom:2px solid #26B700;}
.tweet:hover,.hatena:hover,.line:hover{margin-top:3px;border:none;}
.hatena img,.tweet img,.line img{width:25px;height:25px;}
.article div.iframe{position:absolute;width:24%;height:25px;bottom:5px;right:0;padding-left:3px;padding-bottom:2px;}

是非、使ってください^^

ブックマークレットに関する過去記事