5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

TwitterのツイートにURLがあったら「はてなブックマーク」にブックマーク追加する仕組みをPythonで実装してAWS Lambdaで動してみた

Last updated at Posted at 2019-05-18

2018年末、はてなブックマークで便利だった外部サービス連携「Twitterからブックマークを追加」サービスが終了しました。Qiita投稿時にツイートするとはてなブックマークにもブックマーク追加してくれて良かったのに。。。悲しい。。。

はてなブックマークがIDコール廃止。外部サービス連携も順次終了 - Impress Watch
https://www.watch.impress.co.jp/docs/news/1150477.html

「Twitterからブックマークを追加」や「mixi連携」、「Evernote連携」、「Facebook連携」などの外部サービス連携も11月初旬に終了。また、毎日、指定の時刻にマイホットエントリーをメールで送信する「マイホットエントリーメール」、お気に入りフィードを「はてなメッセージ」で送信する「お気に入りレポート」も終了する。

終了してからは手動でブックマーク追加していたのですが、他にも気になったサイトがあったときにツイートするかブックマークするか無駄に悩んだりすることが増えてきて面倒になったので、連携する仕組みを実装してみました。

はてなブックマークAPIがつかえる

はてなブックマークにAPIがあるのか調べてみたらありました。下記記事でブックマーク追加するサンプルもあげてくれているので参考にしました。(感謝

はてなブックマークを #API で追加する #python スクリプトの例 - Qiita
https://qiita.com/YumaInaura/items/0641702719fef0260d8e

APIに関しては公式ドキュメントが参考になります。

はてなブックマーク ブックマーク API - Hatena Developer Center
http://developer.hatena.ne.jp/ja/documents/bookmark/apis/rest/bookmark#post_my_bookmark_parameter_comment

OAuth認証を利用するにはConsumer key を取得する必要がありますので、下記ドキュメントを参考にします。

Consumer key を取得して OAuth 開発をはじめよう - Hatena Developer Center
http://developer.hatena.ne.jp/ja/documents/auth/apis/oauth/consumer

APIを利用して自分のアカウント情報にアクセスするにはOAuth認証でアクセストークンを取得する必要があります。
下記ライブラリでさくっと取得できそうでしたがエラー発生したため、公式にあるRuby実装サンプルを利用してアクセストークンを取得しました。

はてなブックマーク Web APIを手軽に使えるgemを作った - Qiita
https://qiita.com/t__nabe/items/7918b6c6232eb14c248e

```console:ダメだった(´・ω・`)

gem install hatena_bookmark_client_for_ruby

get_hatebu_access_token

/Library/Ruby/Gems/2.3.0/gems/oauth-0.5.4/lib/oauth/consumer.rb:197:in request': parameter_rejected (OAuth::Problem) from /Library/Ruby/Gems/2.3.0/gems/oauth-0.5.4/lib/oauth/consumer.rb:214:in token_request'
from /Library/Ruby/Gems/2.3.0/gems/oauth-0.5.4/lib/oauth/consumer.rb:155:in get_request_token' from /Library/Ruby/Gems/2.3.0/gems/hatena_bookmark_client_for_ruby-0.1.3/exe/get_hatebu_access_token:27:in '
from /usr/local/bin/get_hatebu_access_token:22:in load' from /usr/local/bin/get_hatebu_access_token:22:in '


```console
> touch oauth_consumer.rb
# 公式の「サンプルコード Ruby版」をコピペ
# YOUR_CONSUMER_KEYとYOUR_CONSUMER_SECRETを書き換える

> gem install sinatra

> ruby oauth_consumer.rb

[2019-05-18 14:07:10] INFO  WEBrick 1.3.1
[2019-05-18 14:07:10] INFO  ruby 2.3.7 (2018-03-28) [universal.x86_64-darwin18]
== Sinatra (v2.0.5) has taken the stage on 4567 for development with backup from WEBrick
[2019-05-18 14:07:11] INFO  WEBrick::HTTPServer#start: pid=29898 port=4567

http://localhost:4567 にアクセスして、はてなブックマークでアクセスを許可してトークンを取得します。

スクリーンショット 2019-05-18 14.07.32.png スクリーンショット 2019-05-18 14.07.43.png localhost_4567_oauth_callback_oauth_token_UC_2B7f_2BcIDSYrpg_3D_3D_oauth_verifier_ZwugnXywhKzEClwAwarZLkzYのコピー.png

Twitter APIを利用してツイートを取得する

Twitter APIの利用に関しては下記を参考にしました。

Pythonでサクッと簡単にTwitterAPIを叩いてみる - Qiita
https://qiita.com/ogrew/items/0b267f57b8aaa24f1b73

Twitter APIを利用するために必要となるアプリ登録とアクセストークン取得については以前に行ってたので今回はスキップします。下記が参考になります。

Twitter REST APIの使い方
https://syncer.jp/Web/API/Twitter/REST_API/

以前にもTwitter APIを利用したことがあり、ツイートを検索する際に、since:until: を利用して期間指定できることを知ったので、それを利用して取得するツイートを絞り込みます。日時のフォーマットを2019-05-18_12:34:56_JST と指定することで秒単位まで指定可能です。

Twitterの検索で時間を含む期間指定をする方法 - Qiita
https://qiita.com/kai_kou/items/336a9d1290c13abba7e2

ユーザーを指定するにはfrom: が利用できるので、こんな感じのクエリで検索します。

Twitter検索:特定のユーザー、アカウント内を指定して検索する方法
https://appbu.jp/twitter-search-from-specific-user

from:k_aik_ou since:2019-05-18_12:34:56_JST until:2019-05-18_13:45:01_JST

Pythonで実装する

はてなブックマーク APIとTwitter APIが利用できることと必要となるキーが取得できたので、雑にPythonで実装します。consumerKeyconsumerSecretaccessTokenaccessTokenSecret は各自のに置き換えてください。

main.py
import json
import requests
from requests_oauthlib import OAuth1
from requests_oauthlib import OAuth1Session
import datetime,time,sys
import re


def tweet_to_hatebu():
    # はてなブックマーク
    hatena_auth = OAuth1(
      "consumerKey",
      "consumerSecret",
      "accessToken",
      "accessTokenSecret"
    )

    # Twitter
    twitter_session = OAuth1Session(
      "consumerKey",
      "consumerSecret",
      "accessToken",
      "accessTokenSecret"
    )

    # APIのエンドポイント
    bookmark_api_url = "http://api.b.hatena.ne.jp/1/my/bookmark"
    twitter_api_url = "https://api.twitter.com/1.1/search/tweets.json"


    # ツイート取得する期間を指定する
    # from_atは定期実行する間隔に合わせて調整する
    now = datetime.datetime.now()
    from_at = now - datetime.timedelta(minutes=10)
    from_at_str = from_at.strftime("%Y-%m-%d_%H:%M:%S_JST")
    to_at_str = now.strftime("%Y-%m-%d_%H:%M:%S_JST")

    # 取得件数は適当に指定(最大100ツイート)
    params = {
      "q": "from:ツイッターのユーザー名 since:" + from_at_str + "until:" + to_at_str,
      "lang": "ja",
      "result_type": "recent",
      "count": 100,
    }

    # 指定した条件のツイートが取得できるまでAPIを叩く
    statuses = []
    while True:
      res = twitter_session.get(twitter_api_url, params = params, verify=True)
      res_text = json.loads(res.text)
      if len(res_text["statuses"]) == 0:
        break

      # Twitter APIの利用制限を超えたらヤメ
      if res.headers["X-Rate-Limit-Remaining"] == 0:
        break

      statuses.extend(res_text["statuses"])
      next_max_id = res_text["statuses"][-1]["id"] - 1
      params["max_id"] = next_max_id

    # ツイート時間でソートするなど
    statuses = sorted(statuses, key=lambda x: x["created_at"])

    for tweet in statuses:
        # 画像を含むツイートは無視
        if "media" in tweet["entities"]:
          print("media")
          continue

        # ながいつぶやきは無視
        if tweet["truncated"]:
          print("truncated")
          continue

        # ツイートテキストからURLを取得する
        text = tweet["text"]
        url_pattern = r"(https?)(:\/\/[-_\.!~*\"()a-zA-Z0-9;\/?:\@&=\+\$,%#]+)"
        matchOB = re.search(url_pattern, text)

        # URLを含めずにブックマークにコメントする
        comment = re.sub(url_pattern, "", text)

        # リツイートだったらコメントは無視
        rt_matchOB = re.search(r"RT ", text)
        if rt_matchOB:
          comment = ""

        # URLがあったらコメントを添えてブックマーク追加する
        if matchOB:
          bookmark_url = matchOB.group()
          print(requests.post(bookmark_api_url + "?url=" + bookmark_url + "&comment=" + comment, auth= hatena_auth).content)


tweet_to_hatebu()

必要なライブラリをインストールして実行するとツイート取得してブックマーク追加することができます。

> pip install requests requests_oauthlib
> python main.py
スクリーンショット 2019-05-18 14.47.22.png スクリーンショット 2019-05-18 13.56.31.png

AWS Lambdaを利用して定期実行させる

実装できましたがこのままだと手動でスクリプト実行しなきゃいけないので、AWS Lambdaに関数を登録して定期実行させます。

前提

  • AWSアカウントがある
  • AWS Lambda関数作成権限がある

実装の手直し

AWS Lambdaで実行できるように実装を手直しします。tweet_to_hatebu メソッドの実装は変わらずです。

> mv main.py lambda_function.py
lambda_function.py
import json
import requests
from requests_oauthlib import OAuth1
from requests_oauthlib import OAuth1Session
import datetime,time,sys
import re

def lambda_handler(event, context):
    tweet_to_hatebu()
    
    return {
        "statusCode": 200,
        "body": json.dumps("Hello from Lambda!")
    }

def tweet_to_hatebu():
()

ZIPにまとめてアップロードする

こちらを参考に必要となるライブラリと実装をZIPにまとめてアップロードしてAWS Lambda関数を作成します。

【Python】AWS Lambdaで外部モジュールを使用する - Qiita
https://qiita.com/SHASE03/items/16fd31d3698f207b42c9

> pip install requests requests_oauthlib -t ./
> zip -r tweet2hatebu.zip ./*

ZIPファイルアップロード後は、ブラウザ上でファイル編集できるようになります。
Lambda_Management_Consoleのコピー.png

このままだとdatetime.datetime.now() で日時を取得したときにUTC時間となるので関数の環境設定にTZ 変数を追加します。値はAsia/Tokyo です。

AWS Lambdaのタイムゾーン変更 - Qiita
https://qiita.com/nullian/items/39ecf1f6d0194b72e8e6
スクリーンショット 2019-05-18 15.12.02.png

保存してからテストして動作する確認します。
スクリーンショット 2019-05-18 13.56.43.png

Amazon CloudWatch Eventを利用して定期的に関数が実行するようにします。ルールはお好みで。
スクリーンショット 2019-05-18 13.58.53.png
スクリーンショット 2019-05-18 13.59.38.png

これで、定期的にツイートに含まれるURLをはてなブックマークにブックマーク追加する仕組みが出来上がりました。
スクリーンショット 2019-05-18 14.00.24.png
やったぜ。

まとめ

調査から実装してAWS Lambdaで動かせるようにするまで2時間くらいでできました。
安定稼働させるには各APIの利用制限などを考慮した実装にする必要があるかと思いますが、個人で利用する分にはこれくらい雑な実装でも良いかなと思います。

参考

はてなブックマークがIDコール廃止。外部サービス連携も順次終了 - Impress Watch
https://www.watch.impress.co.jp/docs/news/1150477.html

はてなブックマークを #API で追加する #python スクリプトの例 - Qiita
https://qiita.com/YumaInaura/items/0641702719fef0260d8e

はてなブックマーク ブックマーク API - Hatena Developer Center
http://developer.hatena.ne.jp/ja/documents/bookmark/apis/rest/bookmark#post_my_bookmark_parameter_comment

Consumer key を取得して OAuth 開発をはじめよう - Hatena Developer Center
http://developer.hatena.ne.jp/ja/documents/auth/apis/oauth/consumer

はてなブックマーク Web APIを手軽に使えるgemを作った - Qiita
https://qiita.com/t__nabe/items/7918b6c6232eb14c248e

Pythonでサクッと簡単にTwitterAPIを叩いてみる - Qiita
https://qiita.com/ogrew/items/0b267f57b8aaa24f1b73

Twitter REST APIの使い方
https://syncer.jp/Web/API/Twitter/REST_API/

Twitterの検索で時間を含む期間指定をする方法 - Qiita
https://qiita.com/kai_kou/items/336a9d1290c13abba7e2

Twitter検索:特定のユーザー、アカウント内を指定して検索する方法
https://appbu.jp/twitter-search-from-specific-user

AWS Lambdaのタイムゾーン変更 - Qiita
https://qiita.com/nullian/items/39ecf1f6d0194b72e8e6

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?