I, a fan of Mayu Matsuoka (commonly known as Mayura), I made a LINE Bot just for me, just for me.
After about 5 years as a fan
→ Search for tweets related to Mayu Matsuoka on the Twitter timeline. → Save Mayu Matsuoka's images and videos
I don't enjoy this work as much as I used to, and I myself become a member of society, so I don't have time to surf Twitter every day.
** Let's automate everything! !! ** **
So, as the first step, search for tweets with images and videos that are popular recently on Twitter, get the image URL, and send it on time every day using LINE Bot! !! !! !!
Please add friends if you like.

The explanation of how to use twitter API and how to register LINE Developers is omitted here.
Twitter Developers page https://developer.twitter.com/en/portal/dashboard
tweepy official documentation http://docs.tweepy.org/en/latest/
The environment variables are described in the Yaml file in the env folder.
search_tweets.py
import os
import tweepy
from datetime import datetime, date, timedelta
from dateutil.relativedelta import relativedelta
#Set of environment variables
consumer_key = os.getenv('TWITTER_CONSUMER_KEY')
consumer_secret = os.getenv('TWITTER_CONSUMER_SECRET')
access_token = os.getenv('TWITTER_ACCESS_TOKEN')
access_token_secret = os.getenv('TWITTER_ACCESS_TOKEN_SECRET')
bearer_token = os.getenv('TWITTER_ACCESS_TOKEN_SECRET')
#on twitter#Image search for Mayu Matsuoka and get URL function
def search_tweets():
    auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
    auth.set_access_token(access_token, access_token_secret)
    api = tweepy.API(auth)
env/stg.yml
STAGE: stg
LINE_ACCESS_TOKEN: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
LINE_CHANNEL_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
USER_ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWITTER_CONSUMER_KEY: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWITTER_CONSUMER_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWITTER_BEAR_TOKEN: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWITTER_ACCESS_TOKEN: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWITTER_ACCESS_TOKEN_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TZ: Asia/Tokyo
search_tweets.py
    #Get yesterday's date
    yesterday = datetime.strftime(datetime.today() - relativedelta(days=1), f"%Y-%m-%d")
    #Twitter search word
    q = f'#Mayu Matsuoka OR Mayu Matsuoka-Mayu Matsuoka similar filter:media exclude:retweets min_faves:10 since:{yesterday} min_retweets:2'
    #Search
    cric_tweet = tweepy.Cursor(
        api.search, q=q, 
        tweet_mode='extended', #Get all omitted tweets
        include_entities=True).items(20) #Get all omitted links
    #image
    contents = []
    for tweet in cric_tweet:
        print(tweet.full_text)
        try:
            #An array that stores URLs of images and videos in tweets
            media = tweet.extended_entities['media']
            print(media)
            for m in media:
                print(m)
                #Image URL of the preview screen required when sending with LINE Bot
                preview = m['media_url_https']
                #For video
                if m['type'] == 'video':
                    #When getting the video URL, content_type is video/If it is not mp4, the video will not play when sent by LINE Bot.
                    #Also, I wanted to write it in one line, so I used the comprehension notation forcibly and finally[0]I got the URL in.
                    origin = [variant['url'] for variant in m['video_info']
                              ['variants'] if variant['content_type'] == 'video/mp4'][0]
                #For images
                else:
                    #URL of the content image displayed when the preview image is clicked
                    origin = m['media_url_https']
                #Arrange it in the required form when sending with the LINE Bot Messaging API.
                content = {'preview': preview,
                           'origin': origin, 'type': m['type']}
                contents.append(content)
            print('--------------------------------------------')
        except:
            print('noUrl')
            print('--------------------------------------------')
    return contents
I wrote in the article about when I was addicted to this process, so please do not miss it ↓
A story I was addicted to trying to get a video url with tweepy https://qiita.com/soma_sekimoto/items/65c664f00573284b0b74
LINE Bot Official Reference https://developers.line.me/ja/docs/messaging-api/getting-started/
LINE Bot SDK Github https://github.com/line/line-bot-sdk-python
send_media.py
# -*- coding:utf-8 -*-
import logging
from linebot import LineBotApi
from linebot.exceptions import LineBotApiError
from linebot.models import (
    TextSendMessage, ImageSendMessage, VideoSendMessage
)
import requests
import os
import search_tweets
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def send_media(event, context):
    logger.info("Authentication OK.")
    #Create a LineBot API object
    token = os.getenv('LINE_ACCESS_TOKEN')
    line_bot_api = LineBotApi(token)
    try:
        #Get an array of image and video URL objects with twitter search
        all_media_list = search_tweets.search_tweets()
        print('all_media_list')
        print(all_media_list)
        messages = []
        #Further transform the array obtained by tweepy for LINE Bot
        for media in all_media_list:
            item = VideoSendMessage(
                original_content_url=media['origin'], preview_image_url=media['preview']) if media['type'] == 'video' else ImageSendMessage(
                original_content_url=media['origin'], preview_image_url=media['preview'])
            messages.append(item)
        print('messages')
        print(messages)
        #Be sure to send messages only to yourself, except in a production environment.
        if os.getenv('STAGE') == 'prod':
            #For some reason, I can only send 4 images at a time, so I will send them in two parts. (Still, it is still a mystery that only 7 sheets can be sent in total)
            line_bot_api.broadcast(
                messages[0:3]
            )
            line_bot_api.broadcast(
                messages[4:8]
            )
        else:
            user_id = os.getenv('USER_ID')
            line_bot_api.push_message(
                user_id,
                messages[0:3]
            )
            line_bot_api.push_message(
                user_id,
                messages[4:8]
            )
    except LineBotApiError as e:
        print(e.status_code)
        print(e.error.message)
        print(e.error.details)
    return {"stautsCode": 200, "body": "OK"}
if __name__ == '__main__':
    send_media(None, None)
requirements.py
import os
import sys
requirements = os.path.join(
    os.path.split(__file__)[0],
    '.requirements',
)
if requirements not in sys.path:
    sys.path.append(requirements)
requirements.txt
requests 
print_function
line-bot-sdk #Module that can use LINE Bot SDK in Python
tweepy #Module that can use Twitter API in Python
serverless.yml
service: mayu-delivery
provider:
  name: aws
  runtime: python3.7
  region: ap-northeast-1
  stage: stg
  deploymentBucket: sls-deps #Specifying a deployment bucket
  environment: ${file(./env/${opt:stage, self:provider.stage}.yml)}
plugins:
  - serverless-python-requirements
custom:
  scheduleEnabled:
    prod: true
    stg: false
    local: false
functions:
  send_media:
    handler: media_deliver.send_media
    timeout: 300
    events:
      - http:
          path: linebot/send_media
          method: post
      - schedule:
          rate: cron(30 3 * * ? *)
          enabled: ${self:custom.scheduleEnabled.${opt:stage, self:provider.stage}}
sls deploy
endpoints:
  POST - https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/linebot/send_media
functions:
  send_media: mayu-delivery-prod-send_media
Don't forget to copy the URL of the above endpoints to the LINE Bot side.

search_tweets.py
import os
import tweepy
from datetime import datetime, date, timedelta
from dateutil.relativedelta import relativedelta
consumer_key = os.getenv('TWITTER_CONSUMER_KEY')
consumer_secret = os.getenv('TWITTER_CONSUMER_SECRET')
access_token = os.getenv('TWITTER_ACCESS_TOKEN')
access_token_secret = os.getenv('TWITTER_ACCESS_TOKEN_SECRET')
bearer_token = os.getenv('TWITTER_ACCESS_TOKEN_SECRET')
#on twitter#Image search for Mayu Matsuoka and get URL
def search_tweets():
    auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
    auth.set_access_token(access_token, access_token_secret)
    api = tweepy.API(auth)
    yesterday = datetime.strftime(
        datetime.today() - relativedelta(days=1), f"%Y-%m-%d")
    q = f'#Mayu Matsuoka OR Mayu Matsuoka-Mayu Matsuoka similar filter:media exclude:retweets min_faves:10 since:{yesterday} min_retweets:2'
    cric_tweet = tweepy.Cursor(
        api.search, q=q, tweet_mode='extended', include_entities=True).items(20)
    contents = []
    for tweet in cric_tweet:
        print(tweet.full_text)
        try:
            media = tweet.extended_entities['media']
            print(media)
            for m in media:
                print(m)
                preview = m['media_url_https']
                if m['type'] == 'video':
                    origin = [variant['url'] for variant in m['video_info']
                              ['variants'] if variant['content_type'] == 'video/mp4'][0]
                else:
                    origin = m['media_url_https']
                content = {'preview': preview,
                           'origin': origin, 'type': m['type']}
                contents.append(content)
            print('--------------------------------------------')
        except:
            print('noUrl')
            print('--------------------------------------------')
    return contents
if __name__ == "__main__":
    search_tweets()
media_deliver.py
# -*- coding:utf-8 -*-
import logging
from linebot import LineBotApi
from linebot.exceptions import LineBotApiError
from linebot.models import (
    TextSendMessage, ImageSendMessage, VideoSendMessage
)
import requests
import os
import search_tweets
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def send_media(event, context):
    logger.info("Authentication OK.")
    #Create a LineBot API object
    token = os.getenv('LINE_ACCESS_TOKEN')
    line_bot_api = LineBotApi(token)
    try:
        #Get an array of image and video URL objects with twitter search
        all_media_list = search_tweets.search_tweets()
        print('all_media_list')
        print(all_media_list)
        messages = []
        for media in all_media_list:
            item = VideoSendMessage(
                original_content_url=media['origin'], preview_image_url=media['preview']) if media['type'] == 'video' else ImageSendMessage(
                original_content_url=media['origin'], preview_image_url=media['preview'])
            messages.append(item)
        print('messages')
        print(messages)
        if os.getenv('STAGE') == 'prod':
            line_bot_api.broadcast(
                messages[0:3]
            )
            line_bot_api.broadcast(
                messages[4:8]
            )
        else:
            user_id = os.getenv('USER_ID')
            line_bot_api.push_message(
                user_id,
                messages[0:3]
            )
            line_bot_api.push_message(
                user_id,
                messages[4:8]
            )
    except LineBotApiError as e:
        print(e.status_code)
        print(e.error.message)
        print(e.error.details)
    return {"stautsCode": 200, "body": "OK"}
if __name__ == '__main__':
    send_media(None, None)
requirements.py
import os
import sys
requirements = os.path.join(
    os.path.split(__file__)[0],
    '.requirements',
)
if requirements not in sys.path:
    sys.path.append(requirements)
requirements.txt
requests
line-bot-sdk
print_function
tweepy
serverless.yml
service: mayu-delivery
provider:
  name: aws
  runtime: python3.7
  region: ap-northeast-1
  stage: stg
  deploymentBucket: sls-deps
  environment: ${file(./env/${opt:stage, self:provider.stage}.yml)}
plugins:
  - serverless-python-requirements
custom:
  scheduleEnabled:
    prod: true
    stg: false
    local: false
functions:
  send_media:
    handler: media_deliver.send_media
    timeout: 300
    events:
      - http:
          path: linebot/send_media
          method: post
      - schedule:
          rate: cron(30 3 * * ? *)
          enabled: ${self:custom.scheduleEnabled.${opt:stage, self:provider.stage}}
env/stg.yml
STAGE: stg
LINE_ACCESS_TOKEN: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
LINE_CHANNEL_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
USER_ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWITTER_CONSUMER_KEY: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWITTER_CONSUMER_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWITTER_BEAR_TOKEN: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWITTER_ACCESS_TOKEN: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWITTER_ACCESS_TOKEN_SECRET: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TZ: Asia/Tokyo
The LINE Bot is still unsatisfactory for me, but I will continue to improve and add functions.
If you find something wrong or something more like this, please leave a comment! !!
And please add friends! !! !! !!

https://blog.serverworks.co.jp/sls-line-beginner
Recommended Posts