[PYTHON] Triez les visages d'anime en grattant les pages de personnages d'anime avec Beautiful Soup et Selenium

Aikatsu! Je voulais utiliser la photo du visage d'un personnage pour dessiner les résultats de l'analyse de la série, mais le nombre de personnes est important et le fonctionnement manuel est gênant. J'ai donc gratté avec Beautiful Soup et Print Screen avec du sélénium. J'ai décidé de le faire automatiquement jusqu'à ce que le visage du personnage soit découpé dans PrintScreen avec OpenCV.

Département de raclage

Tout d'abord, un système de préparation préalable

from urllib import request
from bs4 import BeautifulSoup
from selenium import webdriver
import pandas as pd
import time
import os
import shutil
import itertools

#OpenCV n'autorise pas les noms de fichiers japonais, donc chargez le fichier de mappage
df=pd.read_csv("C:/XXXX/aikatsu_name_romaji_mapping.tsv", sep='\t', engine='python', encoding="utf-8")

#Charger le pilote Chrome
driver = webdriver.Chrome("C:/XXXX/chromedriver/chromedriver.exe") 

#Avoir une URL de tuple à gratter
character_urls =(
    "http://www.aikatsu.net/01/character/index.html",
    "http://www.aikatsu.net/02/character/index.html",
    "http://www.aikatsu.net/03/character/index.html",
    "http://www.aikatsu.net/aikatsustars_01/character/index.html",
    "http://www.aikatsu.net/aikatsustars_02/character/index.html",
    "http://www.aikatsu.net/aikatsufriends_01/character/",
    "http://www.aikatsu.net/aikatsufriends_02/character/",
    "http://www.aikatsu.net/character/"
)

#Création d'un répertoire pour stocker PrintScreen
target_dir = "C:/XXXX/download/"

if os.path.isdir(target_dir):
    shutil.rmtree(target_dir)
    time.sleep(1)
os.mkdir(target_dir)

Il aurait peut-être été préférable de faire de la création de répertoire une fonction.

La cartographie est aussi simple que cela.

scraping_aikatsu3.PNG

J'utilise Pandas uniquement parce que le nombre de personnages cibles est d'environ 67 et qu'il n'est pas nécessaire de le rendre DB ou riche, et je peux le faire rapidement avec juste des connaissances.

Ceci et cela lors de l'utilisation de sélénium

Lorsque vous utilisez Selenium, l'emplacement de stockage du pilote est généralement défini dans la variable d'environnement, mais comme il s'agit d'un outil jetable, il n'a pas besoin d'être aussi riche. Donc, tout en faisant référence à ce qui suit, j'ai écrit le pilote en solide. Introduction à Selenium commençant avec seulement 3 lignes de python

De plus, l'erreur suivante s'est produite au moment de l'exécution. WebDriverError: unknown error: Runtime.executionContextCreated has invalid Cela peut être résolu en faisant correspondre la version du pilote que vous utilisez avec la version chrome car elle est différente de la version chrome.

Département de mise en œuvre du grattage

for character_url in character_urls:
    html = request.urlopen(character_url)
    soup = BeautifulSoup(html, "html.parser")
    
    #Obtenez des informations sur chaque personnage
    characters=soup.find_all("a")
    idol_names = [i.find('img') for i in characters]
    urls = [i.get('href') for i in characters]
    
    character_url_prefix=character_url.split("index.html")
    
    for i, j in zip(idol_names, urls):
        #Si la balise alt ne peut pas être prise correctement, le processus est rejeté.
        if i == None:
            continue
        #Repousser les informations autres que les personnages
        if j.startswith("http") or j.startswith("../")  or j.startswith("index"):
            continue

        idol_name = i.get("alt").replace(" ","").replace(" ","")
        print(idol_name)
        
        #affichage et réglage de la page sélénium
        driver.get(character_url_prefix[0]+j) 
        driver.set_window_size(1250, 1036)
        driver.execute_script("document.body.style.zoom='90%'")

        #Shirayuri Kaguya définit une valeur fixe car les informations alt sont vides
        if idol_name == "":
            idol_name = "Shirayuri Kaguya"
            
        #OpenCV ne peut pas utiliser de noms japonais, alors convertissez-le en caractères romains
        idol_name_romaji = df[df["character"]==idol_name]["romaji"].values[0]

        file_name="{}{}.png ".format(target_dir, idol_name_romaji)

        #Si un fichier du même nom existe déjà, renommez-le.
        if os.path.exists(file_name):
            for i in itertools.count(1):
                newname = '{} ({})'.format(idol_name_romaji, i)
                file_name="{}{}.png ".format(target_dir, newname)

                #Quitter si le fichier du même nom n'existe pas
                if not os.path.exists(file_name):
                    break
                    
        #Définissez un temps de sommeil légèrement plus long pour éviter les effets lors de la transition vers les pages Web
        time.sleep(5)            
        driver.save_screenshot(file_name)

driver.quit()

Vous pouvez obtenir les données comme ceci. À l'origine, le nom japonais alt a été ajouté au nom du fichier, mais comme il ne peut pas être lu par OpenCV, il est volontairement converti en notation de caractères romains. (Romaji est approprié, vous pouvez donc faire une erreur)

scraping_aikatsu.PNG

De plus, lors de l'obtention des noms de personnages (idol_names), None sera obtenu comme indiqué ci-dessous. Puisque l'URL et le nom du personnage de chaque personnage sont bouclés avec zip, il est nécessaire d'avoir le même nombre d'éléments, donc j'essaye de jouer à l'intérieur plutôt qu'avant la boucle.

[<img alt="Aikatsu en parade!" src="../images/logo.png "/>,
 <img alt="Aikatsu en parade! la communication" src="../images/bt-aikatsuonparadecom.png "/>,
 <img alt="Aikatsu en parade! Quel est" src="../images/bt-aikatsuonparade.png "/>,
 <img alt="Diffuser des informations" src="../images/bt-tvinfo.png "/>,
 <img alt="personnage" src="../images/bt-character.png "/>,
 <img alt="Récit" src="../images/bt-story.png "/>,
 <img alt="CD" src="../images/bt-cd.png "/>,
 <img alt="BD/DVD" src="../images/bt-bddvd.png "/>,
 <img alt="NEWS" src="../images/bt-news.png "/>,
 <img alt="TOP" src="../images/bt-top.png "/>,
 <img alt="Raki Himeishi" src="images/bt-raki.png "/>,
 <img alt="Yuki Aine" src="images/bt-aine.png "/>,
 <img alt="Mio Minato" src="images/bt-mio.png "/>,
 <img alt="Hoshimiya Ichigo" src="images/bt-ichigo.png "/>,
 <img alt="Akari Ozora" src="images/bt-akari.png "/>,
 <img alt="Yume Nijino" src="images/bt-yume.png "/>,
 <img alt="BANDAINAMCO Pictures" height="53" src="../images/bnp.png " width="118"/>,
 None]

Section OpenCV

import os
import cv2
from pathlib import Path

#Créer un annuaire
download_dir = '{0}parse/'.format(target_dir)

if os.path.isdir(download_dir):
    shutil.rmtree(download_dir)
    time.sleep(1)
os.mkdir(download_dir)

#Créer un classificateur basé sur le fichier de quantité d'objets
classifier = cv2.CascadeClassifier('C:/XXX/lbpcascade_animeface.xml')

#Récupérez les fichiers dans le répertoire récupéré
p = Path(target_dir)

for i in list(p.glob("*.png ")): 
    #Détection facial
    image = cv2.imread(i.as_posix())
    
    #Créer un annuaire
    file_tmp=i.as_posix().split("/")
    parse_dir = '{0}{1}/'.format(download_dir, file_tmp[len(file_tmp)-1:len(file_tmp)][0].split(".")[0])
    os.mkdir(parse_dir)
    
    #Échelle de gris
    gray_image = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    faces = classifier.detectMultiScale(gray_image)

    for i, (x,y,w,h) in enumerate(faces):
        #Découpez les faces une à une. Ajustez la coordonnée y pour la rendre rectangulaire
        face_image = image[y-50:y+h, x:x+w]
        output_path = '{0}{1}.png'.format(parse_dir, i)
        #l'écriture
        cv2.imwrite(output_path ,face_image)

Je voulais qu'OpenCV soit rectangulaire, j'ai donc juste modifié un peu les coordonnées et le contenu est le suivant. Détection de visage d'anime avec OpenCV

scraping_aikatsu2.PNG

Vous pouvez l'obtenir comme ça. En raison de la pose, certains d'entre eux n'ont pas été identifiés comme des personnages par le classificateur. Comme il n'y a que quelques personnes, je me demande si je dois le faire manuellement.

Recommended Posts

Triez les visages d'anime en grattant les pages de personnages d'anime avec Beautiful Soup et Selenium
Racler plusieurs pages avec Beautiful Soup
Grattage avec Python et belle soupe
Gratter avec une belle soupe
Grattage de table avec belle soupe
J'ai essayé différentes choses avec Python: le grattage (Beautiful Soup + Selenium + PhantomJS) et l'analyse morphologique
Essayez de gratter avec Python + Beautiful Soup
Grattage avec Python, Selenium et Chromedriver
Grattage de site Web avec Beautiful Soup en Python
Pratiquer le web scraping avec Python et Selenium
Grattage au sélénium
Grattage au sélénium ~ 2 ~
Grattage avec du sélénium
Méthodes fréquemment utilisées de sélénium et de belle soupe
Classer les visages d'anime par suite / apprentissage profond avec Keras
[Python] Supprimer en spécifiant une balise avec Beautiful Soup
Méthode de test automatisée combinant Beautiful Soup et Selenium (Python)
Grattage réussi avec Selenium
Grattage avec du sélénium [Python]
Exploration Web, scraping Web, acquisition de caractères et sauvegarde d'image avec python
Obtenez l'URL de destination du lien en spécifiant la phrase de texte avec le grattage Python (Beautiful Soup) + XPath
Grattage au sélénium en Python
Grattage avec Selenium + Python Partie 1
Grattage avec du sélénium en Python
Grattage avec Selenium + Python Partie 2
Gratter la page i-town avec du sélénium
Pratique de l'exploration avec Beautiful Soup
Accro au code de caractère en insérant et en extrayant des données avec SQL Alchemy