[PYTHON] Umweltfreundliches Scraping mit Bildverarbeitung

Fortsetzung Versuchen Sie, mit Python (2) eine Erfassungssoftware zu erstellen, die so genau wie möglich ist. https://qiita.com/akaiteto/items/56bfd8d764d42b9ff508 Versuchen Sie, mit Python (1) eine Erfassungssoftware zu erstellen, die so genau wie möglich ist. https://qiita.com/akaiteto/items/b2119260d732bb189c87

Einführung

Ich habe keine Lust mehr auf Bildschirm- und Audioaufnahmen, also mache ich noch einen Teil. Der folgende Prozess ist ein grober Prozess, der derzeit vorgesehen ist.

    1. Befehlsausführung zum angegebenen Zeitpunkt -> 2. Starten Sie den Browser mit der voreingestellten URL
    1. Nehmen Sie Browser-Screenshots und Audio auf
  1. Videoausgabe durch Zusammenführen von Browser-Screenshots und Audio

Dieses Mal werde ich den zweiten Teil machen. Ich möchte jede Struktur der Website flexibel unterstützen Ziel ist es, den Browser mit OpenCV-Bilderkennung zu betreiben, ohne HTML zu analysieren.

Ich habe den Grund für die Nachrüstung hinzugefügt, aber ... Da der Bildschirm zusammengedrückt ist, möchte ich nur das Bild verarbeiten.

Spezifikation

1. 1. Übergang zum URL-Ziel
2. Drücken Sie die Wiedergabetaste
3. 3. Bereich der Wetterkarte erkennen
4. Notieren Sie den erkannten Bereich

Stellen Sie sich eine Site vor, die ein Video einer Wetterkarte liefert. Der gesamte Prozess wird wie oben angenommen. Diesmal wird es wahrscheinlich 1-3 sein.

Ausführungsumgebung

OS : windows10 ver: python3.7 web: chrome

1. 1. Übergang zum URL-Ziel

Selenium

Verwenden wir Selenium, eine Bibliothek, mit der Sie den Browser über Befehle bedienen können. https://qiita.com/hanzawak/items/2ab4d2a333d6be6ac760 https://rabbitfoot.xyz/selenium-chrome-profile/

Nebenbei benutze ich also Chrome + Pycharm Installieren Sie den Webtreiber bei der Installation in der virtuellen Umgebung Python.

#Installation in einer virtuellen Umgebung
cd D:~ Ausgelassen ~\venv\Scripts
bat activate.bat
pip install chromedriver-binary==(Die von Ihnen verwendete Chrome-Version)

Öffne URL

Zeigen Sie die Wetterkarten-Site an. Speichern Sie auch das aufgenommene Bild des geöffneten Chroms für spätere Schritte. Wenn Sie die unten stehende Quelle verwenden, füllen Sie bitte den Abschnitt (Ihr Benutzername) aus. Einzelheiten zum Profilpfad finden Sie unter https://rabbitfoot.xyz/selenium-chrome-profile/


from selenium import webdriver
import chromedriver_binary  #Wichtig
from selenium.webdriver.chrome.options import Options
import win32gui
import win32ui
import win32con
import numpy as np
import cv2

#Holen Sie sich den Bildschirm in voller Größe
hnd = win32gui.GetDesktopWindow()
x0, y0, x1, y1 = win32gui.GetWindowRect(hnd)
fullscreen_width = x1 - x0
fullscreen_height = y1 - y0

#Browsergröße
browse_width=300
browse_height=fullscreen_height

#Starten Sie den Browser
options = Options()
options.add_argument(r"--user-data-dir=C:\Users\(Dein Benutzername)\AppData\Local\Google\Chrome\User Data")
driver = webdriver.Chrome(chrome_options=options)
driver.get("url")
driver.set_window_size(browse_width,browse_height)
driver.set_window_position(0,0)

#Browser-Screenshot
windc = win32gui.GetWindowDC(hnd)
srcdc = win32ui.CreateDCFromHandle(windc)
memdc = srcdc.CreateCompatibleDC()
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(srcdc, browse_width, browse_height)
memdc.SelectObject(bmp)
memdc.BitBlt((0, 0), (browse_width, browse_height), srcdc, (0, 0), win32con.SRCCOPY)
bmp.SaveBitmapFile(memdc, 'PointDetect.bmp')


# driver.close()

Beim Öffnen einer Site, für die eine Anmeldung erforderlich ist. Ich mag es nicht, Code mit meinem Passwort raw zu schreiben, also mache ich es nicht.

** Wenn für die Site eine Anmeldung erforderlich ist, melden Sie sich bitte vorab über Chrome an **

user data directory is already in use, please specify a unique value for --user-data-dir argument, or don't use --user-data-dir

Der obige Fehler tritt übrigens auf, wenn Chrome ausgeführt wird. Sie können Maßnahmen ergreifen, aber dieses Mal müssen nicht mehrere Chromteile gestartet werden, daher werde ich dies nicht tun.

2. Drücken Sie die Wiedergabetaste

Lassen Sie uns die Schaltfläche durch Bildverarbeitung erkennen und darauf klicken.

Als Überblick über den Prozess Holen Sie sich die Koordinaten der Wiedergabetaste und klicken Sie auf die Koordinaten in der Pyautogui-Bibliothek. Das Problem besteht darin, die Koordinaten der Wiedergabetaste abzurufen. Es gibt die folgenden zwei Vorschläge zur Prüfung.

1. 1. Erkennen Sie die Form und ermitteln Sie die Koordinaten
2. Suchen Sie den gleichen Teil wie das Bild der Wiedergabetaste

1. 1. Erkennen Sie die Form und ermitteln Sie die Koordinaten

1. 1. Erkennen Sie die Form und ermitteln Sie die Koordinaten

Machen wir es einfach mit der opencv-Funktion.

DetectTriangle.py


import cv2
import numpy as np

def DetectTriangle(img, inputNm, outputNm):
    image_obj = cv2.imread(inputNm)
    img = cv2.adaptiveThreshold(img, 255, 1, 1, 11, 2)
    cv2.imwrite("PointDetect_threshold" + outputNm, img)

    contours, hierarchy = cv2.findContours(img,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_NONE)

    for cnt in contours:
        approx = cv2.approxPolyDP(cnt, 0.1 * cv2.arcLength(cnt, True), True)
        # approx = cv2.approxPolyDP(cnt, 0.07 * cv2.arcLength(cnt, True), True)  #Parameter: Beeinflusst die Genauigkeit
        # approx = cv2.approxPolyDP(cnt, .03 * cv2.arcLength(cnt, True), True)   #Parameter: Beeinflusst die Genauigkeit
        # approx = cv2.approxPolyDP(cnt, .009 * cv2.arcLength(cnt, True), True)  #Parameter: Beeinflusst die Genauigkeit

        if len(approx) == 3:
            print("triangle")
            cv2.drawContours(image_obj, [cnt], 0, (0, 0, 255), -1)
        elif len(approx) == 4:
            print("square")
            cv2.drawContours(image_obj, [cnt], 0, (0, 255, 0), -1)
        elif len(approx) == 8:
            print("circle")
            area = cv2.contourArea(cnt)
            (cx, cy), radius = cv2.minEnclosingCircle(cnt)
            circleArea = radius * radius * np.pi
            if circleArea == area:
                cv2.drawContours(image_obj, [cnt], 0, (255, 0, 0), -1)

    cv2.imwrite(outputNm, image_obj)

inputNm = 'PointDetect2.bmp'
srcImage = cv2.imread(inputNm)

gray = cv2.cvtColor(srcImage, cv2.COLOR_BGR2GRAY)
cv2.imwrite("PointDetect_gray.png ", gray)

kernel = np.ones((4, 4), np.uint8)
dilation = cv2.dilate(gray, kernel, iterations=1)
cv2.imwrite("PointDetect_dilation.png ", dilation)

blur = cv2.GaussianBlur(dilation, (5, 5), 0)
cv2.imwrite("PointDetect_blur.png ", dilation)

DetectTriangle(blur,inputNm,"result_blur.png ")         #Verwischen
DetectTriangle(gray,inputNm,"result_gray.png ")         #Graustufen
DetectTriangle(dilation,inputNm,"result_dilation.png ") #Aufblasen (weil die Wiedergabetaste klein ist)

Die Verarbeitung, die Sie ausführen möchten, ist ungefähr wie folgt.

1. 1. Vorverarbeitung
2. Schwellenwertverarbeitung
3. 3. Konturextraktion

Ich werde es mit Google Image Search Sukusho versuchen. PointDetect2.jpg

Graustufen als Vorverarbeitung ↓ (Ich mache verschiedene andere Dinge in der Quelle) PointDetect_gray.png

Schwellenwertverarbeitung ↓ PointDetect_thresholdresult_dilation.png

Konturextraktion ↓ result_gray.png

Rot ist ein Dreieck, Grün ist ein Quadrat und Blau ist ein Kreis. Aus den Koordinaten des Umrisses der hier ermittelten Figur Es ist eine Berechnung, um die Position der Wiedergabetaste anzugeben, bei der es sich um eine Dreiecksform handelt.

・ ・ ・ ・ ・ ・

Also ging ich zur Wetterseite. Das Ergebnis war ... nicht gut. Ich habe versucht, etwas zu verwischen, zu erweitern, Parameter anzupassen usw., aber es hat nicht funktioniert.

Die Wiedergabetaste wurde ebenfalls erkannt, es gibt jedoch zu viele Fehlalarme. Erstens ist es nicht für Standorte mit vielen dreieckigen Figuren geeignet, Ein weiterer Nachteil ist, dass Sie möglicherweise die entsprechenden Parameter für jede Site anpassen müssen.

Es wäre möglich, diese Wetterstelle spezifisch zu erkennen, Ich möchte es zu einem Format machen, das auf verschiedenen Websites erstellt werden kann, daher wird Plan 1 abgelehnt.

2. Suchen Sie den gleichen Teil wie das Bild der Wiedergabetaste

2. Suchen Sie den gleichen Teil wie das Bild der Wiedergabetaste

Ich werde versuchen, es durch Template-Matching zu erkennen. Es ist ein Prozess, um festzustellen, ob dasselbe wie ein kleines Bild in einem anderen Bild enthalten ist. Um einen Vorlagenabgleich durchzuführen, muss das Bild der Wiedergabetaste die richtige Antwort sein.

無題.png Also, unter dem obigen Fluss, Fügen Sie eine Phase mit dem Namen "Bild der Wiedergabetaste abrufen (manuell)" hinzu. Ich wollte alles automatisch machen, aber es kann nicht geholfen werden.

無題.png

Referenz: https://shizenkarasuzon.hatenablog.com/entry/2020/03/23/005440

Stellen Sie sich vor Ein kleines Fenster wie das obige wird angezeigt, und der Benutzer wählt die Schaltfläche aus, auf die er im quadratischen Auswahlfenster klicken möchte (hellblau). Speichern Sie das Bild für eine Vorlage, die mit dem Bild von ... Manueller Betrieb wird nur zum ersten Mal angenommen.

Vorlagenübereinstimmung

Also werde ich versuchen, Vorlagen abzugleichen.

http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_template_matching/py_template_matching.html

Als ich es gemäß der openCV-Beispielquelle ausführte, funktionierte es sehr gut. Gehen wir mit der Politik von 2

3. 3. Bereich der Wetterkarte erkennen

Ich spiele mit opencvs Absdiff (Verschiedenes) Führt eine Bewegungserkennung für die Bilder vor und nach dem Drücken der Wiedergabetaste durch. Erkennt den Änderungsbereich.

Zusammenfassung

Ich werde die bisherigen Quellen zusammenfassen.

Als Voraussetzung ist das Bild des Teils, auf das Sie klicken möchten, Angenommen, Sie haben hier bereits ein Bild der Wiedergabetaste. ↓ Bild wie unten ausschneiden PointDetect_patch.jpg

Installieren Sie vor dem Ausführen die folgenden Bibliotheken.

pip install PyAutoGUI

In meiner Umgebung ist der folgende Fehler aufgetreten und die Installation ist fehlgeschlagen.

SyntaxError: (unicode error) 'utf-8' codec can't decode byte 0x93 in position 0: invalid start byte (sitecustomize.py, line 7)

https://qiita.com/hisakichi95/items/41002333efa8f6371d40 Ich habe eine ältere Version von PyMsgBox unter Bezugnahme auf installiert.

Also die folgende Quelle. Ich organisiere es nicht

Detect.py


from selenium import webdriver
import chromedriver_binary  #Wichtig
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
import win32gui
import win32ui
import win32con
import numpy as np
import cv2

def DetectMotion(ImgNm1,ImgNm2):
    img1 = cv2.imread(ImgNm1, 0)
    img2 = cv2.imread(ImgNm2, 0)

    img1 = img1.copy().astype("float")
    cv2.accumulateWeighted(img2, img1, 0.6)

    cv2.accumulateWeighted(img2, img1, 0.6)
    frameDelta = cv2.absdiff(img2, cv2.convertScaleAbs(img1))

    thresh = cv2.threshold(frameDelta, 3, 255, cv2.THRESH_BINARY)[1]
    contours, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    img2 = cv2.imread(TEMP_AFTER_SCREENSHOT)
    top_left_X = 9999999
    top_left_Y = 9999999
    bum_right_X = 0
    bum_right_Y = 0

    for i in range(0, len(contours)):
        if len(contours[i]) > 0:

            # remove small objects
            if cv2.contourArea(contours[i]) < 500:
                continue

            rect = contours[i]
            x, y, w, h = cv2.boundingRect(rect)
            pos_top = (x, y)
            pos_bum = (x + w, y + h)

            print(x, y, x + w, y + h)
            top_left_X = pos_top[0] if top_left_X > pos_top[0] else top_left_X
            top_left_Y = pos_top[1] if top_left_Y > pos_top[1] else top_left_Y
            bum_right_X = pos_bum[0] if bum_right_X < pos_bum[0] else bum_right_X
            bum_right_Y = pos_bum[1] if bum_right_Y < pos_bum[1] else bum_right_Y

    return (top_left_X, top_left_Y), (bum_right_X, bum_right_Y)

def DiffImage(img1,img2):
    im_diff = img1.astype(int) - img2.astype(int)
    im_diff_abs = np.abs(im_diff)
    return im_diff_abs.max()

def DetectBtn(bmp,memdc,CapFIleNm,PatchNm,scrollY):
    memdc.BitBlt((0, 0), (browse_width, browse_height), srcdc, (0, 0), win32con.SRCCOPY)
    bmp.SaveBitmapFile(memdc, CapFIleNm)
    #Schaltflächenkoordinaten abrufen
    img = cv2.imread(CapFIleNm, 0)

    img2 = img.copy()
    template = cv2.imread(PatchNm, 0)
    w, h = template.shape[::-1]

    meth = 'cv2.TM_CCOEFF_NORMED'
    img = img2.copy()
    method = eval(meth)

    res = cv2.matchTemplate(img, template, method)
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

    if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
        top_left = min_loc
    else:
        top_left = max_loc
    bottom_right = (top_left[0] + w, top_left[1] + h)

    cv2.rectangle(img, top_left, bottom_right, 255, 2)
    range = ((bottom_right[0] - top_left[0]) / 2, (bottom_right[1] - top_left[1]) / 2)
    btn_center = (int(top_left[0] + range[0]), int(top_left[1] + range[1]))
    print("Schaltfläche oben links Koordinaten", top_left)
    print("Schaltfläche oben rechts Koordinaten", bottom_right)
    print("Koordinaten der Schaltflächenmitte", btn_center)

    #Schneiden Sie das erkannte Teil aus
    img1 = img[top_left[1]: bottom_right[1], top_left[0]: bottom_right[0]]

    if DiffImage(template,img1) > 180:
        #Zu verschieden vom Schaltflächenbild-> False
        cv2.imwrite("Detect_Fail" + str(scrollY) + ".jpg ", img1)
        print("btn not exist")
        return False,(0,0)
    else:
        #Erfolg-> True
        cv2.imwrite("Detect_Success" + str(scrollY) + ".jpg ", img1)
        print("btn exist")
        return True,btn_center

TEMP_BEFORE_SCREENSHOT = 'PointDetect_before.bmp'
TEMP_AFTER_SCREENSHOT = 'PointDetect_after.bmp'
TEMP_PATCH = 'PointDetect_patch.jpg'

#Holen Sie sich den Bildschirm in voller Größe
hnd = win32gui.GetDesktopWindow()
x0, y0, x1, y1 = win32gui.GetWindowRect(hnd)
fullscreen_width = x1 - x0
fullscreen_height = y1 - y0

#Browsergröße
# browse_width=fullscreen_width
# browse_height=fullscreen_height
browse_width=1920
browse_height=1080

#Starten Sie den Browser
options = Options()
# options.add_argument(r"--user-data-dir=C:\Users\Dein Benutzername\AppData\Local\Google\Chrome\User Data")
driver = webdriver.Chrome(chrome_options=options)
driver.get("https://")
driver.set_window_size(browse_width,browse_height)
driver.set_window_position(0,0)

#Warten auf Browserverhalten
import time
time.sleep(3)

#Sukusho Vorbereitung
windc = win32gui.GetWindowDC(hnd)
srcdc = win32ui.CreateDCFromHandle(windc)
memdc = srcdc.CreateCompatibleDC()
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(srcdc, browse_width, browse_height)
memdc.SelectObject(bmp)

#Scrollen Sie, bis Sie die Schaltfläche finden
Detectflg=False
isScrolButton=False
scrollY = 0
while Detectflg==False:
    scrollY += int(fullscreen_height/4)
    #Holen Sie sich die Aufnahme vor und nach dem Scrollen
    memdc.BitBlt((0, 0), (browse_width, browse_height), srcdc, (0, 0), win32con.SRCCOPY)
    bmp.SaveBitmapFile(memdc, TEMP_BEFORE_SCREENSHOT)
    driver.execute_script("window.scrollTo(0, "+ str(scrollY) +")")
    time.sleep(5)
    memdc.BitBlt((0, 0), (browse_width, browse_height), srcdc, (0, 0), win32con.SRCCOPY)
    bmp.SaveBitmapFile(memdc, TEMP_AFTER_SCREENSHOT)

    img1 = cv2.imread(TEMP_BEFORE_SCREENSHOT, 0)
    img2 = cv2.imread(TEMP_AFTER_SCREENSHOT, 0)

    diff = DiffImage(img1,img2)
    if diff < 100:
        #Der Bildschirm ändert sich auch beim Scrollen nicht->Ich habe versagt, weil ich am Ende der Schriftrolle angekommen bin
        print("scrollbutton")
        flg=True,btn_pos
        isScrolButton=True

    flg,btn_pos = DetectBtn(bmp,memdc,TEMP_AFTER_SCREENSHOT,TEMP_PATCH,scrollY)
    Detectflg = flg

#Klicken Sie auf die Schaltflächenkoordinaten
if isScrolButton:
    print("Button nicht gefunden")
    exit()

#Wiedergabe
import pyautogui
pyautogui.click(btn_pos[0],btn_pos[1])

#Vor dem Ändern speichern
memdc.BitBlt((0, 0), (browse_width, browse_height), srcdc, (0, 0), win32con.SRCCOPY)
bmp.SaveBitmapFile(memdc, TEMP_BEFORE_SCREENSHOT)

#Warten Sie, bis sich der Bildschirm ändert
time.sleep(5)

#Nach Änderung speichern
memdc.BitBlt((0, 0), (browse_width, browse_height), srcdc, (0, 0), win32con.SRCCOPY)
bmp.SaveBitmapFile(memdc, TEMP_AFTER_SCREENSHOT)

#Bewegungserkennung
top_left,bottom_right = DetectMotion(TEMP_BEFORE_SCREENSHOT,TEMP_AFTER_SCREENSHOT)
img = cv2.imread(TEMP_AFTER_SCREENSHOT)
img1 = img[top_left[1]: bottom_right[1], top_left[0]: bottom_right[0]]
cv2.imwrite("MotionArea.jpg ", img1)

# driver.close()

Bildlauffunktion, um eine Schaltfläche und zu finden Wir haben einen Prozess hinzugefügt, um die Differenz des Bildes für eine falsche Erkennung zu verwenden, wenn die Schaltfläche erkannt wird.

Das nächste Mal möchte ich es mit der Aufnahmefunktion kombinieren, die ich beim letzten Mal gemacht habe. Na dann

Recommended Posts

Umweltfreundliches Scraping mit Bildverarbeitung
[Bildverarbeitung] Posterisierung
Python-Bildverarbeitung
Bildverarbeitung 100 Schläge ①
Scraping mit Python
Bildverarbeitung mit MyHDL
Scraping von Hinatazakas Blog-Bild
Lesen Sie die digitale Bildverarbeitung
Bildsegmentierung mit U-Net
Bildverarbeitung mit Python
Bildverarbeitung mit PIL
Scraping mit Python 3.5 async / await
Bildverarbeitung mit Python (Teil 2)
opencv-python Einführung in die Bildverarbeitung
Bildverarbeitung mit PIL (Pillow)
Versuchen Sie es mit Jupyters Docker-Image
Digitale Bildverarbeitung (räumliche Filterung)
100 Schläge bei der Bildverarbeitung !! (011-020) Frühes Spiel
Scraping mit Python 3.5 Async-Syntax
Bildverarbeitung mit Python (Teil 1)
Vorhersage von Wolkenbildern mit convLSTM
Bildersammlung mit Web Scraping
Web Scraping mit Selenium (Python)
Bildverarbeitung mit Python (3)
Bildverarbeitung mit Python (Pillow)
Bildverarbeitungssammlung in Python
Web Scraping mit AWS Lambda
Implementieren Sie die Umkehrumkehrverarbeitung mit BitBoard
Bildausdehnung und Kontraktionsverarbeitung
Verwenden des Python-Modus in der Verarbeitung
[Python] Bildverarbeitung mit Scicit-Image
Verstehen Sie die Funktion der Faltung am Beispiel der Bildverarbeitung
[Bildverarbeitung] Poo-san ist durch Kantenerkennung mit Python und OpenCV nackt!