Загрузка данных


#NoEnv
#SingleInstance Force
#Persistent
SendMode Input
SetWorkingDir %A_ScriptDir%
SetBatchLines, -1

CoordMode, Mouse, Screen
CoordMode, Pixel, Screen

; ============================================================
; ПОДКЛЮЧЕНИЕ GDI+
; ============================================================
;
; Файл Gdip_All.ahk должен лежать В ТОЙ ЖЕ ПАПКЕ,
; что и этот скрипт.
;
; Например:
;
; Aukcion.ahk
; Gdip_All.ahk
;
; ============================================================

#Include %A_ScriptDir%\Gdip_All.ahk


; ============================================================
;                    НАСТРОЙКИ
; ============================================================


; ============================================================
; 1. TESSERACT OCR
; ============================================================
;
; Здесь указан путь к программе Tesseract.
;
; Если Tesseract установлен стандартно:
;
; C:\Program Files\Tesseract-OCR\tesseract.exe
;
; ============================================================

TesseractPath := "C:\Program Files\Tesseract-OCR\tesseract.exe"


; ============================================================
; ЯЗЫК OCR
; ============================================================
;
; rus+eng = русский + английский
;
; Если тебе нужен только русский:
;
; OCRLanguage := "rus"
;
; ============================================================

OCRLanguage := "rus+eng"


; ============================================================
; 2. МАКСИМАЛЬНАЯ ЦЕНА
; ============================================================
;
; Скрипт будет выбирать цены НИЖЕ этого значения.
;
; 50000 = 50 000
;
; ============================================================

MaxPrice := 50000


; ============================================================
; 3. ПОЛЕ ПОИСКА
; ============================================================
;
; Координаты места, куда вводится название товара.
;
; X = положение по горизонтали
; Y = положение по вертикали
;
; ============================================================

InputX := 500
InputY := 300


; ============================================================
; ТЕКСТ, КОТОРЫЙ НУЖНО ИСКАТЬ
; ============================================================

SearchText := "НУЖНЫЙ ТЕКСТ"


; ============================================================
; 4. КНОПКА ОБНОВЛЕНИЯ СПИСКА
; ============================================================
;
; После ввода текста скрипт нажимает сюда.
;
; В дальнейшем это будет использоваться
; для обновления списка.
;
; ============================================================

RefreshX := 700
RefreshY := 300


; ============================================================
; 5. ОБЛАСТЬ OCR
; ============================================================
;
; ЭТО ОДИН ИЗ САМЫХ ВАЖНЫХ ПУНКТОВ.
;
; Скрипт будет анализировать ТОЛЬКО эту область экрана.
;
; OCRX / OCRY
; = левый верхний угол области.
;
; OCRWidth
; = ширина области.
;
; OCRHeight
; = высота области.
;
; Пример:
;
; OCRX := 400
; OCRY := 400
; OCRWidth := 700
; OCRHeight := 500
;
; ============================================================

OCRX := 400
OCRY := 400

OCRWidth := 700
OCRHeight := 500


; ============================================================
; 6. КНОПКА ПОДТВЕРЖДЕНИЯ
; ============================================================
;
; После нахождения подходящего варианта:
;
; 1. клик по найденной цене;
; 2. ожидание;
; 3. клик сюда.
;
; ============================================================

ConfirmX := 1000
ConfirmY := 800


; ============================================================
; 7. ПОЛЗУНОК СПИСКА
; ============================================================
;
; Координаты самого ползунка.
;
; ============================================================

ScrollBarX := 1200
ScrollBarY := 500


; ============================================================
; НА СКОЛЬКО ПИКСЕЛЕЙ ОПУСКАТЬ ПОЛЗУНОК
; ============================================================
;
; Например:
;
; 150 = опускать на 150 пикселей.
;
; ============================================================

ScrollPixels := 150


; ============================================================
; СКОЛЬКО РАЗ ПРОКРУЧИВАТЬ ОДНУ СТРАНИЦУ
; ============================================================
;
; Например:
;
; 5 шагов × 150 пикселей.
;
; После 5 шагов скрипт считает страницу законченной.
;
; ============================================================

MaxScrollSteps := 5


; ============================================================
; 8. КНОПКА ПЕРЕХОДА НА 2-Ю СТРАНИЦУ
; ============================================================
;
; ============================================================

Page2X := 1100
Page2Y := 850


; ============================================================
; ЗАДЕРЖКИ
; ============================================================
;
; Все значения указаны в миллисекундах.
;
; 1000 = 1 секунда
; 500  = 0.5 секунды
; 300  = 0.3 секунды
;
; Эти значения можно менять.
;
; ============================================================


; После движения мыши
MoveDelay := 80


; После обычного клика
ClickDelay := 250


; После обновления списка
RefreshDelay := 600


; После ввода текста
InputDelay := 250


; После прокрутки
ScrollDelay := 300


; После перехода на страницу
PageDelay := 600


; После выбора найденного товара
SelectDelay := 350


; ============================================================
; СЛУЖЕБНЫЕ ПЕРЕМЕННЫЕ
; ============================================================

ScriptRunning := false

CurrentPage := 1

CurrentScrollStep := 0


; ============================================================
; F3 — ЗАПУСК
; ============================================================

F3::

    if (ScriptRunning)
        return


    ScriptRunning := true

    CurrentPage := 1
    CurrentScrollStep := 0


    ToolTip, СКРИПТ ЗАПУЩЕН

    Sleep, 700

    ToolTip


    ; Начинаем с первого пункта
    SetTimer, StartSearch, -10

return


; ============================================================
; F6 — ОСТАНОВКА
; ============================================================

F6::

    ScriptRunning := false


    ToolTip, СКРИПТ ОСТАНОВЛЕН

    Sleep, 700

    ToolTip

return



; ============================================================
; НАЧАЛО РАБОТЫ
; ============================================================
;
; Здесь выполняются пункты:
;
; 1. Ввод текста
; 2. Обновление списка
;
; ============================================================

StartSearch:

    if (!ScriptRunning)
        return


; ============================================================
; ПУНКТ 1
; ВВОД НАЗВАНИЯ ТОВАРА
; ============================================================

    MouseMove, %InputX%, %InputY%, 0

    Sleep, %MoveDelay%

    Click

    Sleep, %ClickDelay%


    ; Выделяем старый текст
    SendInput, ^a

    Sleep, 100


    ; Вводим новый текст
    SendInput, %SearchText%

    Sleep, %InputDelay%


; ============================================================
; ПУНКТ 2
; ОБНОВЛЕНИЕ СПИСКА
; ============================================================

    MouseMove, %RefreshX%, %RefreshY%, 0

    Sleep, %MoveDelay%

    Click

    Sleep, %RefreshDelay%


; ============================================================
; Начинаем поиск с верхней части первой страницы
; ============================================================

    CurrentPage := 1
    CurrentScrollStep := 0

    Goto, SearchPage1

return



; ============================================================
; ПОИСК НА ПЕРВОЙ СТРАНИЦЕ
; ============================================================

SearchPage1:

    if (!ScriptRunning)
        return


; ============================================================
; ПУНКТ 3
; OCR АНАЛИЗ ОБЛАСТИ
; ============================================================

    OCRResult := OCR_GetPrices(OCRX, OCRY, OCRWidth, OCRHeight, TesseractPath, OCRLanguage, MaxPrice)


; ============================================================
; НАЙДЕНА ПОДХОДЯЩАЯ ЦЕНА
; ============================================================

    if (OCRResult != "")
    {

        StringSplit, Found, OCRResult, |


        FoundX := Found1
        FoundY := Found2
        FoundPrice := Found3


        ToolTip, НАЙДЕНА ЦЕНА: %FoundPrice%

        Sleep, 500

        ToolTip


; ------------------------------------------------------------
; КЛИК ПО НАЙДЕННОМУ ВАРИАНТУ
; ------------------------------------------------------------

        MouseMove, %FoundX%, %FoundY%, 0

        Sleep, %MoveDelay%

        Click

        Sleep, %SelectDelay%


; ------------------------------------------------------------
; ПОДТВЕРЖДЕНИЕ
; ------------------------------------------------------------

        MouseMove, %ConfirmX%, %ConfirmY%, 0

        Sleep, %MoveDelay%

        Click

        Sleep, %RefreshDelay%


; ------------------------------------------------------------
; ПОСЛЕ ПОКУПКИ:
;
; НЕ ВВОДИМ ТЕКСТ ЗАНОВО.
;
; СРАЗУ ПЕРЕХОДИМ К ПУНКТУ 2.
; ------------------------------------------------------------

        CurrentPage := 1
        CurrentScrollStep := 0

        SetTimer, RefreshSearch, -10

        return
    }


; ============================================================
; ПОДХОДЯЩЕЙ ЦЕНЫ НЕТ
; ============================================================

    CurrentScrollStep++


; ============================================================
; ПУНКТ 4
; ПРОКРУТКА ВНИЗ
; ============================================================

    if (CurrentScrollStep <= MaxScrollSteps)
    {

        ScrollListDown()

        Sleep, %ScrollDelay%

        Goto, SearchPage1
    }


; ============================================================
; ПУНКТ 5
; ПЕРЕХОД НА 2-Ю СТРАНИЦУ
; ============================================================

    CurrentPage := 2

    CurrentScrollStep := 0


    MouseMove, %Page2X%, %Page2Y%, 0

    Sleep, %MoveDelay%

    Click

    Sleep, %PageDelay%


    ; Переходим к поиску на второй странице

    Goto, SearchPage2

return



; ============================================================
; ПОИСК НА ВТОРОЙ СТРАНИЦЕ
; ============================================================

SearchPage2:

    if (!ScriptRunning)
        return


; ============================================================
; OCR
; ============================================================

    OCRResult := OCR_GetPrices(OCRX, OCRY, OCRWidth, OCRHeight, TesseractPath, OCRLanguage, MaxPrice)


; ============================================================
; НАЙДЕНА ПОДХОДЯЩАЯ ЦЕНА
; ============================================================

    if (OCRResult != "")
    {

        StringSplit, Found, OCRResult, |


        FoundX := Found1
        FoundY := Found2
        FoundPrice := Found3


        ToolTip, НАЙДЕНА ЦЕНА: %FoundPrice%

        Sleep, 500

        ToolTip


; ------------------------------------------------------------
; КЛИК ПО ВАРИАНТУ
; ------------------------------------------------------------

        MouseMove, %FoundX%, %FoundY%, 0

        Sleep, %MoveDelay%

        Click

        Sleep, %SelectDelay%


; ------------------------------------------------------------
; КНОПКА ПОДТВЕРЖДЕНИЯ
; ------------------------------------------------------------

        MouseMove, %ConfirmX%, %ConfirmY%, 0

        Sleep, %MoveDelay%

        Click

        Sleep, %RefreshDelay%


; ------------------------------------------------------------
; ПОСЛЕ УСПЕШНОГО ВЫБОРА:
;
; ВОЗВРАЩАЕМСЯ К ПУНКТУ 2
; ------------------------------------------------------------

        CurrentPage := 1
        CurrentScrollStep := 0

        SetTimer, RefreshSearch, -10

        return
    }


; ============================================================
; НА ВТОРОЙ СТРАНИЦЕ НИЧЕГО НЕ НАЙДЕНО
; ============================================================

    CurrentScrollStep++


; ============================================================
; ПРОКРУТКА ВТОРОЙ СТРАНИЦЫ
; ============================================================

    if (CurrentScrollStep <= MaxScrollSteps)
    {

        ScrollListDown()

        Sleep, %ScrollDelay%

        Goto, SearchPage2
    }


; ============================================================
; ВТОРАЯ СТРАНИЦА ЗАКОНЧИЛАСЬ
;
; НИЧЕГО НЕ НАШЛИ.
;
; ВОЗВРАЩАЕМСЯ К ПУНКТУ 2.
; ============================================================

    CurrentPage := 1

    CurrentScrollStep := 0


    SetTimer, RefreshSearch, -10

return



; ============================================================
; ПУНКТ 2 ПОСЛЕ УСПЕШНОГО ВЫБОРА
; ============================================================
;
; Здесь текст уже введён.
;
; Поэтому заново вводить его НЕ НУЖНО.
;
; Просто обновляем список.
;
; ============================================================

RefreshSearch:

    if (!ScriptRunning)
        return


    MouseMove, %RefreshX%, %RefreshY%, 0

    Sleep, %MoveDelay%

    Click

    Sleep, %RefreshDelay%


    CurrentPage := 1

    CurrentScrollStep := 0


    Goto, SearchPage1

return



; ============================================================
; ФУНКЦИЯ ПРОКРУТКИ
; ============================================================

ScrollListDown()
{

    global ScrollBarX
    global ScrollBarY
    global ScrollPixels
    global MoveDelay


; ------------------------------------------------------------
; Наводимся на ползунок
; ------------------------------------------------------------

    MouseMove, %ScrollBarX%, %ScrollBarY%, 0

    Sleep, %MoveDelay%


; ------------------------------------------------------------
; Зажимаем левую кнопку
; ------------------------------------------------------------

    Click, Down

    Sleep, 100


; ------------------------------------------------------------
; Рассчитываем новую позицию
; ------------------------------------------------------------

    NewScrollY := ScrollBarY + ScrollPixels


; ------------------------------------------------------------
; Опускаем ползунок
; ------------------------------------------------------------

    MouseMove, %ScrollBarX%, %NewScrollY%, 300


; ------------------------------------------------------------
; Отпускаем кнопку
; ------------------------------------------------------------

    Click, Up
}



; ============================================================
; OCR_GetPrices
; ============================================================
;
; Делает скриншот области OCR.
;
; Передаёт его Tesseract.
;
; Получает TSV.
;
; Ищет число меньше MaxPrice.
;
; Возвращает:
;
; X|Y|PRICE
;
; ============================================================

OCR_GetPrices(X, Y, Width, Height, TesseractPath, Language, MaxPrice)
{

; ------------------------------------------------------------
; Временные файлы
; ------------------------------------------------------------

    TempImage := A_Temp "\ahk_auction_screen.png"

    TempBase := A_Temp "\ahk_auction_ocr"

    TSVFile := TempBase ".tsv"


; ------------------------------------------------------------
; Удаляем старый результат Tesseract
; ------------------------------------------------------------

    if (FileExist(TSVFile))
        FileDelete, %TSVFile%


; ------------------------------------------------------------
; Запускаем GDI+
; ------------------------------------------------------------

    pToken := Gdip_Startup()

    if (!pToken)
    {

        ToolTip, ОШИБКА: GDI+ НЕ ЗАПУСТИЛСЯ

        Sleep, 1000

        ToolTip

        return ""
    }


; ------------------------------------------------------------
; Создаём скриншот нужной области
; ------------------------------------------------------------

    ScreenArea := X "|" Y "|" Width "|" Height

    pBitmap := Gdip_BitmapFromScreen(ScreenArea)


    if (!pBitmap)
    {

        Gdip_Shutdown(pToken)

        ToolTip, ОШИБКА: НЕ УДАЛОСЬ СДЕЛАТЬ СКРИНШОТ

        Sleep, 1000

        ToolTip

        return ""
    }


; ------------------------------------------------------------
; Сохраняем скриншот
; ------------------------------------------------------------

    SaveResult := Gdip_SaveBitmapToFile(pBitmap, TempImage)


; ------------------------------------------------------------
; Освобождаем GDI+
; ------------------------------------------------------------

    Gdip_DisposeImage(pBitmap)

    Gdip_Shutdown(pToken)


    if (SaveResult != 0)
        return ""


    if (!FileExist(TempImage))
        return ""


; ============================================================
; ЗАПУСК TESSERACT
; ============================================================

    RunWait, "%TesseractPath%" "%TempImage%" "%TempBase%" -l %Language% --psm 6 tsv,, Hide


; ------------------------------------------------------------
; Проверяем TSV
; ------------------------------------------------------------

    if (!FileExist(TSVFile))
        return ""


; ------------------------------------------------------------
; Читаем результат
; ------------------------------------------------------------

    FileRead, TSV, %TSVFile%

    if (ErrorLevel)
        return ""


; ============================================================
; ОБРАБОТКА OCR
; ============================================================

    Loop, Parse, TSV, `n, `r
    {

        Line := A_LoopField


; ------------------------------------------------------------
; Пропускаем пустые строки
; ------------------------------------------------------------

        if (Line = "")
            continue


; ------------------------------------------------------------
; Пропускаем заголовок TSV
; ------------------------------------------------------------

        if (InStr(Line, "level" . A_Tab . "page_num"))
            continue


; ------------------------------------------------------------
; Разбираем строку TSV
; ------------------------------------------------------------

        StringSplit, Col, Line, %A_Tab%


; ------------------------------------------------------------
; Col6 = X
; Col7 = Y
; Col8 = Width
; Col9 = Height
; Col12 = текст
; ------------------------------------------------------------

        if (Col12 = "")
            continue


        Text := Trim(Col12)


        if (Text = "")
            continue


; ============================================================
; ОЧИСТКА ЦЕНЫ
; ============================================================

        CleanPrice := Text


        CleanPrice := StrReplace(CleanPrice, "₽", "")

        CleanPrice := StrReplace(CleanPrice, "$", "")

        CleanPrice := StrReplace(CleanPrice, "€", "")


        CleanPrice := StrReplace(CleanPrice, " ", "")

        CleanPrice := StrReplace(CleanPrice, ".", "")

        CleanPrice := StrReplace(CleanPrice, ",", "")


; ------------------------------------------------------------
; Оставляем только цифры
; ------------------------------------------------------------

        CleanPrice := RegExReplace(CleanPrice, "[^\d]")


        if (CleanPrice = "")
            continue


; ------------------------------------------------------------
; Переводим в число
; ------------------------------------------------------------

        Price := CleanPrice + 0


; ============================================================
; ПРОВЕРКА ЦЕНЫ
; ============================================================

        if (Price > 0 && Price < MaxPrice)
        {


; ------------------------------------------------------------
; Вычисляем координаты центра найденного текста
; ------------------------------------------------------------

            FoundX := X + Col6 + (Col8 / 2)

            FoundY := Y + Col7 + (Col9 / 2)


; ------------------------------------------------------------
; Возвращаем:
;
; X|Y|PRICE
; ------------------------------------------------------------

            return FoundX "|" FoundY "|" Price
        }
    }


; ============================================================
; НИЧЕГО НЕ НАЙДЕНО
; ============================================================

    return ""
}