Last active
January 4, 2016 18:39
-
-
Save t2psyto/8662173 to your computer and use it in GitHub Desktop.
IEで開いたflashページで、win32apiをたたいてflashのウィンドウハンドラにクリックを送る。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: cp932 -*- | |
import win32gui, win32ui, win32con | |
import time, random | |
import webbrowser | |
## flashplayerのwmodeをwindowにする。→ hwnd が取得できるようになる。 | |
# ref: http://stackoverflow.com/questions/534474/changing-arbitrary-flash-objects-wmode-to-transparent | |
def set_flash_wmode(driver, waitsec=0.2): | |
setwmode = """(function(){ | |
var embed = document.getElementsByTagName('embed'); | |
for(var i = 0; i < embed.length; i++){ | |
embed[i].setAttribute('wmode','window'); | |
} | |
// FF does a "live" array when working directly with elements, | |
// so "els" changes as we add/remove elements; to avoid problems | |
// with indexing, copy to a temporary array | |
var els = document.getElementsByTagName('object'); | |
var obj = []; | |
for(var i = 0; i < els.length; i++){ | |
obj[i] = els[i]; | |
} | |
for(var i = 0; i < obj.length; i++){ | |
var param = document.createElement('param'); | |
param.setAttribute('name','wmode'); | |
param.setAttribute('value','window'); | |
obj[i].appendChild(param); | |
var wrapper = document.createElement('div'); | |
obj[i].parentNode.appendChild(wrapper); | |
if(obj[i].outerHTML){ | |
// IE | |
var html = obj[i].outerHTML; | |
obj[i].parentNode.removeChild(obj[i]); | |
wrapper.innerHTML = html; | |
}else{ | |
// ff/chrome | |
obj[i].parentNode.removeChild(obj[i]); | |
wrapper.appendChild(obj[i]); | |
} | |
} | |
})(); | |
""" | |
driver.execute_script(setwmode) | |
time.sleep(waitsec) | |
def find_webdriver_window(driver, hwnd_ietab): | |
default_window = driver.current_window_handle | |
dict_handles = {elem:elem for elem in driver.window_handles} | |
orig_titles = {} | |
tabset = {} | |
#ウィンドウタイトルが書き換わるまで待つ(チェックする) | |
def wait_titlechanged(driver, dict_titles, timeout=20, wait_sec=0.2): | |
for webdriver_handle,title in dict_titles.items(): | |
driver.switch_to_window(webdriver_handle) | |
for i in range(timeout): | |
if driver.title == title: | |
break #for i を抜ける | |
else: | |
time.sleep(wait_sec) | |
time.sleep(wait_sec) #さらにちょっと待つ | |
return | |
def change_titles(driver, dict_handles): | |
previous_titles = {} | |
for webdriver_handle,title in dict_handles.items(): | |
driver.switch_to_window(webdriver_handle) | |
previous_titles[webdriver_handle] = driver.title | |
#print "webdriver_handle:", webdriver_handle | |
driver.execute_script("""document.title = "%s";var temp = document.title;""" % title) | |
#書き換わったかチェック | |
wait_titlechanged(driver, dict_handles) | |
return previous_titles | |
#window title を webdriver_handle に書き換える | |
print "change window_title to webdriver_handle:" | |
orig_titles = change_titles(driver, dict_handles) | |
# hWnd と webdriver_window_handle のマッピング | |
print "grab hwnd and webdriver_handle:" | |
for local_hwnd in hwnd_ietab: | |
win32gui.SetActiveWindow(local_hwnd) | |
title = win32gui.GetWindowText(local_hwnd)[0:36] | |
#print title | |
tabset[title] = local_hwnd | |
#window title を 元に戻す | |
print "restore wndow_titles:" | |
_dummy = change_titles(driver, orig_titles) | |
driver.switch_to_window(default_window) | |
return tabset | |
def searchChildWindows(currentHwnd, wantedText="",wantedClass="", wantedFunction=""): | |
results = [] | |
childWindows = [] | |
try: | |
win32gui.EnumChildWindows(currentHwnd, | |
_windowEnumerationHandler, | |
childWindows) | |
except win32gui.error: | |
# This seems to mean that the control *cannot* have child windows, | |
# i.e. not a container. | |
return | |
#print "childWindows:", len(childWindows) | |
count = 0 | |
for childHwnd, windowText, windowClass in childWindows: | |
#print count | |
count = count + 1 | |
descendentMatchingHwnds = searchChildWindows(childHwnd, wantedText,wantedClass, wantedFunction) | |
if descendentMatchingHwnds: | |
results += descendentMatchingHwnds | |
if wantedText and \ | |
not _normaliseText(wantedText) in _normaliseText(windowText): | |
continue | |
if wantedClass and \ | |
not windowClass == wantedClass: | |
continue | |
#if selectionFunction and \ | |
# not selectionFunction(childHwnd): | |
# continue | |
#print childHwnd, windowText, windowClass | |
results.append(childHwnd) | |
return results | |
def _windowEnumerationHandler(hwnd, resultList): | |
'''Pass to win32gui.EnumWindows() to generate list of window handle, | |
window text, window class tuples.''' | |
resultList.append((hwnd, | |
win32gui.GetWindowText(hwnd), | |
win32gui.GetClassName(hwnd))) | |
# IEでflashのペイントソフトを開く | |
## builtin webbrowser | |
#ie = webbrowser.get(webbrowser.iexplore) | |
#ie.open("http://www.ippei.org/flash/peint/flashpeint.html") | |
#time.sleep(3) #ロード完了するまでちょっと待つ | |
## selenium webdriver | |
from selenium.webdriver.ie.webdriver import WebDriver | |
driver = WebDriver() | |
driver.get("http://www.ippei.org/flash/peint/flashpeint.html") | |
#driver.get("http://www.yahoo.co.jp") | |
set_flash_wmode(driver) | |
hwnd = win32gui.GetDesktopWindow() | |
hwnd2 = win32gui.FindWindowEx(hwnd, None, "IEFrame", None) | |
#タブウィンドウリストを取得 | |
results = searchChildWindows(hwnd2,wantedClass="TabWindowClass") | |
results = list(set(results)) #重複除去 | |
#FlashPlayerのウィンドウハンドルリストを保存する変数 | |
flashobjs = [] | |
hwnd_flash = None | |
# hwnd と webdriver_handle のマッチング | |
webdriver_hwnds = find_webdriver_window(driver, results) | |
print "webdriver_hwnds:", webdriver_hwnds | |
results_all = results | |
results = [webdriver_hwnds[driver.window_handles[0]]] | |
for local_hwnd in results: | |
print local_hwnd, win32gui.GetClassName(local_hwnd), win32gui.GetWindowText(local_hwnd) | |
#タブウィンドウ毎にFlashPlayerのウィンドウハンドルを取得 | |
results2 = searchChildWindows(local_hwnd,wantedClass='MacromediaFlashPlayerActiveX') | |
results2 = list(set(results2)) #重複除去 | |
print results2 | |
flashobjs.extend(results2) | |
## for DEBUG; ウィンドウハンドルの情報を表示 | |
for local_hwnd2 in results2: | |
print "\t", local_hwnd2, win32gui.GetClassName(local_hwnd2), win32gui.GetWindowText(local_hwnd2), win32gui.GetWindowRect(local_hwnd2) | |
# xy座標をlParamに変換 | |
def MAKELPARAM(point): | |
x, y = point | |
#lParam = (y << 16) | (x & 0xffff) | |
lParam = y << 16 | x | |
return lParam | |
# ウィンドウの座標(point) を 左クリックする | |
def send_click(local_hwnd, point): | |
#print local_hwnd | |
lParam = MAKELPARAM(point) | |
win32gui.SetActiveWindow(local_hwnd) | |
cwnd_paint = win32ui.CreateWindowFromHandle(local_hwnd) | |
#最初に LBUTTONUP がないとマウスクリック反応しなかった | |
cwnd_paint.SendMessage(win32con.WM_LBUTTONUP, 0, lParam) | |
cwnd_paint.SendMessage(win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, lParam) | |
time.sleep(1) #1秒押しっぱなし | |
cwnd_paint.SendMessage(win32con.WM_LBUTTONUP, 0, lParam) | |
# 最初に見つけたFlashObject | |
# fixme: flashobjectを複数開いている場合にはまだ対応できてない。 | |
if len(flashobjs) > 0: | |
hwnd_flash = flashobjs[0] | |
print hwnd_flash | |
#flashobject内の座標(25,130)(「ブラシ」ボタン)を左クリック | |
point = (25,130) | |
send_click(hwnd_flash, point) | |
#flashobject内のランダムな座標を左クリック x10回 | |
for n in range(10): | |
x = random.randint(100, 500) | |
y = random.randint(100, 500) | |
send_click(hwnd_flash, (x,y)) | |
#driver.quit() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
selenium-webdriver でブラウザ制御するようにした。
seleniumのwindow_handlerとwin32apiのhwndを対応付けできるようにした。
iframeなどの深い階層に配置されたflashも見つけるために、whndの取得時にディープな探索をするようにした。
flashのウィンドウモードをwmode=windowに無理やり変更することで、windowlessなflashでwhnd取得できない問題に対処。