見出し画像

画像認識とTinderをくみあわせてみたら?:画像認識してTinder写真を選択するアプリ作ってみた

最近Webアプリつくるための勉強のためにTinderをpythonでいじってます!※pynderだけだと想定外の動作をしたため、加筆訂正します!

そこそこいじるのに慣れてきたので、画像認識をちょっとかませてTinder自動化bot作ってみたくなりました!!

画像認識&Tinder

まずは

1.顔写真のみをいいね(右スワイプ)し、あとはいいえ(左スワイプ)する

2.いいねした顔写真、いいえした顔写真を別々のフォルダに保存する

3.スワイプしている状況を表示する

というのを目標にしてみました。。

環境設定は今まで二つの記事を参考にしてみてください。

基本的にはpynder, openCV, selenium, Chromedriverが胆になります。

これにBeutifulsoupとCSSをいじるcssutilsをつかいます。

メインはSelemiumとChromedriverでブラウザをいじると同時に、BeutifulsoupとCSSでブラウザ情報情報を加工します。

python Tinder APIは場所指定のみに使いますので、いらないかもしれません。

Beautifulsoupのインストールは

!pip install beautifulsoup4

cssutilsのインストールは

 !pip install cssutils

です。

顔認識のところは

の二つを参考にしました。

FaceBook ID Facebook Token をゲットしよう

まずはFacebookアカウントをもとにTinderアカウントをゲットしてください。

これに基づいて、付与される

Facebook ID

Facebook tinder token

がTinderをいじるのに必要になります。

Facebook IDは以下のサイトで

Facebook tokenは以下をクリックすると、

facebookのログイン画面が出ます。そこでfacebookにログインすると、tinderの認証を求められ、画面が変わります。そこのURLウィンドウにでてくる次のような情報の中のXXXXXXXXXX部分がtokenになります(実際はすごく長いです)。

fbconnect://success/#access_token=XXXXXXXXXX&expires_in=5022&reauthorize_required_in=7775999

上のURLは長いので、以下のサイトに張り付けると作業しやすいです。

以上で、必要な情報はそろいましたので次は実装です。

実装編

インポート部分です

import os
import re
import random
import matplotlib.pyplot as plt
import cv2
import numpy as np
import urllib.request
from urllib.parse import quote
import httplib2
import pynder
import time
import random
import sys
import pandas as pd
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.common.by import By
import selenium
import cssutils
from bs4 import BeautifulSoup

画像を読み込んで保存する関数(Aidemyさんのブログ参照)

def get_image(img_url): # ウェブ上の画像をダウンロードする
    opener = urllib.request.build_opener()
    http = httplib2.Http(".cache")
    response, content = http.request(img_url)            
    return content

def aidemy_imshow(name, img): # Jupyter notebook上で画像を表示
    b,g,r = cv2.split(img)
    img = cv2.merge([r,g,b])
    plt.imshow(img)
    plt.show()
cv2.imshow = aidemy_imshow

def jpg_count(folder_name): # ディレクトリ内のjpgファイルを数える
    files = os.listdir("./"+folder_name)
    jpgcount = 0
    for file in files:
        index = re.search(".jpg", file)
        if index:
            jpgcount += 1
    return jpgcount

def image_save(img,folder_name): # 画像を保存する
    # ディレクトリがなければ作る
    if not os.path.exists(folder_name):
        os.mkdir(folder_name)
    jpgcount = jpg_count(folder_name)
    # カウント数+1でファイル名をつけて保存
    w_pass = "./{}/{}.jpg".format(folder_name,jpgcount)
    cv2.imwrite(w_pass,img)

画像をバッファリングして、顔の正面画像かどうか判断する関数(workout_engineerさんのブログ)。OpenCVを使っています!

def analysis_face(img):
    # web上の画像をlocalに保存する
    # Tinder APIで取得した画像URLは、サーバ上にあるのでOpenCVで解析できない
    local_image_path = "test.jpg"
    request_img = urllib.request.urlretrieve(img, local_image_path)
    face_cascade = cv2.CascadeClassifier("C:/Users/USERNAME/Anaconda/Lib/site-packages/cv2/data/haarcascade_frontalface_alt.xml")
    # 画像を読み込ませる
    loaded_img = cv2.imread(f"{local_image_path}")
    img_gray = cv2.cvtColor(loaded_img, cv2.COLOR_BGR2GRAY)
    #cascade = cv2.CascadeClassifier(cascade_path)
    faces = face_cascade.detectMultiScale(img_gray, scaleFactor=1.1, minNeighbors=2, minSize=(64,64))
    if len(faces) == 0:
        print("顔写真なし")
        #os.remove(local_image_path)
        # 画像を削除する
        return False
        # 顔検出されなかったら、抜ける
    else:
        print("顔写真あり")
        return True

特に問題なのは顔認識するカスケード分類器の場所。Windowsだとこんな感じのPATHだと思います。USERNAME部分はPCサインインしているユーザー名を入れて下さい。あと微妙にPCによってローケーションが違うことがあるので、エクスプローラで探してみるのも重要です。

face_cascade = cv2.CascadeClassifier("C:/Users/USERNAME/Anaconda/Lib/site-packages/cv2/data/haarcascade_frontalface_alt.xml")

次にディスクトップに移動します(USERNAMEは個々人のものをいれてください)。

os.chdir("C:/Users/USERNAME/Desktop")

次にいよいよtinderとつなぐ作業

usrid = "YYYYYYYYYYYYY" # findmyfbidで取得したFacebook ID
token = "XXXXXXXXXX" # Facebook Tinder Token

session = pynder.Session(facebook_id = usrid, facebook_token = token)

これでtinderからいろいろ情報を取ってこれるようになったはずです!

Chromedriver経由で(PATHに注意。USERNAMEは個々人のものを)、Chromeブラウザを開き、そこからTinderにログインします。

chro = webdriver.Chrome('/Users/USERNAME/Desktop/chromedriver_win32/chromedriver')

#Go to Tinder.com
chro.get("https://tinder.com/app/login")

Tinderにログインすると、スワイプする画面で女の子の写真が出てると思いますので、この写真をダウンロードさせ画像認識させるという操作を行います。

当初このブラウザで見ている時とPynderでpythonからつないだ時と同じ情報が出ていると思っていたのですが、実際は違うようでした。

そこでブラウザ上に表示されている画像のURLを取ってくることが必要になります。結構ややこしいのが、CSSの背景画像として画像が表示されているらしく、いろいろやったのですが、seleniumだけではうまくとってこれませんでした。

そこでBeautifulsoupとcssutilをかまして、

     html=(chro.page_source)
        soup = BeautifulSoup(html)
        div_style = soup.find('div', { "class":"Bdrs(8px) Bgz(cv) Bgp(c) StretchedBox StretchedBox::a Cnt($blank)::a"} )['style']
        style = cssutils.parseStyle(div_style)
        url = style['background-image']
        url = url.replace('url(', '').replace(')', '') 

のように渡してあげます!

あとは自分のお気に入りの場所に移動して(下の例は横浜)、スワイプと情報どりです!

#横浜に移動
session.update_location(35.465786, 139.622313)
# 写真を保存するディレクトリを作成する
if not os.path.exists("images_f"):
        os.mkdir("images_f")

if not os.path.exists("images_n"):
        os.mkdir("images_n")
        
print("ok")

I=0
Limit = 30

key = input('Press y when the top page of tinder appears')
if key == "y":

    while I < Limit:
        I=I+1
        html=(chro.page_source)
        soup = BeautifulSoup(html)
        div_style = soup.find('div', { 'class':'Bdrs(8px) Bgz(cv) Bgp(c) StretchedBox StretchedBox::a Cnt($blank)::a'} )['style']
        print(div_style)
        style = cssutils.parseStyle(div_style)
        url = style['background-image']
        url = url.replace('url(', '').replace(')', '') 
        face_bool = analysis_face(url)

        if not face_bool:
            chro.find_element_by_tag_name("body").send_keys(Keys.LEFT)
            img_buf = np.fromstring(get_image(url), dtype='uint8')
            img = cv2.imdecode(img_buf, 1)
            image_save(img,"./images_n")
            print(I)
            time.sleep(0.5)
            continue
  
        else:
            chro.find_element_by_tag_name("body").send_keys(Keys.RIGHT)
            img_buf = np.fromstring(get_image(url), dtype='uint8')
            img = cv2.imdecode(img_buf, 1)
            image_save(img,"./images_f")
            print(I)
            time.sleep(0.5)
    else:
        print("swipe"+str(Limit)+ "people")

実際の画面はこんな感じです。

何らかの基準で顔写真を選んでいて、見ていると楽しいです。

えっつ、それ捨てる??

みたいなww

犬、漫画は除外するのは良いのですが、花を選んだのには吹いてしまいました。あと人の顔がきちんと写っているにもかかわらず捨ててる例もあります。

精度はまだまだのようですね!!!

OpenCVをいじればもう少し精度が上がるのかもしれません。これについては今後の課題としたいと思います。

ただこのシステム面白いので、もう少し勉強して、本格的に画像認識できるTinderアプリ作っていきたいです!





この記事が気に入ったらサポートをしてみませんか?