English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Python seleniumのファイルアップロード方法のまとめ

ファイルアップロードはすべてのUI自動化テストで直面する厄介な問題です、今日はここで自分のファイルアップロードの経験を共有し、多くのファイルアップロードの罠に落ちたseleniumerの方々に助けになればと思います。

まず、アップロードボタンの種類を区別する必要があります、大まかに2種類に分類できます、1つはinputボックス、もう1つは比較的複雑で、js、flashなどで実現され、タグはinputではありません

この2つのことをそれぞれ分析します:

1.inputタグ

众所周知、inputタグは直接send_keysを使用できます、ここも例外ではありません、コード例を見てみましょう:

サンプルURL:http://www.sahitest.com/demo/php/fileUpload.htm

代码:

# -*- coding: utf-8 -*-
from selenium import webdriver
driver = webdriver.Firefox()
driver.get('http:')//sahitest.com/demo/php/fileUpload.htm')
upload = driver.find_element_by_id('file')
upload.send_keys('d:\\baidu.py') # send_keys
print upload.get_attribute('value') # check value
driver.quit()

結果:

baidu.py

明らかに、inputアップロードの場合、直接send_keysを使用するのが最も簡単な解決策です。

2.非input型アップロード

次に、難度が上がります。inputフィールドで実装されていないアップロードはどうすればいいですか?この種のアップロードは非常に異なります。aタグ、div、button、objectを使用しています。これらのアップロードをウェブページ上で直接処理することはできません。唯一の方法は、OSのダイアログボックスを開き、ダイアログボックスを処理することです。

問題が再び発生しました。OSのダイアログボックスに関連するレベルは、seleniumでは解決できません。どうすればいいですか?非常に簡単です。OSレベルの操作を使用して処理します。ここでは、問題の解決方法を見つけました。

基本的な解決策は以下の通りです:
 1.autoIT、外部の力を利用して、生成されたau3またはexeファイル。
 2.Python pywin32ライブラリは、ダイアログのハンドルを識別し、操作を行います。
 3.SendKeysライブラリ
 4.keybd_event,跟3同様ですが、Ctrlを使用してキーボードをシミュレートしています。+a,ctrl+c,ctrl+v… 

現在のところ、私は以上の4つの方法しか知りません。他の方法がある場合は、コメントを残して教えてください。それで学びましょう。

順番に見てみましょう:

1. autoIT

autoITのアップロードおよびパラメータ化の方法については、別のブログ記事で詳しく説明しました。seleniumのautoitコマンドラインパラメータを参照してください。ここでは詳細は省略します。

2.win32gui

話は長くなりますので、まずコードを紹介します:

サンプルURL:http://www.sahitest.com/demo/php/fileUpload.htm

代码:

# -*- coding: utf-8 -*-
from selenium import webdriver
import win32gui
import win32con
import time
dr = webdriver.Firefox()
dr.get('http://sahitest.com/demo/php/fileUpload.htm')
upload = dr.find_element_by_id('file')
upload.click()
time.sleep(1)
# win32gui
dialog = win32gui.FindWindow('#32770', u'文件上传') # 对话框
ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, 'ComboBoxEx32', None) 
ComboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, 'ComboBox', None)
Edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None) # 上面三句依次寻找对象,直到找到输入框Edit对象的句柄
button = win32gui.FindWindowEx(dialog, 0, 'Button', None) # 确定按钮Button
win32gui.SendMessage(Edit, win32con.WM_SETTEXT, None, 'd:\\baidu.py') # 往输入框输入绝对地址
win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1button) # 按button
print upload.get_attribute('value')
dr.quit()

結果:

baidu.py

ここで非常に重要な小さなツールが必要です:Spy++百度で検索すると多くの情報があります。もちろん、autoITの標準ツールも使用できますが、これより良いものがありますので、他のものをダウンロードすることをお勧めします。

そして、pywinをインストールする必要があります32のライブラリ、あなたはここでに対応するライブラリを見つけます、注意32のバージョンであっても、64のバージョンと一致するものを見つけてください。

インストールが完了した後、【スタートメニューのPythonフォルダ】でPyWin32のドキュメント【Python for Windows Documentation】で、対応するメソッドAPIを見つけることができます。

使用しているものを簡単に紹介します:

win32gui.FindWindow(lpClassName=None, lpWindowName=None):
 •自上層ウィンドウから条件に一致するウィンドウを検索し、そのウィンドウのハンドルを返します。
 •lpClassName:クラス名、Spy++で見えます
 •lpWindowName:ウィンドウ名、タイトルバーに見える名前
 •コードサンプルでは、アップロードウィンドウを探すために使用しています、その中の1つを使うだけで良いです。classnameを使うと他のものに干渉されやすく、windownameを使うと不安定です。異なるアップロードダイアログには異なるwindow_nameがあります、どのように定位するかは状況に応じて決めます。 

win32gui.FindWindowEx(hwndParent=0, hwndChildAfter=0, lpszClass=None, lpszWindow=None)
 •クラス名とウィンドウ名が一致するウィンドウを検索し、そのウィンドウのハンドルを返します。見つからない場合は0を返します。
 •hwndParent:0でない場合、hwndParentウィンドウの子ウィンドウを検索します。
 •hwndChildAfter:0でない場合、z-indexの順序でhwndChildAfterから子ウィンドウを検索し始めます。そうでない場合は、最初の子ウィンドウから検索を開始します。
 •lpClassName:文字型、ウィンドウのクラス名、これはSpy++で見つける。
 •lpWindowName:文字型、ウィンドウ名、タイトルバーに見える名前です。
 •コードサンプルでは、入力フィールドと確認ボタンを階層的に探すために使用しています 

win32gui.SendMessage(hWnd, Msg, wParam, lParam)
 •hWnd:整数型、メッセージを受け取るウィンドウのハンドル
 •Msg:整数型、送信するメッセージ、これらのメッセージはWindowsが事前に定義したものであり、システム定義メッセージ(System-定義されたメッセージ)
 •wParam:整数型、メッセージのwParamパラメータ
 •lParam:整数型、メッセージのlParamパラメータ
 •コードサンプルでは、入力フィールドにファイルパスを入力し、確認ボタンをクリックするために使用しています 

そしてwinについて}32apiモジュールおよび他のメソッドについては、ここでは詳細に説明しません。興味がある場合は、自分で百度やpywinで調べてください。32ドキュメント。

3.SendKeys

まずSendKeysライブラリをインストールする必要があります。pipを使用してインストールできます。

pip install SendKeys 

コード例:

サンプルURL:http://www.sahitest.com/demo/php/fileUpload.htm

代码:

# -*- coding: utf-8 -*-
from selenium import webdriver
import win32gui
import win32con
import time
dr = webdriver.Firefox()
dr.get('http://sahitest.com/demo/php/fileUpload.htm')
upload = dr.find_element_by_id('file')
upload.click()
time.sleep(1)
# SendKeys
SendKeys.SendKeys('D:\\baidu.py') # ファイルアドレスを送信
SendKeys.SendKeys("{ENTER}") # Enterキーを送信
print upload.get_attribute('value')
dr.quit()

結果:

baidu.py

SendKeysライブラリを使用して焦点に情報を直接入力できますが、ウィンドウを開く際には少し待機時間を設定すると良いです。そうしないと、最初の文字がsendに入力されないことがあります(またはアドレスの前に無用な文字を追加することもできます)。ただし、この方法は不安定なので推奨しません。

4.keybd_event

win32apiはkeybd_event()メソッドを提供してキーボードイベントをシミュレートしますが、このメソッドは少し複雑で不安定なので、推奨しません。以下に一部のコード例を示します。研究したい場合は、自分で百度で学習してください。

# まずinputボックスを見つけて、アップロードしたいファイルのアドレスを入力し、クリップボードにコピーする 
video.send_keys('C:\\Users\\Administrator\\Pictures\\04b20919fc78baf41fc993fd8ee2c5c9.jpg')
video.send_keys(Keys.CONTROL, 'a') # seleniumのsend_keys(ctrl+a)
video.send_keys(Keys.CONTROL, 'x') # (ctrl+x)
driver.find_element_by_id('uploadImage').click() # 上传ボタンをクリックしてアップロードボックスを開く
# 貼り付け(ctrl + v)
win32api.keybd_event(17, 0, 0, 0) # ボタンを押す ctrl
win32api.keybd_event(86, 0, 0, 0) # ボタンを押す v
win32api.keybd_event(86, 0, win32con.KEYEVENTF_KEYUP, 0) # ボタンをリリースする v
win32api.keybd_event(17, 0, win32con.KEYEVENTF_KEYUP, 0) # 升起按键 ctrl
time.sleep(1)
# 回车(enter)
win32api.keybd_event(13, 0, 0, 0) # 按下按键 enter
win32api.keybd_event(13, 0, win32con.KEYEVENTF_KEYUP, 0) # 升起按键 enter
...

是不是很麻烦,当然,你甚至可以用按键把整个路径输入进去,不过,我想没人愿意这么做的。而且在此过程中你不能随意移动鼠标,不能使用剪贴板,太不稳定了,所以非常不建议你用这种办法。。

3.多文件上传

接下来还有一种情况值得我们考虑,那就是多文件上传。如何上传多个文件,当然我们还是往输入框里输入文件路径,所以唯一要搞清楚的就是多文件上传时,文件路径是怎么写的。

我来告诉你吧,多文件上传就是在文件路径框里用引号括起单个路径,然后用逗号隔开多个路径,就是这么简单,例如:
"D:\a.txt" "D:\b.txt"
但需要注意的是:只有多个文件在同一路径下,才能这样用,否则是会失败的(下面的写法是不可以的):
"C:\a.txt" "D:\b.txt" 

接下里找一个例子试试:

示例网址:http://www.sucaijiayuan.com/api/demo.php?url=/demo/20150128-1

代码:

# -*- coding: utf-8 -*-
from selenium import webdriver
import win32gui
import win32con
import time
dr = webdriver.Firefox()
dr.get('http://www.sucaijiayuan.com/api/demo.php?url=/demo/20150128-1)
dr.switch_to.frame('iframe') # 一定要注意frame
dr.find_element_by_class_name('filePicker').click()
time.sleep(1)
dialog = win32gui.FindWindow('#32770', None)
ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, 'ComboBoxEx32', None)
ComboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, 'ComboBox', None)
Edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None)
button = win32gui.FindWindowEx(dialog, 0, 'Button', None)
# 上記の例のコードと同じですが、ここではパラメータが異なります。必要に応じて、アップロード機能をエンキャップするアップロード関数を書くことができます
win32gui.SendMessage(Edit, win32con.WM_SETTEXT, 0, '"d:\\baidu.py" "d:\\upload.py" "d:\\1.html"')
win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button)
print dr.find_element_by_id('status_info').text
dr.quit()

結果:

選択3件のファイル、合計1.17KB。

したがって、多ファイルアップロードはそれほど複雑ではなく、非常に簡単です。唯一の違いは、入力パラメータが異なることだけです。autoITでも実現できます。興味がある場合は、自分で試してみてください。

また、上記のウィンドウのコードは前の例と基本的に同じであることがわかります。これにより、アップロード部分を抽出して、関数を作成することができます。アップロードが必要な場合、関数を呼び出し、パラメータを渡すだけで済みます。

見ての通り、アップロードは非常に簡単です。

これでこの記事のすべての内容が終わりました。皆様の学習に役立つことを願っています。また、ナイアラ・チュートリアルのサポートをどうぞお願いします。

声明:この記事の内容はインターネットから収集され、著作権者に帰属します。インターネットユーザーが自発的に貢献し、自己でアップロードしたものであり、このサイトは所有権を持ちません。また、人工編集は行われていません。著作権侵害を疑う内容が見つかった場合は、以下のメールアドレスまでご連絡ください:notice#oldtoolbag.com(メールを送信する際、#を@に置き換えてください。侵害を報告する場合、関連する証拠を提供してください。一旦確認が取れましたら、このサイトは即座に侵害を疑う内容を削除します。)

基本チュートリアル
おすすめ