こんにちは、エンジニアインターンの南条です!

弊社では定期的にAirdropキャンペーンを実施しており、多くのユーザーの皆さんに参加していただいております。 今回はその中でもTwitterにシェアカードをツイートするだけで参加できる、Twitterシェアカードキャンペーンの技術的なお話をしたいと思います。

今回仕組みを説明していくにあたって、先日開催されたZilliqaシェアカードキャンペーンを例に進めていきたいと思います。

Zilliqa Sharecard Campaign

開発環境

  • 開発言語

    • python3
  • 依存ライブラリ

    • pyzbar
    • pillow
    • requests
    • tweepy
    • pandas
    • google-cloud
    • firebase_admin
    • grpcio

Tweet収集

まず初めにTwitterSearchAPI[1]を用いて、ツイートを収集します。 この際の検索クエリ(条件)としましては「#Ginco #ZILLIQA filter:images」を指定して、「#Ginco」と「#ZILLIQA」のハッシュタグがついた画像付きのツイートを収集しています。 シェアカードキャンペーン対象ツイートをここで収集し、ひたすらキューにためていくという処理を行います。

for tweet in tweepy.Cursor(self.api.search, q=self.query).items():
    if "media" in tweet.entities:
        for media in tweet.entities["media"]:
            app.q.append({"url": media['media_url_https'],
                "time": int(tweet.created_at.timestamp())})

実際のツイート

ツイートのデータ

{'created_at': 'Mon Sep 10 07:49:59 +0000 2018', 'id': 1039058388489912320, 'id_str': '1039058388489912320', 'text': '仮想通貨ウォレットアプリGincoにてZILLIQAのAirdrop開催中!アプリをダウンロードしてシェアカードをツイートするだけなので是非!!\n#Ginco #ZILLIQA https://t.co/TvAU9F5bd8', 'truncated': False, 'entities': {'hashtags': [{'text': 'Ginco', 'indices': [73, 79]}, {'text': 'ZILLIQA', 'indices': [80, 88]}], 'symbols': [], 'user_mentions': [], 'urls': [], 'media': [{'id': 1039058387302998016, 'id_str': '1039058387302998016', 'indices': [89, 112], 'media_url': 'http://pbs.twimg.com/media/Dmt6GRwV4AArtNa.jpg', 'media_url_https': 'https://pbs.twimg.com/media/Dmt6GRwV4AArtNa.jpg', 'url': 'https://t.co/TvAU9F5bd8', 'display_url': 'pic.twitter.com/TvAU9F5bd8', 'expanded_url': 'https://twitter.com/nandehu0323/status/1039058388489912320/photo/1', 'type': 'photo', 'sizes': {'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'small': {'w': 680, 'h': 428, 'resize': 'fit'}, 'large': {'w': 686, 'h': 432, 'resize': 'fit'}, 'medium': {'w': 686, 'h': 432, 'resize': 'fit'}}}]}, 'extended_entities': {'media': [{'id': 1039058387302998016, 'id_str': '1039058387302998016', 'indices': [89, 112], 'media_url': 'http://pbs.twimg.com/media/Dmt6GRwV4AArtNa.jpg', 'media_url_https': 'https://pbs.twimg.com/media/Dmt6GRwV4AArtNa.jpg', 'url': 'https://t.co/TvAU9F5bd8', 'display_url': 'pic.twitter.com/TvAU9F5bd8', 'expanded_url': 'https://twitter.com/nandehu0323/status/1039058388489912320/photo/1', 'type': 'photo', 'sizes': {'thumb': {'w': 150, 'h': 150, 'resize': 'crop'}, 'small': {'w': 680, 'h': 428, 'resize': 'fit'}, 'large': {'w': 686, 'h': 432, 'resize': 'fit'}, 'medium': {'w': 686, 'h': 432, 'resize': 'fit'}}}]}, 'source': '<a href="http://twitter.com/download/iphone" rel="nofollow">Twitter for iPhone</a>', 'in_reply_to_status_id': None, 'in_reply_to_status_id_str': None, 'in_reply_to_user_id': None, 'in_reply_to_user_id_str': None, 'in_reply_to_screen_name': None, 'user': {'id': 168021996, 'id_str': '168021996', 'name': 'なんぞー', 'screen_name': 'nandehu0323', 'location': 'tokyo', 'description': '電気通信大                               Blockchain本気でいじってます!', 'url': None, 'entities': {'description': {'urls': []}}, 'protected': False, 'followers_count': 746, 'friends_count': 616, 'listed_count': 8, 'created_at': 'Sun Jul 18 04:52:31 +0000 2010', 'favourites_count': 1221, 'utc_offset': None, 'time_zone': None, 'geo_enabled': True, 'verified': False, 'statuses_count': 115, 'lang': 'ja', 'contributors_enabled': False, 'is_translator': False, 'is_translation_enabled': False, 'profile_background_color': '131516', 'profile_background_image_url': 'http://abs.twimg.com/images/themes/theme14/bg.gif', 'profile_background_image_url_https': 'https://abs.twimg.com/images/themes/theme14/bg.gif', 'profile_background_tile': True, 'profile_image_url': 'http://pbs.twimg.com/profile_images/589680579102183424/bvbGg5TO_normal.jpg', 'profile_image_url_https': 'https://pbs.twimg.com/profile_images/589680579102183424/bvbGg5TO_normal.jpg', 'profile_banner_url': 'https://pbs.twimg.com/profile_banners/168021996/1519910528', 'profile_link_color': '009999', 'profile_sidebar_border_color': 'EEEEEE', 'profile_sidebar_fill_color': 'EFEFEF', 'profile_text_color': '333333', 'profile_use_background_image': True, 'has_extended_profile': True, 'default_profile': False, 'default_profile_image': False, 'following': False, 'follow_request_sent': False, 'notifications': False, 'translator_type': 'none'}, 'geo': None, 'coordinates': None, 'place': None, 'contributors': None, 'is_quote_status': False, 'retweet_count': 0, 'favorite_count': 1, 'favorited': False, 'retweeted': False, 'possibly_sensitive': False, 'lang': 'ja'}

画像の処理

次に、該当ツイートに添付されている画像をダウンロード(download関数)し、QRコードが含まれている場合にデコード(decode関数)しシェアカードのアドレスを取得します。

def download(self):
    try:
        que = self.q.popleft()
        url = que["url"]
        r = requests.get(url, headers=self.headers)
        if r.status_code == 200:
            filepath = self.make_filepath(self.image_dir, url)
            f = open(filepath, "wb")
            f.write(r.content)
            f.close()
            decodeData = self.decode(filepath, que["time"])
            if not decodeData.empty:
                self.write(decodeData)
    except IndexError:
        time.sleep(1)
    except requests.exceptions.ConnectionError as e:
        print(e)
        time.sleep(1)

def decode(self, filepath, timestamp, remove=1):
    data = decode(Image.open(filepath))
    try:
        if data:
            if data[0][0].decode("utf-8") not in out.recipient:
                se = pd.Series([data[0][0].decode("utf-8"),
                                timestamp], index=self.df.columns)
                return se
            else:
                return pd.Series()
        else:
            return pd.Series()
    finally:
        os.remove(filepath)

ダウンロードした画像

Zilliqa Sharecard

デコード結果

0x4dF42276dea7c6C17cFBD7Be0fD014B32193B77E

データの加工

指定された時間内に収集されたデータをCSVファイルとして出力します。 出力する際にGincoユーザーであるかどうかの判定やアドレスのvalidationを行います。

送金処理

CSVファイルを元に順次送金を行っていきます。 一度Airdropを受け取ったユーザー宛てには再度送金しないように、履歴を保存しています。

最後に

アーキテクチャの全体はこのような感じになっています。

Zilliqa Sharecard Architecture

以前、TwitterでTipBotを作っていたこともあり、それの応用で今回のAirdropツールを作成しました。 今後はもっと多くのユーザーの皆様に参加していただけるよう、安定性の向上や負荷分散などをしてレベルアップさせていこうと考えています!


GincoではこのようなTwitterシェアカードキャンペーンの他、さまざまなAirdropを実施中ですので、ぜひまだインストールされていない方はこちらからどうぞ!

Gincoをダウンロード

今後のAirdropのスケジュールについてはこちらをご覧ください!

Airdropスケジュール


参考文献