【python】最近インストールしたモジュールリスト

32bitでpython環境を作り直してみます。python3.7(32bit)です。

(1) pip + virturalenv
qiita.com
python get-pip.py
pip install virtualenv

(2) comtypes + MSHTML
qiita.com
pip install comtypes

from comtypes.client import GetModule

GetModule('mshtml.tlb')

ここにMSTHML.pyが入っていることを確認
\Lib\site-packages\comtypes\gen
※理由は分からないけど、anacondaだとうまく取得できない。

(3) wxPython
qiita.com

pip install wxPython

(4) win32gui
win32guiを入れますが、"pip install win32gui"はダメだそうです。
Python - win32guiをインストールするため、pip install win32guiを行うと、エラーが出て止まる。(python setup.py egg_info" failed with error)|teratail

このリンク先を参考に・・・↓↓↓
qiita.com

ここからダウンロードしましょう。↓↓↓
github.com
をダウンロードしました。

普通にインストールすると、多分、違うところに入っちゃうので、
virtualenvの中で、こんな感じで書いてインストールします。

easy_install pywin32-223.win32-py3.7.exe

ちなみに、最新版の224は上手くインストールできなかったので、223を使いました。

pywin32で使えるモジュールは、ここにまとまっているようです。
http://timgolden.me.uk/pywin32-docs/win32_modules.html

(5) pyinstaller
kconcon3.hatenablog.com

pip install pyinstaller

exeにまとめるときは、次のように書きます。

pyinstaller --onefile --windowed your_python_file.py 

【python】URLチェッカー

開いている全てのIEタブのURLをIHTMLDocument2を使ってチェックします。
urlChecker_v0.0.1.0.exe

### iedetection.py ###
__author__ = "w.y"
__version__ = "0.0.1.0"

from win32gui import GetClassName,EnumChildWindows,FindWindow
from comtypes.gen.MSHTML import IHTMLWindow2,IHTMLDocument2,IHTMLDocument3,IHTMLElement,IHTMLInputElement,IHTMLFrameElement3,IDispatch
from ctypes import windll,c_ulong,byref,POINTER
from time import sleep

class clsIETabs(object):

	lsHandle = []
	lsTitle = []
	lsUrl = []
	pDoc2 = POINTER(IHTMLDocument2)()

	
	def __init__(self) : 
		self.lsHandle.clear()
		self.lsTitle.clear()
		self.lsUrl.clear()

	def setHandle(self, value) :
		self.lsHandle.append(value)
		return True

	def setTitle(self, value) :
		self.lsTitle.append(value)
		return True

	def setUrl(self, value) :
		self.lsUrl.append(value)
		return True

	def resetIETabs(self) :
		self.lsHandle.clear()
		self.lsTitle.clear()
		self.lsUrl.clear()
		return True

	def getDoc2FromHandle(self,hWnd) :
		lRes2 = c_ulong(0)
		pLRes2 = byref(lRes2)
		uMsg = windll.user32.RegisterWindowMessageW(u'WM_HTML_GETOBJECT')
		windll.user32.SendMessageTimeoutW(hWnd, uMsg, 0, 0,2, 1000, pLRes2) # 2 == SMTO_ABORTIFHUNG 
		windll.oleacc.ObjectFromLresult(lRes2, IHTMLDocument2._iid_, 0, byref(self.pDoc2))
		return self.pDoc2

	def getDoc3FromHandle(self,hWnd) :
		lRes3 = c_ulong(0)
		pLRes3 = byref(lRes3)
		uMsg = windll.user32.RegisterWindowMessageW(u'WM_HTML_GETOBJECT')
		windll.user32.SendMessageTimeoutW(hWnd, uMsg, 0, 0,2, 1000, pLRes3) # 2 == SMTO_ABORTIFHUNG 
		windll.oleacc.ObjectFromLresult(lRes3, IHTMLDocument3._iid_, 0, byref(self.pDoc3))
		return self.pDoc3


	def __checkIETab(self,hWnd) :
		if (GetClassName(hWnd) == 'Internet Explorer_Server'):
			#print(str(hWnd)+' : '+GetClassName(hWnd)+' : '+SGetWindowText(hWnd))
			self.setHandle(hWnd);

	def iedetectstub(self) :
		return 'OK'

	def iedetect(self) :
		#初期化:IEタブのクラスを生成、無限ループフラグをセット
		user32 = windll.user32
		strResult = ''
		#無限ループIEタブを監視
		#古いIEタブリストの削除
		self.resetIETabs()
		
		#IEタブリスト(ウインドウハンドル)の取得
		EnumChildWindows(FindWindow(u'IEFrame',None),lambda hWnd, _: self.__checkIETab(hWnd), None)
		#IEタブリスト(タイトルとUrl)の取得
		for hWnd in self.lsHandle:
			try : 
				self.getDoc2FromHandle(hWnd)
				strResult=strResult+IETabs.pDoc2.title+' ; '+IETabs.pDoc2.url+'\n\n'
			except :
				pass
		return strResult

if __name__ == '__main__':
	IETabs = clsIETabs()
	windll.user32.MessageBoxW(None, IETabs.iedetect(), 'URL Checker', 0x00000040)

【python】Salesforceのurlから対象画面か否か判定する

Salesforce Classicの特定のタスたむオブジェクトの編集 及び 新規画面のみを対象にしたい場合です。

def matchPage(alRegexUrl,strTargetUrl):#一致判定
	flRes = True
	for strRegexUrl in alRegexUrl :
		if not(strTargetUrl.find(strRegexUrl) > -1) :
			flRes = False
	return flRes

def myTest():
	strRegexUrl = ['https://ap.salesforce.com/800','retURL']

	# カスタムオブジェクトの編集画面
	strUrl01 = 'https://ap.salesforce.com/80010000000CRTS/e?retURL=%2F80010000000CRTS&_CONFIRMATIONTOKEN=VmpFPSxNakF4T0MweE1TMHhORlF3T0RvMU16b3dNUzQyTmpCYSxzaTZVMUEzZ19fRGFBUDZSaDRVMXJpLE9EVXhZV0Zo&common.udd.actions.ActionsUtilORIG_URI=%2F80010000000CRTS%2Fe'
	print(matchPage(strRegexUrl,strUrl01))

	# カスタムオブジェクトの新規画面
	strUrl02 = 'https://ap.salesforce.com/800/e?retURL=%2F800%2Fo'
	print(matchPage(strRegexUrl,strUrl02))

	# カスタムオブジェクトの参照
	strUrl03 = 'https://ap.salesforce.com/80010000000CRTS'
	print(matchPage(strRegexUrl,strUrl03))

【python】MSHTMLイベント受信

Eternal Windowsの次の記事のC++コードをpythonに変換しようと思いました。
http://eternalwindows.jp/browser/mshtml/mshtml07.html

これでコンパイルを通すところまではできましたが、ボタンクリックしてもメッセージを出してくれない。。。 うーむ。

この方式は、一旦、諦めるか。

ただ、少なくともIHTMLDocument3やIHTMLDocument2を使えるようになった効果は大きい!

### iecontrol4.py ###
__author__ = "w.y"
__version__ = "0.0.0.4"

# Win32モジュール
import win32gui
from comtypes.gen.MSHTML import IHTMLWindow2,IHTMLDocument2,IHTMLDocument3,IHTMLElement
from comtypes.gen.MSHTML import BSTR,IDispatch
from comtypes.automation import VARIANT,VT_DISPATCH
from ctypes import windll,c_ulong,byref,POINTER
from time import sleep



class __clsIETabs(object):
	lsHandle = []
	lsHandlePrev = []
	lsTitle = []
	lsTitlePrev = []
	lsUrl = []
	lsUrlPrev = []
	lsHandleChange = []
	lsHandleClose = []

	def setHandle(self, value):
		self.lsHandle.append(value)
		return True

	def removeHandle(self, value):
		self.lsHandle.remove(value)
		return True

	def setTitle(self, value):
		self.lsTitle.append(value)
		return True

	def setUrl(self, value):
		self.lsUrl.append(value)
		return True

	def resetIETabs(self):
		self.lsHandlePrev.clear()
		self.lsTitlePrev.clear()
		self.lsUrlPrev.clear()
		for index, handle in enumerate(self.lsHandle):
			self.lsHandlePrev.append(handle);
			self.lsTitlePrev.append(self.lsTitle[index]);
			self.lsUrlPrev.append(self.lsUrl[index]);
		self.lsHandle.clear()
		self.lsTitle.clear()
		self.lsUrl.clear()
		return True

	def getIETabsChange(self):
		self.lsHandleChange.clear()
		for indexNow, hWndNow in enumerate(self.lsHandle) :
			flChange = True 
			for indexPrev,hWndPrev in enumerate(self.lsHandlePrev) :
				if ((hWndNow == hWndPrev) 
					and (self.lsTitle[indexNow] == self.lsTitlePrev[indexPrev]) 
					and (self.lsUrl[indexNow] == self.lsUrlPrev[indexPrev])):
					flChange = False
			if flChange :
				self.lsHandleChange.append(hWndNow)
		return self.lsHandleChange

	def getIETabsClose(self):
		self.lsHandleClose.clear()
		self.lsHandleClose = list(set(self.lsHandlePrev)-set(self.lsHandle))
		return self.lsHandleClose

def __checkIETab(hWnd,IETabs):
	if (win32gui.GetClassName(hWnd) == 'Internet Explorer_Server'):
		#print(str(hWnd)+' : '+win32gui.GetClassName(hWnd)+' : '+win32gui.GetWindowText(hWnd))
		IETabs.setHandle(hWnd);

class clsEventHandler(IDispatch):
	m_pWin2 = POINTER(IHTMLWindow2)()
	def __init__(self,pWin2):
		super().__init__()
		m_pWin2 = pWin2
		windll.user32.MessageBoxW(None, u'生成されました!', u'メッセージボックス!', 0x00000040)

	def _IDispatch__com_Invoke():
		super()._IDispatch__com_Invoke()
		print('ボタンが押されましたっ!')
		windll.user32.MessageBoxW(None, u'メッセージぼっくす!', u'メッセージボックス!', 0x00000040)

	def _Invoke():
		super()._Invoke()
		print('ボタンが押されましたっ!')
		windll.user32.MessageBoxW(None, u'メッセージぼっくす!', u'メッセージボックス!', 0x00000040)


	def _invoke():
		super()._invoke()
		print('ボタンが押されましたっ!')
		windll.user32.MessageBoxW(None, u'メッセージぼっくす!', u'メッセージボックス!', 0x00000040)


	def Invoke():
		super().Invoke()
		print('ボタンが押されましたっ!')
		windll.user32.MessageBoxW(None, u'メッセージぼっくす!', u'メッセージボックス!', 0x00000040)

def run():

	#初期化:IEタブのクラスを生成、無限ループフラグをセット
	IETabs = __clsIETabs()
	flContinue = True
	user32 = windll.user32
	
	#無限ループIEタブを監視
	while(flContinue):
		#古いIEタブリストの削除
		IETabs.resetIETabs()

		#IEタブリスト(ウインドウハンドル)の取得
		win32gui.EnumChildWindows(win32gui.FindWindow(u'IEFrame',None),lambda hWnd, _: __checkIETab(hWnd,IETabs), None)

		#IEタブリスト(タイトルとUrl)の取得
		uMsg = user32.RegisterWindowMessageW(u'WM_HTML_GETOBJECT')	
		for hIETab in IETabs.lsHandle:
			try : 
				lRes2 = c_ulong(0)
				pLRes2 = byref(lRes2)
				user32.SendMessageTimeoutW(hWnd, uMsg, 0, 0,2, 1000, pLRes2) # 2 == SMTO_ABORTIFHUNG 
				pDoc2 = POINTER(IHTMLDocument2)()			
				windll.oleacc.ObjectFromLresult(lRes2, IHTMLDocument2._iid_, 0, byref(pDoc2))
				IETabs.setTitle(pDoc2.title)
				IETabs.setUrl(pDoc2.url)
			except :
				IETabs.setTitle('no title')
				IETabs.setUrl('no url')
				print('IETabError!')

		#変化したIEタブ、閉じたIEタブの検出
		print('Change : ',IETabs.getIETabsChange())
		for hWnd in IETabs.getIETabsChange():
			# タイトル/URL/エレメントの取得
			lRes2 = c_ulong(0)
			pLRes2 = byref(lRes2)
			user32.SendMessageTimeoutW(hWnd, uMsg, 0, 0,2, 1000, pLRes2) # 2 == SMTO_ABORTIFHUNG 
			pDoc2 = POINTER(IHTMLDocument2)()			
			windll.oleacc.ObjectFromLresult(lRes2, IHTMLDocument2._iid_, 0, byref(pDoc2))

			lRes3 = c_ulong(0)
			pLRes3 = byref(lRes3)
			user32.SendMessageTimeoutW(hWnd, uMsg, 0, 0,2, 1000, pLRes3) # 2 == SMTO_ABORTIFHUNG 
			pDoc3 = POINTER(IHTMLDocument3)()			
			windll.oleacc.ObjectFromLresult(lRes3, IHTMLDocument3._iid_, 0, byref(pDoc3))

			pElementItem01 = POINTER(IHTMLElement)()
			pElementItem02 = POINTER(IHTMLElement)()
			strBstr = BSTR()	
			pDoc3._IHTMLDocument3__com_getElementById('btn01',byref(pElementItem01))
			pDoc3._IHTMLDocument3__com_getElementById('str_Value009',byref(pElementItem02))
			#pElementItem02._IHTMLElement__com__get_innerHTML(byref(strBstr))
			#print(strBstr)
			
			pWin2 = POINTER(IHTMLWindow2)()
			pDoc2._IHTMLDocument2__com__get_parentWindow(byref(pWin2));
			
			var = VARIANT()
			var.vt = VT_DISPATCH;
			var.pdispVal = clsEventHandler(byref(pWin2));
			try:
				pElementItem01._IHTMLElement__com__set_onclick(var);
				pElementItem02._IHTMLElement__com__set_onclick(var);
				print('set!')
			except:
				print('except!')
			
		print('Close  : ',IETabs.getIETabsClose())
		sleep(1)

if __name__ == '__main__':
	run()

でも、ここまで良くやったと思う。大幅なレベルアップ!

【python】MSHTML

◆ctypes
こういうインポートができるんだから、MSHTMLできるでしょう。

from mshtml import IHTMLDocument2, IHTMLElement

Connecting to running instances of IE on your computer « Python recipes « ActiveState Code


IHTMLElementがput_onclick()を持っているわけです。
IHTMLElement

そこにIDispatch(もしくはPyIDispatch)でアクセスできれば良いわけだな。

とうとう、C++のときのようなイベント受信ができちゃうかな?
http://eternalwindows.jp/browser/mshtml/mshtml07.html


PyIdispatchの説明は、次の2つです。
http://timgolden.me.uk/pywin32-docs/PyIDispatch__Invoke_meth.html
https://www.oreilly.com/library/view/python-programming-on/1565926218/ch12s03s06.html

cytpesでtlbファイルを変換しようと思うのだが、、、MSHTMLpythonに変換するためのreadtlb.pyが見つからない。。。
しかも、readtlb.pyについてのWeb記事が極めて少なかったり、古いのしかヒットしなかったり、ちょっと心配になってきた。

◆comtypes
こんなソースコードがgitに落ちていた。。。
github.com

もしかして、comtypes.genを使うのか?

from comtypes.client import GetModule

GetModule('mshtml.tlb')
GetModule('oleacc.dll')

ctypesのGetModuleの使い方は、こちらを参考にしました。
qiita.com

以下の場所に、mshtml.pyができているのが確認できます。

C:\python\envselenium\Lib\site-packages\comtypes-1.1.7-py3.6.egg\comtypes\gen

さぁ、次のスクリプトMSHTMLの持っているメソッドやメンバーを確認しましょう!

from comtypes.gen import MSHTML

for element in dir(MSHTML):
	print(element)

f:id:urbanplanner:20181110090407p:plain
これで、IHTMLDocument3が使えるようになるぞ!

◆ctyepsのこんな使い方
windllとか、こんな感じに使うこともできるらしい。凄いよ。
komaken.me

例えば、メッセージボックスを出してみる!

from ctypes import *
user32 = windll.user32
user32.MessageBoxW(None, u'メッセージぼっくす!', u'メッセージボックス!', 0x00000040)

【python】wxPythonでGUIを作ってみます!

◆ステップ1:まずは準備です。

pip install wxPython

◆ステップ2:常駐アプリを作る
qiita.com

◆ステップ3:wxPythonのスレッドを使う
wxPythonでスレッドを使ってみる – BTY備忘録

ここで使われているimport thread古いらしい。確かに、環境はWinXPって書いてあるしね。

今はimport threadingを使うそうです。このサイトのプログラムをそのまま動かしたければimport _threadを使おう。

【python】TKinterでGUIを作ってみます!

⇒ いろいろ試したのですが、非同期がダメだったりタスクトレイ常駐の難易度が高かったりということが分かったので、別の方法を考えます!でも、同期実行には強そうだね。

◆ステップ1:まずはキホンから!
簡単じゃん!思ったより使いやすいよ!
python.keicode.com

◆ステップ2:絵を貼りつける
gifなら簡単に読んでくれるんですが、pngやjpgの場合はpillowを使う必要があります。

pip install pillow
from PIL import Image, ImageTk
imageFile = Image.open(IMG_ROBOT)
imageData = ImageTk.PhotoImage(imageFile)


◆ステップ3:非同期でtkinterの画面を呼び出す
やろうとしたところ、次のようなことが書いてありました。tkinterダメじゃん。。。もうっ!

色々調べた所、tkinterはメインプロセス(メインスレッド)以外でmainloopを読んではいけないらしいので、pyqtを使ったらGUIのmainloopをサブプロセスで起動することができました。

teratail.com

◆ステップ4:タスクトレイ常駐とも相性が悪そう
qiita.com


◆とりあえず、ステップ2までの制作物です
・・・まだ見た目がイケてないな。。。

from tkinter import *
from tkinter import ttk
from PIL import Image, ImageTk

IMG_ROBOT = './robot.jpg'

def close_window(root): 
    root.destroy()

def showAssistStart():

	root = Tk()
	root.title('Robot Assistant')
	root.geometry('200x300')
	frame01 = ttk.Frame(root)
	imageFile = Image.open(IMG_ROBOT)
	imageData = ImageTk.PhotoImage(imageFile)
	label02 = ttk.Label(root, image=imageData)
	label01 = ttk.Label(frame01, text='アシスト対象ページです!')
	button01 = ttk.Button(frame01, text='OK',command = lambda: close_window(root))


	frame01.grid(row=0,column=0,sticky=(N,E,S,W))
	button01.grid(row=2,column=1,sticky=W)
	label01.grid(row=1,column=1,sticky=E)
	label02.grid(row=2, column=0)
	
	for child in frame01.winfo_children():
		child.grid_configure(padx=5, pady=5)

	root.mainloop()
	return True

if __name__ == '__main__':
	showAssistStart()