Загрузка данных
#NoEnv
#SingleInstance Force
#Persistent
SendMode Input
SetWorkingDir, %A_ScriptDir%
SetBatchLines, -1
CoordMode, Mouse, Screen
CoordMode, Pixel, Screen
; ============================================================
; GDI+
; ============================================================
;
; GDI+ оставляем подключённым.
; В этой версии GDI+ НЕ используется для создания скриншота,
; потому что Windows BitBlt у тебя работает надёжнее.
;
; ============================================================
#Include %A_ScriptDir%\Gdip_All.ahk
; ============================================================
; TESSERACT OCR
; ============================================================
; Путь к Tesseract.
; Если у тебя он установлен в другом месте — измени эту строку.
TesseractPath := "C:\Program Files\Tesseract-OCR\tesseract.exe"
; Языки OCR.
;
; rus = русский
; eng = английский
;
OCRLanguage := "rus+eng"
; ============================================================
; НАСТРОЙКИ ЦЕНЫ
; ============================================================
; Максимальная допустимая цена.
;
; Скрипт будет принимать только цены:
;
; МЕНЬШЕ 50000
;
MaxPrice := 50000
; ============================================================
; 1. ПОЛЕ ПОИСКА
; ============================================================
; Координаты поля, куда вводится текст.
InputX := 500
InputY := 300
; Что именно вводить.
SearchText := "НУЖНЫЙ ТЕКСТ"
; ============================================================
; 2. КНОПКА ОБНОВЛЕНИЯ
; ============================================================
RefreshX := 700
RefreshY := 300
; ============================================================
; 3. ОБЛАСТЬ OCR
; ============================================================
;
; Именно эта область экрана будет передаваться Tesseract.
;
; X/Y = левый верхний угол.
;
; Width/Height = размер области.
;
; Пример:
;
; X = 400
; Y = 400
; Width = 700
; Height = 500
;
; Значит будет анализироваться область:
;
; от 400 до 1100 по X
; от 400 до 900 по Y
;
; ============================================================
OCRX := 400
OCRY := 400
OCRWidth := 700
OCRHeight := 500
; ============================================================
; 4. КНОПКА ПОДТВЕРЖДЕНИЯ
; ============================================================
ConfirmX := 1000
ConfirmY := 800
; ============================================================
; 5. ПОЛЗУНОК
; ============================================================
ScrollBarX := 1200
ScrollBarY := 500
; На сколько пикселей опускать ползунок.
ScrollPixels := 150
; Сколько раз прокручивать одну страницу.
MaxScrollSteps := 5
; ============================================================
; 6. ВТОРАЯ СТРАНИЦА
; ============================================================
Page2X := 1100
Page2Y := 850
; ============================================================
; ЗАДЕРЖКИ
; ============================================================
MoveDelay := 80
ClickDelay := 250
RefreshDelay := 600
InputDelay := 250
ScrollDelay := 350
PageDelay := 600
SelectDelay := 300
; ============================================================
; СЛУЖЕБНЫЕ ПЕРЕМЕННЫЕ
; ============================================================
ScriptRunning := false
CurrentPage := 1
CurrentScrollStep := 0
; ============================================================
; F3 — ЗАПУСК
; ============================================================
F3::
if (ScriptRunning)
return
ScriptRunning := true
CurrentPage := 1
CurrentScrollStep := 0
ToolTip, АУКЦИОН: ЗАПУЩЕН
Sleep, 600
ToolTip
SetTimer, MainLoop, -10
return
; ============================================================
; F6 — ОСТАНОВКА
; ============================================================
F6::
ScriptRunning := false
ToolTip, АУКЦИОН: ОСТАНОВЛЕН
Sleep, 600
ToolTip
return
; ============================================================
; ОСНОВНОЙ ЦИКЛ
; ============================================================
MainLoop:
if (!ScriptRunning)
return
; ============================================================
; ПУНКТ 1
; ВВОДИМ НАЗВАНИЕ ТОВАРА
; ============================================================
MouseMove, %InputX%, %InputY%, 0
Sleep, %MoveDelay%
Click
Sleep, %ClickDelay%
Send, ^a
Sleep, 80
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
; ============================================================
; 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%
; Начинаем новый цикл.
CurrentPage := 1
CurrentScrollStep := 0
SetTimer, MainLoop, -10
return
}
; ============================================================
; ЦЕНА НЕ НАЙДЕНА
; ============================================================
CurrentScrollStep++
if (CurrentScrollStep <= MaxScrollSteps)
{
ScrollListDown()
Sleep, %ScrollDelay%
Goto, SearchPage1
}
; ============================================================
; КОНЕЦ ПЕРВОЙ СТРАНИЦЫ
; ПЕРЕХОДИМ НА ВТОРУЮ
; ============================================================
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%
; Новый цикл.
CurrentPage := 1
CurrentScrollStep := 0
SetTimer, MainLoop, -10
return
}
; ============================================================
; ЦЕНА НЕ НАЙДЕНА
; ============================================================
CurrentScrollStep++
if (CurrentScrollStep <= MaxScrollSteps)
{
ScrollListDown()
Sleep, %ScrollDelay%
Goto, SearchPage2
}
; ============================================================
; ВТОРАЯ СТРАНИЦА ЗАКОНЧИЛАСЬ
; ============================================================
;
; Ничего не нашли.
;
; Возвращаемся к обновлению списка.
;
; ============================================================
CurrentPage := 1
CurrentScrollStep := 0
MouseMove, %RefreshX%, %RefreshY%, 0
Sleep, %MoveDelay%
Click
Sleep, %RefreshDelay%
Goto, SearchPage1
return
; ============================================================
; ФУНКЦИЯ ПРОКРУТКИ
; ============================================================
ScrollListDown()
{
global ScrollBarX
global ScrollBarY
global ScrollPixels
global MoveDelay
MouseMove, %ScrollBarX%, %ScrollBarY%, 0
Sleep, %MoveDelay%
; Зажимаем левую кнопку.
Click, Down
Sleep, 80
; Перемещаем ползунок.
NewScrollY := ScrollBarY + ScrollPixels
MouseMove, %ScrollBarX%, %NewScrollY%, 300
; Отпускаем кнопку.
Click, Up
}
; ============================================================
; OCR_GetPrices
; ============================================================
;
; 1. Делает скриншот области через BitBlt.
;
; 2. Сохраняет его в BMP.
;
; 3. Передаёт BMP Tesseract.
;
; 4. Получает TSV.
;
; 5. Ищет числовое значение меньше MaxPrice.
;
; 6. Возвращает:
;
; X|Y|PRICE
;
; ============================================================
OCR_GetPrices(X, Y, Width, Height, TesseractPath, Language, MaxPrice)
{
global
; ========================================================
; Временные файлы
; ========================================================
TempImage := A_Temp "\auction_ocr.bmp"
TempBase := A_Temp "\auction_ocr_result"
TSVFile := TempBase ".tsv"
; Удаляем старые файлы.
FileDelete, %TempImage%
FileDelete, %TSVFile%
; ========================================================
; ДЕЛАЕМ BMP СКРИНШОТ
; ========================================================
if (!CaptureScreenToBMP(X, Y, Width, Height, TempImage))
{
ToolTip, ОШИБКА: НЕ УДАЛОСЬ СДЕЛАТЬ СКРИНШОТ
Sleep, 1000
ToolTip
return ""
}
; ========================================================
; ПРОВЕРЯЕМ TESSERACT
; ========================================================
if (!FileExist(TesseractPath))
{
MsgBox, 16, Ошибка Tesseract, Tesseract.exe не найден.`n`nПуть:`n%TesseractPath%
return ""
}
; ========================================================
; ЗАПУСК TESSERACT
; ========================================================
;
; BMP → TSV
;
; TSV содержит:
;
; текст
; X
; Y
; ширину
; высоту
;
; ========================================================
RunWait, "%TesseractPath%" "%TempImage%" "%TempBase%" -l %Language% --psm 6 tsv,, Hide
; ========================================================
; ПРОВЕРЯЕМ TSV
; ========================================================
if (!FileExist(TSVFile))
return ""
FileRead, TSV, %TSVFile%
if (ErrorLevel)
return ""
; ========================================================
; ОБРАБАТЫВАЕМ TSV
; ========================================================
Loop, Parse, TSV, `n, `r
{
Line := A_LoopField
if (Line = "")
continue
; Пропускаем заголовок.
if (InStr(Line, "level" . A_Tab . "page_num"))
continue
; Разделяем TSV.
StringSplit, Col, Line, %A_Tab%
; В Tesseract TSV:
; Col6 = X
; Col7 = Y
; Col8 = Width
; Col9 = Height
; Col12 = Text
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)
continue
if (Price >= MaxPrice)
continue
; ====================================================
; НАШЛИ ПОДХОДЯЩУЮ ЦЕНУ
; ====================================================
FoundX := X + Col6 + (Col8 / 2)
FoundY := Y + Col7 + (Col9 / 2)
return FoundX "|" FoundY "|" Price
}
return ""
}
; ============================================================
; CaptureScreenToBMP
; ============================================================
;
; Делает скриншот через Windows BitBlt.
;
; Это тот способ, который мы уже проверили:
;
; BitBlt → HBITMAP → BMP
;
; GDI+ здесь НЕ используется.
;
; ============================================================
CaptureScreenToBMP(X, Y, Width, Height, FilePath)
{
; ========================================================
; Получаем DC экрана
; ========================================================
hdcScreen := DllCall("GetDC", "Ptr", 0, "Ptr")
if (!hdcScreen)
return false
; ========================================================
; Создаём Memory DC
; ========================================================
hdcMem := DllCall("gdi32\CreateCompatibleDC", "Ptr", hdcScreen, "Ptr")
if (!hdcMem)
{
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hdcScreen)
return false
}
; ========================================================
; Создаём Bitmap
; ========================================================
hBitmap := DllCall("gdi32\CreateCompatibleBitmap", "Ptr", hdcScreen, "Int", Width, "Int", Height, "Ptr")
if (!hBitmap)
{
DllCall("gdi32\DeleteDC", "Ptr", hdcMem)
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hdcScreen)
return false
}
; ========================================================
; Выбираем Bitmap
; ========================================================
hOld := DllCall("gdi32\SelectObject", "Ptr", hdcMem, "Ptr", hBitmap, "Ptr")
; ========================================================
; Делаем захват
; ========================================================
Result := DllCall("gdi32\BitBlt", "Ptr", hdcMem, "Int", 0, "Int", 0, "Int", Width, "Int", Height, "Ptr", hdcScreen, "Int", X, "Int", Y, "UInt", 0x00CC0020)
if (!Result)
{
DllCall("gdi32\SelectObject", "Ptr", hdcMem, "Ptr", hOld)
DllCall("gdi32\DeleteObject", "Ptr", hBitmap)
DllCall("gdi32\DeleteDC", "Ptr", hdcMem)
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hdcScreen)
return false
}
; ========================================================
; Готовим BITMAPINFO
; ========================================================
VarSetCapacity(BitmapInfo, 40, 0)
NumPut(40, BitmapInfo, 0, "UInt")
NumPut(Width, BitmapInfo, 4, "Int")
NumPut(Height, BitmapInfo, 8, "Int")
NumPut(1, BitmapInfo, 12, "UShort")
NumPut(32, BitmapInfo, 14, "UShort")
NumPut(0, BitmapInfo, 16, "UInt")
ImageSize := Width * Height * 4
NumPut(ImageSize, BitmapInfo, 20, "UInt")
; ========================================================
; Выделяем память под пиксели
; ========================================================
VarSetCapacity(Pixels, ImageSize, 0)
; ========================================================
; Возвращаем старый Bitmap
; ========================================================
DllCall("gdi32\SelectObject", "Ptr", hdcMem, "Ptr", hOld)
; ========================================================
; Получаем пиксели
; ========================================================
Result := DllCall("gdi32\GetDIBits", "Ptr", hdcScreen, "Ptr", hBitmap, "UInt", 0, "UInt", Height, "Ptr", &Pixels, "Ptr", &BitmapInfo, "UInt", 0)
if (!Result)
{
DllCall("gdi32\DeleteObject", "Ptr", hBitmap)
DllCall("gdi32\DeleteDC", "Ptr", hdcMem)
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hdcScreen)
return false
}
; ========================================================
; Освобождаем Windows resources
; ========================================================
DllCall("gdi32\DeleteObject", "Ptr", hBitmap)
DllCall("gdi32\DeleteDC", "Ptr", hdcMem)
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hdcScreen)
; ========================================================
; BMP HEADER
; ========================================================
FileSize := 54 + ImageSize
VarSetCapacity(FileHeader, 14, 0)
NumPut(0x4D42, FileHeader, 0, "UShort")
NumPut(FileSize, FileHeader, 2, "UInt")
NumPut(0, FileHeader, 6, "UShort")
NumPut(0, FileHeader, 8, "UShort")
NumPut(54, FileHeader, 10, "UInt")
; ========================================================
; СОЗДАЁМ BMP
; ========================================================
FileDelete, %FilePath%
File := FileOpen(FilePath, "w")
if (!IsObject(File))
return false
File.RawWrite(FileHeader, 14)
File.RawWrite(BitmapInfo, 40)
File.RawWrite(Pixels, ImageSize)
File.Close()
; ========================================================
; ПРОВЕРЯЕМ
; ========================================================
if (!FileExist(FilePath))
return false
FileGetSize, CheckSize, %FilePath%
if (CheckSize <= 54)
return false
return true
}