よくわからないエンジニア

よく分からないエンジニアの日々の記録

よくわからないエンジニア

python Twitterユーザーの画像を収集する

お絵かき用の画像が不足してきたので、画像収集しようと思いたちました。
シェルベースでは以前使ったberryjackがあるのですが、Twitterは利用規約で明確にスクレイピング禁止してるため、おとなしくAPI使って実装します。

目次

前提条件

とりあえず手持ちのMacOSで作りましたが、Linux環境なら追加のライブラリさえちゃんと入れればそのまま動くと思います。(一応手持ちのラズパイでは動きました)
TwitterのAPIですが、申請すれば普通に使えるはずなので、事前に登録して用意しておいて下さい。
pythonは3を使ってます。

とりあえず自分のアカウントに対して実行してみます。

よくわからないエンジニア (@unknownenginee1) | Twitter

実装

使い方

.
├── images
│   └── unknownenginee1
└── tmdl.py

imagesの中にtwitterのユーザー名のディレクトリを作っておけば、そのユーザーの画像を拾ってきます。複数でもOKです。
起動の仕方はpython tmdl.pyで動きますが、tmdl.pyと同じ階層で実行して下さい。頼むぞ。

ソースコード

MAX_COUNTは1ユーザーあたりで取得する最大画像数です。変更すればもっと少なく出来ますが、self.max_count単位でツイートを取ってくるので、その単位でしか設定出来ません。(500と設定しても、self.max_countが200の場合、600まで画像を取得します。)

各key,secretはTwitter APIを自分で発行したもので置き換えて下さい。

import twitter
import json
import time
import os
import pathlib
import requests

ACCESS_TOKEN_KEY = '******************'
ACCESS_TOKEN_SECRET = '******************'
CONSUMER_KEY = '******************'
CONSUMER_SECRET = '******************'
MAX_COUNT=3000

def get_auth():
    auth = twitter.OAuth(ACCESS_TOKEN_KEY,
                         ACCESS_TOKEN_SECRET,
                         CONSUMER_KEY,
                         CONSUMER_SECRET)
    return auth

def get_directory():
    template_path=None
    if not template_path:
        base_dir = os.path.dirname(os.path.abspath(__file__))
        template_path = os.path.join(base_dir, 'images')
    dirlist=os.listdir(template_path)
    return dirlist

def get_save_directory():
    save_path=None
    if not save_path:
        base_dir = os.path.dirname(os.path.abspath(__file__))
        save_path = os.path.join(base_dir, 'images')
    return save_path

class GetMedia(object):
    def __init__(self,tweet,screen_name,max_count=200):
        self.tweet=tweet
        self.MAX_ID=0
        self.COUNT=0
        self.MAX_COUNT=max_count
        self.mediacount=200
        self.screen_name = screen_name
    def get_timeline(self):
        try:
            if self.MAX_ID == 0:
                self.timelines = self.tweet.statuses.user_timeline(screen_name=self.screen_name,count=self.mediacount,include_rts='false')
            else:
                self.timelines = self.tweet.statuses.user_timeline(screen_name=self.screen_name,count=self.mediacount, max_id=self.MAX_ID,include_rts='false')
        except:
            print('no user.check screen name')
            self.timelines=None
    def download_media(self):
        for self.timeline in self.timelines:
            try:
                self.COUNT+=1
                url=self.timeline['entities']['media'][0]['media_url']
                filename=url.split("/")
                fname = filename[len(filename)-1]
                save_path=get_save_directory()
                save_file_name=os.path.join(save_path,self.screen_name,fname)
                if os.path.exists(save_file_name):
                    print(save_file_name+'が既に存在します')
                    self.COUNT=self.MAX_COUNT
                    self.COUNT+=1
                    break
                r = requests.get(url)
                with open(save_file_name,'wb') as file:
                    file.write(r.content)
                    print(save_file_name+'を保存しました。')
            except KeyError:
                pass
            self.MAX_ID = self.timeline['id']
            self.MAX_ID-=1
    def get_media(self):
        while True:
            self.get_timeline()
            if not self.timelines:
                break
            elif self.COUNT > self.MAX_COUNT:
                break
            self.download_media()
            time.sleep(60)

dirlist=get_directory()
auth=get_auth()
tweet=twitter.Twitter(auth=auth)
for directory in dirlist:
    downloader=GetMedia(tweet,directory,MAX_COUNT)
    downloader.get_media()

気が向いたらなんとなく中身の解説くらいするかもしれないし、とりあえず想定通り動いているので、しないかもしれない。
公開してから気がついたけど、これだと画像一枚しか引っ張ってこれないな。