歩いたら休め

なんでこんな模様をしているのですか?

【Python3.6】AWS Lambdaでツイッターを検索して自動リツイートする

先程の記事に引き続き、AWS LambdaでPython3.6が使えるようになったので、過去にPython2.7で書いたバッチ処理のレガシーコードをLambdaに移行しています。

まずは、下の記事で書いた「ツイッターを検索した結果を自動リツイートする」コードを移行します。今見るとけっこうコード酷いですね。

kiito.hatenablog.com

Pythonのコードを書き直す

AWS Lambdaの流儀に従ってコードを書いていきます。

ここではlambda_function.pylambda_handlerという関数を用意して、実行するように設定することとします。

後述しますが、アクセストークン等は環境変数で渡しています。

import os
import time
from datetime import datetime
import twitter


TARGET_TERMS = ['ファンタジスタドール', '鵜野うずめ']
API_ENV_KEY = ['CONSUMER_KEY', 'CONSUMER_SECRET', 'ACCESS_TOKEN_KEY', 'ACCESS_TOKEN_SECRET']
COUNT = 100

def lambda_handler(event, context):
    client = TwitterClient()
    client.run(TARGET_TERMS)
    return True


class TwitterClient(object):
    def __init__(self):
        self.client = twitter.Api(*[os.environ[k] for k in API_ENV_KEY])
        self.nowtime = int(time.mktime(datetime.now().timetuple()))
        self.begin_time = self.nowtime - 60 * 60
    
    def run(self, terms):
        for term in terms:
            for tweet in self._search_tweet(term):
                if tweet.created_at_in_seconds in range(self.begin_time, self.nowtime):
                    self._post_retweet(tweet.id)

    def _search_tweet(self, term):
        return self.client.GetSearch(term=term, count=COUNT, result_type='recent')

    def _post_retweet(self, tweet_id):
        try:
            self.client.PostRetweet(tweet_id)
        except:
            print(f'{tweet_id}は既にリツイートされています')

ちなみにpython-twitterというライブラリを使っています。

github.com

zipで固めてアップロードする

先程の記事で用意したDockerイメージを使って、依存ライブラリも含めたzipファイルを用意しました。

kiito.hatenablog.com

requirements.txtには以下を記述しています。

python-twitter

環境変数でアクセストークン他を設定する

AWS Lambdaでは環境変数が設定できるので、アクセストークンなどはこちらから渡すことにします。

dev.classmethod.jp

こんな感じです。

f:id:takeshi0406:20170506170833p:plain

本来は「暗号化ヘルパーを有効にする」を選択すべきだと思うのですが、「どうせ自分以外見ないだろう」という甘い考えでやっていません。

本当はDockerで環境変数や依存ライブラリまで再現した開発環境を用意すればかっこよかったのですが、今回は小規模なコードなので特に用意しませんでした。

その他の設定

あとは以下の設定を行いました。特に難しいことはないと思います。

  • 「トリガー」で定期的に実行する
  • タイムアウト時間を3秒から3分まで長く設定しなおす(3秒ではさすがに打ち切られてしまう)

【Python2】Twitterの検索結果を自動でリツイートするbotを作りました

@kayourockというアカウントを運営しているのですが、 ここ1年以上、ツイートの内容も更新できないし、自分の力で音楽をdigる時間も少なくなってきてしまいました。

twitter.com

謡曲のようなノスタルジックなメロディーのロック/ポップスを紹介。日本ならではの音楽を応援します。

歌謡ロックbotの特徴は以下の通りです。
・一定時間ごとに楽曲のYoutube動画とAmazon.jp(または公式サイト等)へのリンクをツイート。
・関連する最新情報をリツイートします。
・常時リクエストを受け付けています。

そこで、「歌謡ロック」他、アカウントに関係のある情報を検索して自動でリツイートする機能を付けてみました。

本当はPython3系を使いたかったのですが、今まで使って慣れているpython-twitterが3系に非対応のため、ひとまず2系で実装しました。 oauth tokenを別ファイル(secret.py)にしてimportする等、こちらの記事を参考にしています。 今考えるとjsonとかを読み込む形で書けば良かったですが。

akiniwa.hatenablog.jp

# -*- coding: utf-8 -*-

import time
from datetime import datetime
import twitter
import secret

api = twitter.Api(
    consumer_key = secret.twDict['consumer_key'],
    consumer_secret = secret.twDict['consumer_secret'],
    access_token_key = secret.twDict['access_token_key'],
    access_token_secret = secret.twDict['access_token_secret']
    )

def get_search(term):
    return api.GetSearch(term=term, count=100, result_type='recent')

def post_retweet(tweetid):
    try:
        api.PostRetweet(tweetid)
    except:
        print(u'既にリツイートされています') # って書いてるけど、相手にブロックされている場合もこちら

def search_and_retweet(term, rm_nonurl=False):
    for t in get_search(term):                                           
        nowtime = int(time.mktime(datetime.now().timetuple()))
        # ツイート内容及びscreen nameにbotが含まれる場合、除外する
        if u'bot' in t.text or u'bot' in t.user.screen_name:
            break
        # urlが含まれないツイートを排除する(引数で設定)
        if rm_nonurl is True and len(t.urls) == 0: 
            break
        # 1時間以内のツイートをリツイートする
        if t.created_at_in_seconds in range(nowtime-60*60, nowtime):
            post_retweet(t.id)

search_and_retweet(u'歌謡ロック')
search_and_retweet(u'和ロック', True)
search_and_retweet(u'歌謡メタル', True)

【ディープラーニング】AlchemyVisionの画像タグ付けAPIで動物画像をひたすらタグ付けするbotを作りました

タイトルの【ディープラーニング】はちょっと釣りくさいですが;

 

AlchemyVisionという、画像解析やテキスト解析にDeep Learningを利用できるAPIが話題になっています。

AlchemyAPIは米国のコロラド州デンバー発の人工知能系の技術を応用した自然言語処理や文書解析のサービスを、主に法人向けに展開している企業です。設立自体は2005年とすでに9年ほど経っていますが、シリーズAのファンドを受けたのは2013年になってからですし、名前を目にするようになったのは最近になってからです。

 

実際にいろいろな写真をデモに入れて試してみました。特に動物は精度が良く、犬の場合犬種("shiba"など)までタグ付けできるみたいです。一方、学習データに写真が多いのか、アニメのキャラやイラストは殆どタグ付けできませんでした。

 

そして、そのままAlchemyAPIを利用したtwitterbotも作ってみました。twitterを動物関連のワード検索して、画像のあるツイートを抽出、タグ付けしてツイートします。

AlchemyAnimals (AlcAnimals) on Twitter

アルパカは"cat"と"dog"の両方でタグ付けされました。"alpaca"ってタグは用意されていないみたいです。

 

一応コードも載せておきます。AlchemyAPIのPythonモジュールが公式で用意されていますが、使い方がよくわからなかったのでそのままAPIのURLを叩きました。python-twitterの使い方は下の記事を参考にしました。

python-twitterの使い方(1) - 忘れないようにメモっとく

#!/usr/bin/python
#coding:utf-8

import urllib
import json
import twitter
import secret
import random

api = twitter.Api(
    consumer_key = secret.twDict['consumer_key'],
    consumer_secret = secret.twDict['consumer_secret'],
    access_token_key = secret.twDict['access_token_key'],
    access_token_secret = secret.twDict['access_token_secret']
)

alchemykey = "**************" #APIKEYの取得が必要
keywords = [u"animal",u"dog",u"cat",u"animals",u"zoo",
                u"dogs",u"fish",u"bird",u"monkey",u"sheep",u"space+cats",
                u"wildlife",u"猫",u"alpaca",u"pet",u"animal+crazy",
                u"animal+cute",u"rare+animal",u"mountain+animal",u"national+geographic+animal",
                u"aquarium+animal",u"animal+africa",u"species+asia",u"species africa",u"desert+animal"]
random.shuffle(keywords)
keyword = keywords[0]

search = api.GetSearch(keyword,count=100)
random.shuffle(search)
for tw in search:
    if len(tw.media) == 0:
        print "no picture"
    else:
        url = tw.media[0]["url"]
        media_url = tw.media[0]["media_url"]
        break

endpoint = "http://access.alchemyapi.com/calls/url/URLGetRankedImageKeywords?apikey="
access_url = endpoint + alchemykey + "&url=" + media_url + "&outputMode=" + "json"

endpoint = "http://access.alchemyapi.com/calls/url/URLGetImage"

f = urllib.urlopen(access_url)
api_open = f.read()
f.close()
print api_open

api_open = json.loads(api_open)
tags = api_open["imageKeywords"]
tweet = ""
for tag in tags:
    print tag["text"], tag["score"]
    tweet = tweet + tag["text"] + ": " + tag["score"] + """
    """ #なぜか¥nで改行するとエラー

api.PostUpdate(tweet + url)

【Twitter】@kayourock に自動リンク切れチェック機能を実装しました

@kayourockのクライアントをeasybotterからpythonの自作プログラムに移行しました。ついでにリンク切れしたYoutubeのURLを除く機能を実装してみました。

Pythontwitterを扱うライブラリはたくさんありますが、python-twitterを利用しています。

 

同じディレクトリにアカウント情報を記述したsecret.pyと、ツイート内容を記述したdata.txtというファイルを用意する必要があります。

data.txtには、次のように一行ずつツイート内容を記述します。改行コードなど、詳しくはeasybotterのサイトを参考にするといい気がします。

EasyBotter - プログラミングができなくても作れるTwitter botの作り方

0.8秒と衝撃。「21世紀の自殺者」 http://youtu.be/ru4xoKsm9lo #kayourock
0.8秒と衝撃。「POSTMAN JOHN」 http://youtu.be/dHRMezlbmiE #kayourock
0.8秒と衝撃。「町蔵・町子・破壊」 http://youtu.be/0NQUAHcecRU #kayourock
13*SQUAD「陽炎」 http://youtu.be/TAHY2-2VwhA #kayourock

 

python-twitterの使い方はここを参考。
python-twitterの使い方(1) - 忘れないようにメモっとく

botアカウントのクライアント情報を記述した secret.py を用意します。Read-onlyではなく、ツイートできる権限が必要です。詳しくは以下のサイトで。

python-twitterを使ってTwitterBot開発 - お首が長いのよ

 

youtubeのリンク切れチェックは、サムネイル画像のAPIを利用しています。

【Python】YouTubeのURLリストのリンク切れをチェックするためのコード - 歩いたら休め

# -*- coding: utf-8 -*-

import twitter
import urllib
import random
import secret

api = twitter.Api(
    consumer_key = secret.twDict['consumer_key'],
    consumer_secret = secret.twDict['consumer_secret'],
    access_token_key = secret.twDict['access_token_key'],
    access_token_secret = secret.twDict['access_token_secret']
)

f = open('data.txt')
data1 = f.read()
f.close()

datas1 = data1.split('\n')
random.shuffle(datas1) #ランダムに並び替え(1個目をツイート)

for data in datas1: #リンク切れしていないURLまでループ、breakを忘れると全ツイートするハメに
	data_split = data.split("http://")[1]
	is_youtube = data_split.startswith("youtu.be")
	if is_youtube:
		pic_api = data_split.replace("youtu.be/",
			"http://gdata.youtube.com/feeds/api/videos/")
		f = urllib.urlopen(pic_api)
		url_open = f.read()
		
		if url_open.startswith("""<?xml version='1.0'"""):
			api.PostUpdate(data)
			break
	else:
		api.PostUpdate(data)
		break

ちなみにbreak文を忘れるとdata.txtの内容をすべてツイートすることになるので、大変なことになります。気をつけましょう。

@dempa_botにも同じような機能を実装したいと考えていますが、ニコニコ動画でも同様にリンク切れをチェックする方法を探しています。