Skip to content

Instantly share code, notes, and snippets.

@t2psyto
Last active January 4, 2016 18:39
Show Gist options
  • Save t2psyto/8662173 to your computer and use it in GitHub Desktop.
Save t2psyto/8662173 to your computer and use it in GitHub Desktop.
IEで開いたflashページで、win32apiをたたいてflashのウィンドウハンドラにクリックを送る。
# -*- 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()
@t2psyto
Copy link
Author

t2psyto commented Jan 28, 2014

上記の問題点
javascriptで動的にflashをDOMに追加するタイプのページに対応できない。=>searchChildWindows()ではひっぱってこれない。
flashが複数見つかった場合に区別をつける方法がない。

@t2psyto
Copy link
Author

t2psyto commented Jan 30, 2014

selenium-webdriver でブラウザ制御するようにした。
seleniumのwindow_handlerとwin32apiのhwndを対応付けできるようにした。

iframeなどの深い階層に配置されたflashも見つけるために、whndの取得時にディープな探索をするようにした。

flashのウィンドウモードをwmode=windowに無理やり変更することで、windowlessなflashでwhnd取得できない問題に対処。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment