Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial git commit

  • Loading branch information...
commit ef8c4d87589f8229eab8fb3739cfe3d202d875fe 1 parent ceb0ca3
@bappybd authored
Showing with 9,236 additions and 0 deletions.
  1. +479 −0 easyprocess/__init__.py
  2. 0  easyprocess/examples/__init__.py
  3. +18 −0 easyprocess/examples/log.py
  4. +5 −0 easyprocess/examples/ver.py
  5. +64 −0 easyprocess/unicodeutil.py
  6. +186 −0 main.py
  7. +7 −0 pyvirtualdisplay/__init__.py
  8. +95 −0 pyvirtualdisplay/abstractdisplay.py
  9. +57 −0 pyvirtualdisplay/display.py
  10. 0  pyvirtualdisplay/examples/__init__.py
  11. +5 −0 pyvirtualdisplay/examples/lowres.py
  12. +9 −0 pyvirtualdisplay/examples/screenshot1.py
  13. +15 −0 pyvirtualdisplay/examples/screenshot3.py
  14. +25 −0 pyvirtualdisplay/examples/screenshot4.py
  15. +14 −0 pyvirtualdisplay/examples/vncserver.py
  16. +90 −0 pyvirtualdisplay/smartdisplay.py
  17. +39 −0 pyvirtualdisplay/xephyr.py
  18. +45 −0 pyvirtualdisplay/xvfb.py
  19. +44 −0 pyvirtualdisplay/xvnc.py
  20. +19 −0 selenium/__init__.py
  21. +16 −0 selenium/common/__init__.py
  22. +122 −0 selenium/common/exceptions.py
  23. +2,111 −0 selenium/selenium.py
  24. +31 −0 selenium/webdriver/__init__.py
  25. +14 −0 selenium/webdriver/chrome/__init__.py
  26. +132 −0 selenium/webdriver/chrome/options.py
  27. +108 −0 selenium/webdriver/chrome/service.py
  28. +82 −0 selenium/webdriver/chrome/webdriver.py
  29. +14 −0 selenium/webdriver/common/__init__.py
  30. +253 −0 selenium/webdriver/common/action_chains.py
  31. +39 −0 selenium/webdriver/common/alert.py
  32. +25 −0 selenium/webdriver/common/by.py
  33. +93 −0 selenium/webdriver/common/desired_capabilities.py
  34. 0  selenium/webdriver/common/html5/__init__.py
  35. +17 −0 selenium/webdriver/common/html5/application_cache.py
  36. +84 −0 selenium/webdriver/common/keys.py
  37. +136 −0 selenium/webdriver/common/proxy.py
  38. +165 −0 selenium/webdriver/common/touch_actions.py
  39. +46 −0 selenium/webdriver/common/utils.py
  40. +14 −0 selenium/webdriver/firefox/__init__.py
  41. +79 −0 selenium/webdriver/firefox/extension_connection.py
  42. +178 −0 selenium/webdriver/firefox/firefox_binary.py
  43. +376 −0 selenium/webdriver/firefox/firefox_profile.py
  44. +84 −0 selenium/webdriver/firefox/webdriver.py
  45. BIN  selenium/webdriver/firefox/webdriver.xpi
  46. +16 −0 selenium/webdriver/ie/__init__.py
  47. +106 −0 selenium/webdriver/ie/service.py
  48. +56 −0 selenium/webdriver/ie/webdriver.py
  49. +14 −0 selenium/webdriver/opera/__init__.py
  50. +80 −0 selenium/webdriver/opera/service.py
  51. +68 −0 selenium/webdriver/opera/webdriver.py
  52. +13 −0 selenium/webdriver/phantomjs/__init__.py
  53. +96 −0 selenium/webdriver/phantomjs/service.py
  54. +78 −0 selenium/webdriver/phantomjs/webdriver.py
  55. +14 −0 selenium/webdriver/remote/__init__.py
  56. +144 −0 selenium/webdriver/remote/command.py
  57. +152 −0 selenium/webdriver/remote/errorhandler.py
  58. +408 −0 selenium/webdriver/remote/remote_connection.py
  59. +112 −0 selenium/webdriver/remote/utils.py
  60. +824 −0 selenium/webdriver/remote/webdriver.py
  61. +286 −0 selenium/webdriver/remote/webelement.py
  62. +16 −0 selenium/webdriver/support/__init__.py
  63. +59 −0 selenium/webdriver/support/abstract_event_listener.py
  64. +303 −0 selenium/webdriver/support/color.py
  65. +326 −0 selenium/webdriver/support/event_firing_webdriver.py
  66. +18 −0 selenium/webdriver/support/events.py
  67. +283 −0 selenium/webdriver/support/expected_conditions.py
  68. +223 −0 selenium/webdriver/support/select.py
  69. +19 −0 selenium/webdriver/support/ui.py
  70. +87 −0 selenium/webdriver/support/wait.py
View
479 easyprocess/__init__.py
@@ -0,0 +1,479 @@
+'''
+Easy to use python subprocess interface.
+'''
+
+from easyprocess.unicodeutil import split_command, unidecode, uniencode
+import logging
+import os.path
+import platform
+import signal
+import subprocess
+import sys
+import tempfile
+import threading
+import time
+import ConfigParser
+
+__version__ = '0.1.6'
+
+log = logging.getLogger(__name__)
+# log=logging
+
+log.debug('version=' + __version__)
+
+CONFIG_FILE = '.easyprocess.cfg'
+SECTION_LINK = 'link'
+POLL_TIME = 0.1
+USE_POLL = 0
+
+
+class EasyProcessError(Exception):
+ """
+ """
+ def __init__(self, easy_process, msg=''):
+ self.easy_process = easy_process
+ self.msg = msg
+
+ def __str__(self):
+ return self.msg + ' ' + repr(self.easy_process)
+
+template = '''cmd=%s
+OSError=%s
+Program install error! '''
+
+
+class EasyProcessCheckInstalledError(Exception):
+ """This exception is raised when a process run by check() returns
+ a non-zero exit status or OSError is raised.
+ """
+ def __init__(self, easy_process):
+ self.easy_process = easy_process
+
+ def __str__(self):
+ msg = template % (self.easy_process.cmd,
+ self.easy_process.oserror,
+ )
+ if self.easy_process.url:
+ msg += '\nhome page: ' + self.easy_process.url
+ if platform.dist()[0].lower() == 'ubuntu':
+ if self.easy_process.ubuntu_package:
+ msg += '\nYou can install it in terminal:\n'
+ msg += 'sudo apt-get install %s' % self.easy_process.ubuntu_package
+ return msg
+
+
+class EasyProcess():
+ '''
+ .. module:: easyprocess
+
+ simple interface for :mod:`subprocess`
+
+ shell is not supported (shell=False)
+
+ .. warning::
+
+ unicode is supported only for string list command (Python2.x)
+ (check :mod:`shlex` for more information)
+
+ :param cmd: string ('ls -l') or list of strings (['ls','-l'])
+ :param cwd: working directory
+ :param use_temp_files: use temp files instead of pipes for
+ stdout and stderr,
+ pipes can cause deadlock in some cases
+ (see unit tests)
+ '''
+ config = None
+
+ def __init__(self, cmd, ubuntu_package=None, url=None, cwd=None, use_temp_files=True):
+ self.use_temp_files = use_temp_files
+ self._outputs_processed = False
+
+ self.popen = None
+ self.stdout = None
+ self.stderr = None
+ self._stdout_file = None
+ self._stderr_file = None
+ self.url = url
+ self.ubuntu_package = ubuntu_package
+ self.is_started = False
+ self.oserror = None
+ self.cmd_param = cmd
+ self._thread = None
+# self.max_bytes_to_log = max_bytes_to_log
+ self._stop_thread = False
+ self.timeout_happened = False
+ self.cwd = cwd
+ cmd = split_command(cmd)
+ self.cmd = cmd
+ self.cmd_as_string = ' '.join(self.cmd) # TODO: not perfect
+
+ log.debug('param: "%s" command: %s ("%s")' % (
+ self.cmd_param, self.cmd, self.cmd_as_string))
+
+ if not len(cmd):
+ raise EasyProcessError(self, 'empty command!')
+
+ if not Proc.config:
+ conf_file = os.path.join(os.path.expanduser('~'), CONFIG_FILE)
+ log.debug('reading config: %s' % (conf_file))
+ Proc.config = ConfigParser.RawConfigParser()
+ Proc.config.read(conf_file)
+
+ self.alias = None
+ try:
+ self.alias = Proc.config.get(SECTION_LINK, self.cmd[0])
+ except ConfigParser.NoSectionError:
+ pass
+ except ConfigParser.NoOptionError:
+ pass
+
+ if self.alias:
+ log.debug('alias found: %s' % (self.alias))
+ self.cmd[0] = self.alias
+
+ def __repr__(self):
+ msg = '<%s cmd_param=%s alias={alias} cmd=%s ({scmd}) oserror=%s returncode=%s stdout="%s" stderr="%s" timeout=%s>' % (
+ self.__class__.__name__,
+ self.cmd_param,
+ self.cmd,
+ self.oserror,
+ # alias=self.alias,
+ self.return_code,
+ self.stdout,
+ self.stderr,
+ # scmd=' '.join(self.cmd),
+ self.timeout_happened,
+ )
+ return msg
+
+ @property
+ def pid(self):
+ '''
+ PID (:attr:`subprocess.Popen.pid`)
+
+ :rtype: int
+ '''
+ if self.popen:
+ return self.popen.pid
+
+ @property
+ def return_code(self):
+ '''
+ returncode (:attr:`subprocess.Popen.returncode`)
+
+ :rtype: int
+ '''
+ if self.popen:
+ return self.popen.returncode
+
+ def check(self, return_code=0):
+ '''
+ Run command with arguments. Wait for command to complete.
+ If the exit code was as expected and there is no exception then return,
+ otherwise raise EasyProcessError.
+
+ :param return_code: int, expected return code
+ :rtype: self
+ '''
+# try:
+# ret = self.call().return_code
+# ok = ret == return_code
+# except Exception , e:
+# log.debug('OSError exception:' + str(oserror))
+# ok = False
+# self.oserror = oserror
+
+ ret = self.call().return_code
+ ok = ret == return_code
+ if not ok:
+ raise EasyProcessError(
+ self, 'check error, return code is not zero!')
+ return self
+
+ def check_installed(self):
+ '''
+ Used for testing if program is installed.
+
+ Run command with arguments. Wait for command to complete.
+ If OSError raised, then raise :class:`EasyProcessCheckInstalledError`
+ with information about program installation
+
+ :param return_code: int, expected return code
+ :rtype: self
+ '''
+ try:
+ self.call()
+ except Exception:
+ # log.debug('exception:' + str(e))
+ # self.oserror = oserror
+ raise EasyProcessCheckInstalledError(self)
+ return self
+
+ def call(self, timeout=None):
+ '''
+ Run command with arguments. Wait for command to complete.
+
+ same as:
+ 1. :meth:`start`
+ 2. :meth:`wait`
+ 3. :meth:`stop`
+
+ :rtype: self
+ '''
+ self.start().wait(timeout=timeout)
+ if self.is_alive():
+ self.stop()
+ return self
+
+ def start(self):
+ '''
+ start command in background and does not wait for it
+
+
+ :rtype: self
+ '''
+ if self.is_started:
+ raise EasyProcessError(self, 'process was started twice!')
+
+ if self.use_temp_files:
+ self._stdout_file = tempfile.TemporaryFile(prefix='stdout_')
+ self._stderr_file = tempfile.TemporaryFile(prefix='stderr_')
+ stdout = self._stdout_file
+ stderr = self._stderr_file
+
+ else:
+ stdout = subprocess.PIPE
+ stderr = subprocess.PIPE
+
+ cmd = list(map(uniencode, self.cmd))
+
+ try:
+ self.popen = subprocess.Popen(cmd,
+ stdout=stdout,
+ stderr=stderr,
+ # shell=1,
+ cwd=self.cwd,
+ )
+ except OSError, oserror:
+ log.debug('OSError exception:%s' % (oserror))
+ self.oserror = oserror
+ raise EasyProcessError(self, 'start error')
+ self.is_started = True
+ log.debug('process was started (pid=%s)' % (str(self.pid),))
+
+# def target():
+# self._wait4process()
+
+# def shutdown():
+# self._stop_thread = True
+# self._thread.join()
+
+# self._thread = threading.Thread(target=target)
+# self._thread.daemon = 1
+# self._thread.start()
+# atexit.register(shutdown)
+
+ return self
+
+ def is_alive(self):
+ '''
+ poll process using :meth:`subprocess.Popen.poll`
+
+ :rtype: bool
+ '''
+ if self.popen:
+ return self.popen.poll() is None
+ else:
+ return False
+
+ def wait(self, timeout=None):
+ '''
+ Wait for command to complete.
+
+ Timeout:
+ - discussion: http://stackoverflow.com/questions/1191374/subprocess-with-timeout
+ - implementation: threading
+
+ :rtype: self
+ '''
+
+ if timeout is not None:
+ if not self._thread:
+ self._thread = threading.Thread(target=self._wait4process)
+ self._thread.daemon = 1
+ self._thread.start()
+
+ if self._thread:
+ self._thread.join(timeout=timeout)
+ self.timeout_happened = self.timeout_happened or self._thread.isAlive()
+ else:
+ # no timeout and no existing thread
+ self._wait4process()
+
+ return self
+
+ def _wait4process(self):
+ if self._outputs_processed:
+ return
+
+ def remove_ending_lf(s):
+ if s.endswith('\n'):
+ return s[:-1]
+ else:
+ return s
+
+ if self.popen:
+ if self.use_temp_files:
+ if USE_POLL:
+ while 1:
+ if self.popen.poll() is not None:
+ break
+ if self._stop_thread:
+ return
+ time.sleep(POLL_TIME)
+
+ else:
+ # wait() blocks process, timeout not possible
+ self.popen.wait()
+
+ self._outputs_processed = True
+ self._stdout_file.seek(0)
+ self._stderr_file.seek(0)
+ self.stdout = self._stdout_file.read()
+ self.stderr = self._stderr_file.read()
+
+ self._stdout_file.close()
+ self._stderr_file.close()
+ else:
+ # This will deadlock when using stdout=PIPE and/or stderr=PIPE
+ # and the child process generates enough output to a pipe such
+ # that it blocks waiting for the OS pipe buffer to accept more data.
+ # Use communicate() to avoid that.
+ # self.popen.wait()
+ # self.stdout = self.popen.stdout.read()
+ # self.stderr = self.popen.stderr.read()
+
+ # communicate() blocks process, timeout not possible
+ self._outputs_processed = True
+ (self.stdout, self.stderr) = self.popen.communicate()
+ log.debug('process has ended')
+ self.stdout = remove_ending_lf(unidecode(self.stdout))
+ self.stderr = remove_ending_lf(unidecode(self.stderr))
+
+ log.debug('return code=' + str(self.return_code))
+# def limit_str(s):
+# if len(s) > self.max_bytes_to_log:
+# warn = '[middle of output was removed, max_bytes_to_log=%s]'%(self.max_bytes_to_log)
+# s = s[:self.max_bytes_to_log / 2] + warn + s[-self.max_bytes_to_log / 2:]
+# return s
+ log.debug('stdout=' + (self.stdout))
+ log.debug('stderr=' + (self.stderr))
+
+ def stop(self):
+ '''
+ Kill process
+ and wait for command to complete.
+
+ same as:
+ 1. :meth:`sendstop`
+ 2. :meth:`wait`
+
+ :rtype: self
+ '''
+ return self.sendstop().wait()
+
+ def sendstop(self):
+ '''
+ Kill process (:meth:`subprocess.Popen.terminate`).
+ Do not wait for command to complete.
+
+ :rtype: self
+ '''
+ if not self.is_started:
+ raise EasyProcessError(self, 'process was not started!')
+
+ log.debug(
+ 'stopping process (pid=%s cmd="%s")' % (str(self.pid), self.cmd))
+ if self.popen:
+ if self.is_alive():
+ log.debug('process is active -> sending SIGTERM')
+
+ try:
+ try:
+ self.popen.terminate()
+ except AttributeError:
+ os.kill(self.popen.pid, signal.SIGKILL)
+ except OSError, oserror:
+ log.debug('exception in terminate:%s' % (oserror))
+
+ else:
+ log.debug('process was already stopped')
+ else:
+ log.debug('process was not started')
+
+ return self
+
+ def sleep(self, sec):
+ '''
+ sleeping (same as :func:`time.sleep`)
+
+ :rtype: self
+ '''
+ time.sleep(sec)
+
+ return self
+
+ def wrap(self, func, delay=0):
+ '''
+ returns a function which:
+ 1. start process
+ 2. call func, save result
+ 3. stop process
+ 4. returns result
+
+ similar to :keyword:`with` statement
+
+ :rtype:
+ '''
+ def wrapped():
+ self.start()
+ if delay:
+ self.sleep(delay)
+ x = None
+ try:
+ x = func()
+ except OSError, oserror:
+ log.debug('OSError exception:%s' % (oserror))
+ self.oserror = oserror
+ raise EasyProcessError(self, 'wrap error!')
+ finally:
+ self.stop()
+ return x
+ return wrapped
+
+ def __enter__(self):
+ '''used by the :keyword:`with` statement'''
+ self.start()
+ return self
+
+ def __exit__(self, *exc_info):
+ '''used by the :keyword:`with` statement'''
+ self.stop()
+
+
+def extract_version(txt):
+ '''This function tries to extract the version from the help text of any program.
+ '''
+ words = txt.replace(',', ' ').split()
+ version = None
+ for x in reversed(words):
+ if len(x) > 2:
+ if x[0].lower() == 'v':
+ x = x[1:]
+ if '.' in x and x[0].isdigit():
+ version = x
+ break
+ return version
+
+
+Proc = EasyProcess
View
0  easyprocess/examples/__init__.py
No changes.
View
18 easyprocess/examples/log.py
@@ -0,0 +1,18 @@
+from easyprocess import EasyProcess
+import logging
+
+# turn on logging
+logging.basicConfig(level=logging.DEBUG)
+
+EasyProcess('python --version').call()
+EasyProcess('ping localhost').start().sleep(1).stop()
+EasyProcess('python --version').check()
+try:
+ EasyProcess('bad_command').check()
+except Exception, detail:
+ print detail
+
+try:
+ EasyProcess('sh -c bad_command').check()
+except Exception, detail:
+ print detail
View
5 easyprocess/examples/ver.py
@@ -0,0 +1,5 @@
+from easyprocess import EasyProcess
+import sys
+
+v = EasyProcess([sys.executable, '--version']).call().stderr
+print('your python version:%s' % v)
View
64 easyprocess/unicodeutil.py
@@ -0,0 +1,64 @@
+import logging
+import shlex
+import sys
+import unicodedata
+
+log = logging.getLogger(__name__)
+
+PY3 = sys.version_info[0] >= 3
+
+if PY3:
+ string_types = str,
+else:
+ string_types = basestring,
+
+
+class EasyProcessUnicodeError(Exception):
+ pass
+
+
+def split_command(cmd):
+ '''
+ - cmd is string list -> nothing to do
+ - cmd is string -> split it using shlex
+
+ :param cmd: string ('ls -l') or list of strings (['ls','-l'])
+ :rtype: string list
+ '''
+ if not isinstance(cmd, string_types):
+ # cmd is string list
+ pass
+ else:
+ if not PY3:
+ # cmd is string
+ # The shlex module currently does not support Unicode input (in
+ # 2.x)!
+ if isinstance(cmd, unicode):
+ try:
+ cmd = unicodedata.normalize(
+ 'NFKD', cmd).encode('ascii', 'strict')
+ except UnicodeEncodeError:
+ raise EasyProcessUnicodeError('unicode command "%s" can not be processed.' % cmd +
+ 'Use string list instead of string')
+ log.debug('unicode is normalized')
+ cmd = shlex.split(cmd)
+ return cmd
+
+
+def uniencode(s):
+ if PY3:
+ pass
+# s=s.encode()
+ else:
+ if isinstance(s, unicode):
+ s = s.encode('utf-8')
+ return s
+
+
+def unidecode(s):
+ if PY3:
+ s = s.decode()
+ else:
+ if isinstance(s, str):
+ s = s.decode('utf-8')
+ return s
View
186 main.py
@@ -0,0 +1,186 @@
+#!/usr/bin/env python
+
+import os, time, datetime
+#from pyvirtualdisplay import Display
+from selenium import webdriver
+from selenium.common.exceptions import NoSuchElementException
+from selenium.webdriver.common.keys import Keys
+
+class seleniumApp:
+ def __init__( self ):
+ #site specific variables
+ self.url = 'https://www.24option.com/24option/#Trade'
+ self.asset = 'EUR/USD'
+ self.assetXtraContent = ' <span class="optionRow_asset_description_HiLo">&nbsp;</span>'
+ self.assetDirection = 'High'
+ self.username = 'pacificcoder';
+ self.password = 'go4succeSS'
+ self.pageSaveDir = 'pages/'
+ self.logfile = 'application_log.txt'
+ self.max_waiting_time = 5
+
+ #display = Display(visible=0, size=(1024, 768))
+ #display.start()
+
+ #init Selenium Webdriver
+ self.driver = webdriver.Firefox()
+
+ #self.driver = webdriver.Chrome()
+
+ def startScrap(self):
+ driver = self.driver
+ driver.get(self.url)
+
+ try:
+ time.sleep(self.max_waiting_time)
+ elemResultTable = self.getElementByXpath("//table[@class='options_rows_list']", True)
+ if(elemResultTable):
+ self.log("main result table found")
+
+ # click the "shot term tab"
+ elemShortTermTab = self.getElementByXpath('//div[@class="instrument_tab_ShortTerm"]' )
+ if(elemShortTermTab):
+ elemShortTermTab.click()
+ self.log("shot term tab clicked")
+ time.sleep(2)
+
+ # click "60 seconds button"
+ elemSixtySecondButton = self.getElementByXpath('//div[@class="instrumentTypePanel"]//div[text()="60 seconds"]', True)
+ if(elemSixtySecondButton):
+ elemSixtySecondButton.click()
+ self.log("60 seconds button clicked")
+ time.sleep(2)
+
+ #elemAsset = self.getElementByXpath('//table[@class="optionRow_layout"]//tr//td[@class="optionRow_asset"]//div[text()="'+self.asset+'"][1]' )
+ elemAsset = self.getElementByXpath('//table[@class="optionRow_layout"]//tr//td[@class="optionRow_asset"]//div[@title="Euro-Dollar"][1]' )
+
+ if(elemAsset):
+ self.log("asset row found")
+ self.log(elemAsset.text)
+ elemAsset.click()
+ time.sleep(.5)
+
+ elemTextOptionView = self.getElementByXpath('//table[@class="textOptionView"]')
+ if(elemTextOptionView):
+ self.log("textOptionView found")
+ elemPriceValue = self.getAssetPrice()
+ if(elemPriceValue):
+ self.log("price found: "+elemPriceValue.text)
+
+ if(self.assetDirection == 'High'):
+ elemAssetDirection = self.getElementByXpath('//table[@class="textOptionView_innerContainer_HiLo"]//td[@class="textOptionView_call"]//div[1]')
+ if(elemAssetDirection):
+ elemAssetDirection.click()
+ self.log("High asset value clicked")
+ time.sleep(.2)
+
+ elemYourSelectionInput = self.getElementByXpath('//table[@class="optionMode_amount"]//tbody//tr//td[3]//input')
+ if(elemYourSelectionInput):
+ self.log('Your selection input field found')
+ elemYourSelectionInput.send_keys("99" + Keys.RETURN)
+ time.sleep(.2)
+
+ elemLoginPopupBox = self.getElementByXpath('//div[@class="loginPopup"]')
+ if(elemLoginPopupBox):
+ self.log('login popupbox found')
+ time.sleep(.2)
+
+ elemLoginUsername = self.getElementByXpath('//div[@class="loginBoxLayout"]//input[1]')
+ if(elemLoginUsername):
+ self.log('Username input field found')
+ elemLoginUsername.send_keys(self.username)
+
+ elemLoginPassword = self.getElementByXpath('//div[@class="loginBoxLayout"]//div[5]//input[1]')
+ if(elemLoginPassword):
+ self.log('Password input field found')
+ elemLoginPassword.send_keys(self.password)
+
+ elemLoginButton = self.getElementByXpath('//div[@class="loginBoxLayout"]//div[@id="loginButton"]//input[1]')
+ if(elemLoginButton):
+ self.log('LoginButton found')
+ elemLoginButton.click()
+
+ time.sleep(5)
+
+
+ elemBuyButton = self.getElementByXpath('//table[@class="optionMode_amount"]//tbody//tr//td[4]//div[1]')
+ if(elemBuyButton):
+ self.log('Buy button clicked')
+ elemBuyButton.click()
+
+ time.sleep(10)
+
+ else:
+ self.log("asset row not found")
+ else:
+ self.log("table not found")
+
+ except NoSuchElementException:
+ print "Result table not found"
+
+ driver.quit()
+
+ def getAssetPrice(self):
+ elemPriceValue = self.getElementByXpath('//table[@class="textOptionView_innerContainer_HiLo"]//tbody//tr[2]//td//div[1]//div[1]')
+ return elemPriceValue
+
+ #get element
+ def getElementByXpath(self, regex, waitForElement = False):
+ try:
+ elem = self.driver.find_element_by_xpath(regex) # Find the query box
+ if(elem):
+ return elem
+ else:
+ time.sleep(self.max_waiting_time)
+ if(waitForElement):
+ print "element not found. waiting"
+ self.getElementByXpath(regex, True)
+
+
+ except NoSuchElementException:
+ time.sleep(self.max_waiting_time)
+
+ if(waitForElement):
+ print "exception. waiting"
+ self.getElementByXpath(regex, True)
+ else:
+ return False
+
+ #application log
+ def log(self, contents):
+ #output to console
+ print contents + "\n"
+
+ logFileName = self.logfile
+
+ #fix contents
+ now = datetime.datetime.now()
+ currentDateTime = now.strftime("%Y-%m-%d %H:%M")
+ contents = currentDateTime + " " + str(contents) + "\n"
+
+ with open(logFileName, "a") as f:
+ f.write(contents)
+
+#create application
+if __name__ == "__main__":
+ scrapper = seleniumApp()
+ scrapper.startScrap()
+
+
+
+
+
+
+
+#class Login(unittest.TestCase):
+# def setUp(self):
+# self.driver = webdriver.Firefox()
+#
+# def tearDown(self):
+# self.driver.quit()
+#
+# def test_login(self):
+# driver = self.driver
+# driver.get('http://testurl')
+# username = driver.find_element_by_name('user_id')
+# username.send_keys('admin')
View
7 pyvirtualdisplay/__init__.py
@@ -0,0 +1,7 @@
+from display import Display
+import logging
+
+__version__ = '0.1.2'
+
+log = logging.getLogger(__name__)
+log.debug('version=' + __version__)
View
95 pyvirtualdisplay/abstractdisplay.py
@@ -0,0 +1,95 @@
+from easyprocess import EasyProcess
+import fnmatch
+import logging
+import os
+import time
+
+log = logging.getLogger(__name__)
+
+# TODO: not perfect
+# randomize to avoid possible conflicts
+RANDOMIZE_DISPLAY_NR = True
+if RANDOMIZE_DISPLAY_NR:
+ import random
+ random.seed()
+
+MIN_DISPLAY_NR = 1000
+
+
+class AbstractDisplay(EasyProcess):
+ '''
+ Common parent for Xvfb and Xephyr
+ '''
+
+ @property
+ def new_display_var(self):
+ return ':%s' % (self.display)
+
+ @property
+ def _cmd(self):
+ raise NotImplementedError()
+
+ def lock_files(self):
+ tmpdir = '/tmp'
+ pattern = '.X*-lock'
+# ls = path('/tmp').files('.X*-lock')
+ # remove path.py dependency
+ names = fnmatch.filter(os.listdir(tmpdir), pattern)
+ ls = [os.path.join(tmpdir, child) for child in names]
+ ls = [p for p in ls if os.path.isfile(p)]
+ return ls
+
+ def search_for_display(self):
+ # search for free display
+ ls = map(
+ lambda x: int(x.split('X')[1].split('-')[0]), self.lock_files())
+ if len(ls):
+ display = max(MIN_DISPLAY_NR, max(ls) + 1)
+ else:
+ display = MIN_DISPLAY_NR
+
+ if RANDOMIZE_DISPLAY_NR:
+ display += random.randint(0, 100)
+ return display
+
+ def redirect_display(self, on):
+ '''
+ on:
+ * True -> set $DISPLAY to virtual screen
+ * False -> set $DISPLAY to original screen
+
+ :param on: bool
+ '''
+ d = self.new_display_var if on else self.old_display_var
+ log.debug('DISPLAY=' + d)
+ os.environ['DISPLAY'] = d
+
+ def start(self):
+ '''
+ start display
+
+ :rtype: self
+ '''
+ self.display = self.search_for_display()
+ EasyProcess.__init__(self, self._cmd)
+ EasyProcess.start(self)
+
+ # https://github.com/ponty/PyVirtualDisplay/issues/2
+ self.old_display_var = os.environ[
+ 'DISPLAY'] if 'DISPLAY' in os.environ else ':0'
+
+ self.redirect_display(True)
+ # wait until X server is active
+ # TODO: better method
+ time.sleep(0.1)
+ return self
+
+ def stop(self):
+ '''
+ stop display
+
+ :rtype: self
+ '''
+ self.redirect_display(False)
+ EasyProcess.stop(self)
+ return self
View
57 pyvirtualdisplay/display.py
@@ -0,0 +1,57 @@
+from pyvirtualdisplay.abstractdisplay import AbstractDisplay
+from pyvirtualdisplay.xephyr import XephyrDisplay
+from pyvirtualdisplay.xvfb import XvfbDisplay
+from pyvirtualdisplay.xvnc import XvncDisplay
+
+
+class Display(AbstractDisplay):
+ '''
+ Common class
+
+ :param color_depth: [8, 16, 24, 32]
+ :param size: screen size (width,height)
+ :param bgcolor: background color ['black' or 'white']
+ :param visible: True -> Xephyr, False -> Xvfb
+ :param backend: 'xvfb', 'xvnc' or 'xephyr', ignores ``visible``
+ '''
+ def __init__(self, backend=None, visible=False, size=(1024, 768), color_depth=24, bgcolor='black', **kwargs):
+ self.color_depth = color_depth
+ self.size = size
+ self.bgcolor = bgcolor
+ self.screen = 0
+ self.process = None
+ self.display = None
+ self.visible = visible
+ self.backend = backend
+
+ if not self.backend:
+ if self.visible:
+ self.backend = 'xephyr'
+ else:
+ self.backend = 'xvfb'
+
+ self._obj = self.display_class(
+ size=size,
+ color_depth=color_depth,
+ bgcolor=bgcolor,
+ **kwargs)
+
+ @property
+ def display_class(self):
+ assert self.backend
+ if self.backend == 'xvfb':
+ cls = XvfbDisplay
+ if self.backend == 'xvnc':
+ cls = XvncDisplay
+ if self.backend == 'xephyr':
+ cls = XephyrDisplay
+
+ # TODO: check only once
+ cls.check_installed()
+
+ return cls
+
+ @property
+ def _cmd(self):
+ self._obj.display = self.display
+ return self._obj._cmd
View
0  pyvirtualdisplay/examples/__init__.py
No changes.
View
5 pyvirtualdisplay/examples/lowres.py
@@ -0,0 +1,5 @@
+from easyprocess import EasyProcess
+from pyvirtualdisplay import Display
+
+Display(visible=1, size=(320, 240)).start()
+EasyProcess('gnumeric').start()
View
9 pyvirtualdisplay/examples/screenshot1.py
@@ -0,0 +1,9 @@
+from easyprocess import EasyProcess
+from pyvirtualdisplay.smartdisplay import SmartDisplay
+
+disp = SmartDisplay(visible=0, bgcolor='black').start()
+xmessage = EasyProcess('xmessage hello').start()
+img = disp.waitgrab()
+xmessage.stop()
+disp.stop()
+img.show()
View
15 pyvirtualdisplay/examples/screenshot3.py
@@ -0,0 +1,15 @@
+'''
+using :keyword:`with` statement
+'''
+import logging
+logging.basicConfig(level=logging.DEBUG)
+
+from easyprocess import EasyProcess
+from pyvirtualdisplay.smartdisplay import SmartDisplay
+
+with SmartDisplay(visible=0, bgcolor='black') as disp:
+ with EasyProcess('xmessage hello'):
+ img = disp.waitgrab()
+
+
+img.show()
View
25 pyvirtualdisplay/examples/screenshot4.py
@@ -0,0 +1,25 @@
+'''
+two calls
+'''
+import logging
+logging.basicConfig(level=logging.DEBUG)
+
+from easyprocess import EasyProcess
+from pyvirtualdisplay.smartdisplay import SmartDisplay
+
+backend1 = 'wx'
+backend2 = 'wx'
+
+
+with SmartDisplay(visible=0, bgcolor='black') as disp:
+ disp.pyscreenshot_backend = backend1
+ with EasyProcess('xmessage test1'):
+ img1 = disp.waitgrab()
+
+with SmartDisplay(visible=0, bgcolor='black') as disp:
+ disp.pyscreenshot_backend = backend2
+ with EasyProcess('xmessage test2'):
+ img2 = disp.waitgrab()
+
+img1.show()
+img2.show()
View
14 pyvirtualdisplay/examples/vncserver.py
@@ -0,0 +1,14 @@
+'''
+Example for Xvnc backend
+'''
+
+from easyprocess import EasyProcess
+from entrypoint2 import entrypoint
+from pyvirtualdisplay.display import Display
+
+
+@entrypoint
+def main(rfbport=5904):
+ with Display(backend='xvnc', rfbport=rfbport) as disp:
+ with EasyProcess('xmessage hello') as proc:
+ proc.wait()
View
90 pyvirtualdisplay/smartdisplay.py
@@ -0,0 +1,90 @@
+from pyvirtualdisplay.display import Display
+from PIL import Image
+from PIL import ImageChops
+import logging
+import pyscreenshot
+import time
+
+
+log = logging.getLogger(__name__)
+
+
+# class DisplayError(Exception):
+# pass
+
+class DisplayTimeoutError(Exception):
+ pass
+
+
+class SmartDisplay(Display):
+ pyscreenshot_backend = None
+ pyscreenshot_childprocess = False
+
+ def autocrop(self, im):
+ '''Crop borders off an image.
+
+ :param im: Source image.
+ :param bgcolor: Background color, using either a color tuple or a color name (1.1.4 only).
+ :return: An image without borders, or None if there's no actual content in the image.
+ '''
+ if im.mode != "RGB":
+ im = im.convert("RGB")
+ bg = Image.new("RGB", im.size, self.bgcolor)
+ diff = ImageChops.difference(im, bg)
+ bbox = diff.getbbox()
+ if bbox:
+ return im.crop(bbox)
+ return None # no contents
+
+ def grab(self, autocrop=True):
+ try:
+ # first try newer pyscreenshot version
+ img = pyscreenshot.grab(
+ childprocess=self.pyscreenshot_childprocess,
+ backend=self.pyscreenshot_backend,
+ )
+ except TypeError:
+ # try older pyscreenshot version
+ img = pyscreenshot.grab()
+
+ if autocrop:
+ img = self.autocrop(img)
+ return img
+
+ def waitgrab(self, timeout=60, autocrop=True, cb_imgcheck=None):
+ '''start process and create screenshot.
+ Repeat screenshot until it is not empty and
+ cb_imgcheck callback function returns True
+ for current screenshot.
+
+ :param autocrop: True -> crop screenshot
+ :param timeout: int
+ :param cb_imgcheck: None or callback for testing img,
+ True = accept img,
+ False = reject img
+ '''
+ t = 0
+ sleep_time = 0.3 # for fast windows
+ repeat_time = 1
+ while 1:
+ log.debug('sleeping %s secs' % str(sleep_time))
+ time.sleep(sleep_time)
+ t += sleep_time
+ img = self.grab(autocrop=autocrop)
+ if img:
+ if not cb_imgcheck:
+ break
+ if cb_imgcheck(img):
+ break
+ sleep_time = repeat_time
+ repeat_time += 1 # progressive
+ if t > timeout:
+ msg = 'Timeout! elapsed time:%s timeout:%s ' % (t, timeout)
+ raise DisplayTimeoutError(msg)
+ break
+
+ log.debug('screenshot is empty, next try..')
+ assert img
+# if not img:
+# log.debug('screenshot is empty!')
+ return img
View
39 pyvirtualdisplay/xephyr.py
@@ -0,0 +1,39 @@
+from easyprocess import EasyProcess
+from pyvirtualdisplay.abstractdisplay import AbstractDisplay
+
+PROGRAM = 'Xephyr'
+URL = None
+PACKAGE = 'xephyr'
+
+
+class XephyrDisplay(AbstractDisplay):
+ '''
+ Xephyr wrapper
+
+ Xephyr is an X server outputting to a window on a pre-existing X display
+ '''
+ def __init__(self, size=(1024, 768), color_depth=24, bgcolor='black'):
+ '''
+ :param bgcolor: 'black' or 'white'
+ '''
+ self.color_depth = color_depth
+ self.size = size
+ self.bgcolor = bgcolor
+ self.screen = 0
+ self.process = None
+ self.display = None
+
+ @classmethod
+ def check_installed(cls):
+ EasyProcess([PROGRAM, '-help'], url=URL,
+ ubuntu_package=PACKAGE).check_installed()
+
+ @property
+ def _cmd(self):
+ cmd = [PROGRAM,
+ dict(black='-br', white='-wr')[self.bgcolor],
+ '-screen',
+ 'x'.join(map(str, list(self.size) + [self.color_depth])),
+ self.new_display_var,
+ ]
+ return cmd
View
45 pyvirtualdisplay/xvfb.py
@@ -0,0 +1,45 @@
+from easyprocess import EasyProcess
+from pyvirtualdisplay.abstractdisplay import AbstractDisplay
+import logging
+
+log = logging.getLogger(__name__)
+
+PROGRAM = 'Xvfb'
+URL = None
+PACKAGE = 'xvfb'
+
+
+class XvfbDisplay(AbstractDisplay):
+ '''
+ Xvfb wrapper
+
+ Xvfb is an X server that can run on machines with no display
+ hardware and no physical input devices. It emulates a dumb
+ framebuffer using virtual memory.
+ '''
+ def __init__(self, size=(1024, 768), color_depth=24, bgcolor='black'):
+ '''
+ :param bgcolor: 'black' or 'white'
+ '''
+ self.screen = 0
+ self.size = size
+ self.color_depth = color_depth
+ self.process = None
+ self.bgcolor = bgcolor
+ self.display = None
+
+ @classmethod
+ def check_installed(cls):
+ EasyProcess([PROGRAM, '-help'], url=URL,
+ ubuntu_package=PACKAGE).check_installed()
+
+ @property
+ def _cmd(self):
+ cmd = [PROGRAM,
+ dict(black='-br', white='-wr')[self.bgcolor],
+ '-screen',
+ str(self.screen),
+ 'x'.join(map(str, list(self.size) + [self.color_depth])),
+ self.new_display_var,
+ ]
+ return cmd
View
44 pyvirtualdisplay/xvnc.py
@@ -0,0 +1,44 @@
+from easyprocess import EasyProcess
+from pyvirtualdisplay.abstractdisplay import AbstractDisplay
+import logging
+
+log = logging.getLogger(__name__)
+
+PROGRAM = 'Xvnc'
+URL = None
+PACKAGE = 'tightvncserver'
+
+
+class XvncDisplay(AbstractDisplay):
+ '''
+ Xvnc wrapper
+ '''
+ def __init__(self, size=(1024, 768), color_depth=24, bgcolor='black', rfbport=5900):
+ '''
+ :param bgcolor: 'black' or 'white'
+ :param rfbport: Specifies the TCP port on which Xvnc listens for connections from viewers (the protocol used in VNC is called RFB - "remote framebuffer"). The default is 5900 plus the display number.
+ '''
+ self.screen = 0
+ self.size = size
+ self.color_depth = color_depth
+ self.process = None
+ self.bgcolor = bgcolor
+ self.display = None
+ self.rfbport = rfbport
+
+ @classmethod
+ def check_installed(cls):
+ EasyProcess([PROGRAM, '-help'], url=URL,
+ ubuntu_package=PACKAGE).check_installed()
+
+ @property
+ def _cmd(self):
+ cmd = [PROGRAM,
+ # dict(black='-br', white='-wr')[self.bgcolor],
+ # '-screen',
+ # str(self.screen),
+ # 'x'.join(map(str, list(self.size) + [self.color_depth])),
+ '-rfbport', self.rfbport,
+ self.new_display_var,
+ ]
+ return cmd
View
19 selenium/__init__.py
@@ -0,0 +1,19 @@
+# Copyright 2008-2010 WebDriver committers
+# Copyright 2008-2010 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from selenium import selenium
+
+
+__version__ = "2.31.0"
View
16 selenium/common/__init__.py
@@ -0,0 +1,16 @@
+# Copyright 2008-2010 WebDriver committers
+# Copyright 2008-2010 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import exceptions
View
122 selenium/common/exceptions.py
@@ -0,0 +1,122 @@
+# Copyright 2008-2009 WebDriver committers
+# Copyright 2008-2009 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Exceptions that may happen in all the webdriver code."""
+class WebDriverException(Exception):
+ def __init__(self, msg=None, screen=None, stacktrace=None):
+ self.msg = msg
+ self.screen = screen
+ self.stacktrace = stacktrace
+
+ def __str__(self):
+ exception_msg = "Message: %s " % repr(self.msg)
+ if self.screen is not None:
+ exception_msg = "%s; Screenshot: available via screen " \
+ % exception_msg
+ if self.stacktrace is not None:
+ exception_msg = "%s; Stacktrace: %s " \
+ % (exception_msg, str(self.stacktrace))
+ return exception_msg
+
+class ErrorInResponseException(WebDriverException):
+ """An error has occurred on the server side.
+
+ This may happen when communicating with the firefox extension
+ or the remote driver server."""
+ def __init__(self, response, msg):
+ WebDriverException.__init__(self, msg)
+ self.response = response
+
+class InvalidSwitchToTargetException(WebDriverException):
+ """The frame or window target to be switched doesn't exist."""
+ pass
+
+class NoSuchFrameException(InvalidSwitchToTargetException):
+ pass
+
+class NoSuchWindowException(InvalidSwitchToTargetException):
+ pass
+
+class NoSuchElementException(WebDriverException):
+ """find_element_by_* can't find the element."""
+ pass
+
+class NoSuchAttributeException(WebDriverException):
+ """find_element_by_* can't find the element."""
+ pass
+
+class StaleElementReferenceException(WebDriverException):
+ """Indicates that a reference to an element is now "stale" --- the
+ element no longer appears on the DOM of the page."""
+ pass
+
+class InvalidElementStateException(WebDriverException):
+ pass
+
+class NoAlertPresentException(WebDriverException):
+ pass
+
+class ElementNotVisibleException(InvalidElementStateException):
+ """Thrown to indicate that although an element is present on the
+ DOM, it is not visible, and so is not able to be interacted
+ with."""
+ pass
+
+class ElementNotSelectableException(InvalidElementStateException):
+ pass
+
+class InvalidCookieDomainException(WebDriverException):
+ """Thrown when attempting to add a cookie under a different domain
+ than the current URL."""
+ pass
+
+class UnableToSetCookieException(WebDriverException):
+ """Thrown when a driver fails to set a cookie."""
+ pass
+
+class RemoteDriverServerException(WebDriverException):
+ pass
+
+class TimeoutException(WebDriverException):
+ """Thrown when a command does not complete in enough time."""
+ pass
+
+class MoveTargetOutOfBoundsException(WebDriverException):
+ """Indicates that the target provided to the actions move() method is invalid"""
+ pass
+
+class UnexpectedTagNameException(WebDriverException):
+ """Thrown when a support class did not get an expected web element"""
+ pass
+
+class InvalidSelectorException(NoSuchElementException):
+ """ Thrown when the selector which is used to find an element does not return
+ a WebElement. Currently this only happens when the selector is an xpath
+ expression is used which is either syntactically invalid (i.e. it is not a
+ xpath expression) or the expression does not select WebElements
+ (e.g. "count(//input)").
+ """
+ pass
+
+class ImeNotAvailableException(WebDriverException):
+ """
+ Indicates that IME support is not available. This exception is thrown for every IME-related
+ method call if IME support is not available on the machine.
+ """
+ pass
+
+class ImeActivationFailedException(WebDriverException):
+ """ Indicates that activating an IME engine has failed. """
+ pass
View
2,111 selenium/selenium.py
@@ -0,0 +1,2111 @@
+
+"""
+Copyright 2011 Software Freedom Conservancy.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+__docformat__ = "restructuredtext en"
+
+import httplib
+import urllib
+
+class selenium(object):
+ """
+ Defines an object that runs Selenium commands.
+
+ **Element Locators**
+
+ Element Locators tell Selenium which HTML element a command refers to.
+ The format of a locator is:
+
+ \ *locatorType*\ **=**\ \ *argument*
+
+
+ We support the following strategies for locating elements:
+
+
+ * \ **identifier**\ =\ *id*:
+ Select the element with the specified @id attribute. If no match is
+ found, select the first element whose @name attribute is \ *id*.
+ (This is normally the default; see below.)
+ * \ **id**\ =\ *id*:
+ Select the element with the specified @id attribute.
+ * \ **name**\ =\ *name*:
+ Select the first element with the specified @name attribute.
+
+ * username
+ * name=username
+
+
+ The name may optionally be followed by one or more \ *element-filters*, separated from the name by whitespace. If the \ *filterType* is not specified, \ **value**\ is assumed.
+
+ * name=flavour value=chocolate
+
+
+ * \ **dom**\ =\ *javascriptExpression*:
+
+ Find an element by evaluating the specified string. This allows you to traverse the HTML Document Object
+ Model using JavaScript. Note that you must not return a value in this string; simply make it the last expression in the block.
+
+ * dom=document.forms['myForm'].myDropdown
+ * dom=document.images[56]
+ * dom=function foo() { return document.links[1]; }; foo();
+
+
+ * \ **xpath**\ =\ *xpathExpression*:
+ Locate an element using an XPath expression.
+
+ * xpath=//img[@alt='The image alt text']
+ * xpath=//table[@id='table1']//tr[4]/td[2]
+ * xpath=//a[contains(@href,'#id1')]
+ * xpath=//a[contains(@href,'#id1')]/@class
+ * xpath=(//table[@class='stylee'])//th[text()='theHeaderText']/../td
+ * xpath=//input[@name='name2' and @value='yes']
+ * xpath=//\*[text()="right"]
+
+
+ * \ **link**\ =\ *textPattern*:
+ Select the link (anchor) element which contains text matching the
+ specified \ *pattern*.
+
+ * link=The link text
+
+
+ * \ **css**\ =\ *cssSelectorSyntax*:
+ Select the element using css selectors. Please refer to CSS2 selectors, CSS3 selectors for more information. You can also check the TestCssLocators test in the selenium test suite for an example of usage, which is included in the downloaded selenium core package.
+
+ * css=a[href="#id3"]
+ * css=span#firstChild + span
+
+
+ Currently the css selector locator supports all css1, css2 and css3 selectors except namespace in css3, some pseudo classes(:nth-of-type, :nth-last-of-type, :first-of-type, :last-of-type, :only-of-type, :visited, :hover, :active, :focus, :indeterminate) and pseudo elements(::first-line, ::first-letter, ::selection, ::before, ::after).
+
+ * \ **ui**\ =\ *uiSpecifierString*:
+ Locate an element by resolving the UI specifier string to another locator, and evaluating it. See the Selenium UI-Element Reference for more details.
+
+ * ui=loginPages::loginButton()
+ * ui=settingsPages::toggle(label=Hide Email)
+ * ui=forumPages::postBody(index=2)//a[2]
+
+
+
+
+
+ Without an explicit locator prefix, Selenium uses the following default
+ strategies:
+
+
+ * \ **dom**\ , for locators starting with "document."
+ * \ **xpath**\ , for locators starting with "//"
+ * \ **identifier**\ , otherwise
+
+ **Element Filters**
+
+ Element filters can be used with a locator to refine a list of candidate elements. They are currently used only in the 'name' element-locator.
+
+ Filters look much like locators, ie.
+
+ \ *filterType*\ **=**\ \ *argument*
+
+ Supported element-filters are:
+
+ \ **value=**\ \ *valuePattern*
+
+
+ Matches elements based on their values. This is particularly useful for refining a list of similarly-named toggle-buttons.
+
+ \ **index=**\ \ *index*
+
+
+ Selects a single element based on its position in the list (offset from zero).
+
+ **String-match Patterns**
+
+ Various Pattern syntaxes are available for matching string values:
+
+
+ * \ **glob:**\ \ *pattern*:
+ Match a string against a "glob" (aka "wildmat") pattern. "Glob" is a
+ kind of limited regular-expression syntax typically used in command-line
+ shells. In a glob pattern, "\*" represents any sequence of characters, and "?"
+ represents any single character. Glob patterns match against the entire
+ string.
+ * \ **regexp:**\ \ *regexp*:
+ Match a string using a regular-expression. The full power of JavaScript
+ regular-expressions is available.
+ * \ **regexpi:**\ \ *regexpi*:
+ Match a string using a case-insensitive regular-expression.
+ * \ **exact:**\ \ *string*:
+
+ Match a string exactly, verbatim, without any of that fancy wildcard
+ stuff.
+
+
+
+ If no pattern prefix is specified, Selenium assumes that it's a "glob"
+ pattern.
+
+
+
+ For commands that return multiple values (such as verifySelectOptions),
+ the string being matched is a comma-separated list of the return values,
+ where both commas and backslashes in the values are backslash-escaped.
+ When providing a pattern, the optional matching syntax (i.e. glob,
+ regexp, etc.) is specified once, as usual, at the beginning of the
+ pattern.
+
+
+ """
+
+ ### This part is hard-coded in the XSL
+ def __init__(self, host, port, browserStartCommand, browserURL):
+ self.host = host
+ self.port = port
+ self.browserStartCommand = browserStartCommand
+ self.browserURL = browserURL
+ self.sessionId = None
+ self.extensionJs = ""
+
+ def setExtensionJs(self, extensionJs):
+ self.extensionJs = extensionJs
+
+ def start(self, browserConfigurationOptions=None, driver=None):
+ start_args = [self.browserStartCommand, self.browserURL, self.extensionJs]
+ if browserConfigurationOptions:
+ start_args.append(browserConfigurationOptions)
+ if driver:
+ id = driver.desired_capabilities['webdriver.remote.sessionid']
+ start_args.append('webdriver.remote.sessionid=%s' % id)
+ result = self.get_string("getNewBrowserSession", start_args)
+ try:
+ self.sessionId = result
+ except ValueError:
+ raise Exception, result
+
+ def stop(self):
+ self.do_command("testComplete", [])
+ self.sessionId = None
+
+ def do_command(self, verb, args):
+ conn = httplib.HTTPConnection(self.host, self.port)
+ try:
+ body = u'cmd=' + urllib.quote_plus(unicode(verb).encode('utf-8'))
+ for i in range(len(args)):
+ body += '&' + unicode(i+1) + '=' + \
+ urllib.quote_plus(unicode(args[i]).encode('utf-8'))
+ if (None != self.sessionId):
+ body += "&sessionId=" + unicode(self.sessionId)
+ headers = {
+ "Content-Type":
+ "application/x-www-form-urlencoded; charset=utf-8"
+ }
+ conn.request("POST", "/selenium-server/driver/", body, headers)
+
+ response = conn.getresponse()
+ data = unicode(response.read(), "UTF-8")
+ if (not data.startswith('OK')):
+ raise Exception, data
+ return data
+ finally:
+ conn.close()
+
+ def get_string(self, verb, args):
+ result = self.do_command(verb, args)
+ return result[3:]
+
+ def get_string_array(self, verb, args):
+ csv = self.get_string(verb, args)
+ if not csv:
+ return []
+ token = ""
+ tokens = []
+ escape = False
+ for i in range(len(csv)):
+ letter = csv[i]
+ if (escape):
+ token = token + letter
+ escape = False
+ continue
+ if (letter == '\\'):
+ escape = True
+ elif (letter == ','):
+ tokens.append(token)
+ token = ""
+ else:
+ token = token + letter
+ tokens.append(token)
+ return tokens
+
+ def get_number(self, verb, args):
+ return int(self.get_string(verb, args))
+
+ def get_number_array(self, verb, args):
+ string_array = self.get_string_array(verb, args)
+ num_array = []
+ for i in string_array:
+ num_array.append(int(i))
+
+ return num_array
+
+ def get_boolean(self, verb, args):
+ boolstr = self.get_string(verb, args)
+ if ("true" == boolstr):
+ return True
+ if ("false" == boolstr):
+ return False
+ raise ValueError, "result is neither 'true' nor 'false': " + boolstr
+
+ def get_boolean_array(self, verb, args):
+ boolarr = self.get_string_array(verb, args)
+ for i, boolstr in enumerate(boolarr):
+ if ("true" == boolstr):
+ boolarr[i] = True
+ continue
+ if ("false" == boolstr):
+ boolarr[i] = False
+ continue
+ raise ValueError, "result is neither 'true' nor 'false': " + boolarr[i]
+ return boolarr
+
+
+
+ def click(self,locator):
+ """
+ Clicks on a link, button, checkbox or radio button. If the click action
+ causes a new page to load (like a link usually does), call
+ waitForPageToLoad.
+
+ 'locator' is an element locator
+ """
+ self.do_command("click", [locator,])
+
+
+ def double_click(self,locator):
+ """
+ Double clicks on a link, button, checkbox or radio button. If the double click action
+ causes a new page to load (like a link usually does), call
+ waitForPageToLoad.
+
+ 'locator' is an element locator
+ """
+ self.do_command("doubleClick", [locator,])
+
+
+ def context_menu(self,locator):
+ """
+ Simulates opening the context menu for the specified element (as might happen if the user "right-clicked" on the element).
+
+ 'locator' is an element locator
+ """
+ self.do_command("contextMenu", [locator,])
+
+
+ def click_at(self,locator,coordString):
+ """
+ Clicks on a link, button, checkbox or radio button. If the click action
+ causes a new page to load (like a link usually does), call
+ waitForPageToLoad.
+
+ 'locator' is an element locator
+ 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator.
+ """
+ self.do_command("clickAt", [locator,coordString,])
+
+
+ def double_click_at(self,locator,coordString):
+ """
+ Doubleclicks on a link, button, checkbox or radio button. If the action
+ causes a new page to load (like a link usually does), call
+ waitForPageToLoad.
+
+ 'locator' is an element locator
+ 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator.
+ """
+ self.do_command("doubleClickAt", [locator,coordString,])
+
+
+ def context_menu_at(self,locator,coordString):
+ """
+ Simulates opening the context menu for the specified element (as might happen if the user "right-clicked" on the element).
+
+ 'locator' is an element locator
+ 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator.
+ """
+ self.do_command("contextMenuAt", [locator,coordString,])
+
+
+ def fire_event(self,locator,eventName):
+ """
+ Explicitly simulate an event, to trigger the corresponding "on\ *event*"
+ handler.
+
+ 'locator' is an element locator
+ 'eventName' is the event name, e.g. "focus" or "blur"
+ """
+ self.do_command("fireEvent", [locator,eventName,])
+
+
+ def focus(self,locator):
+ """
+ Move the focus to the specified element; for example, if the element is an input field, move the cursor to that field.
+
+ 'locator' is an element locator
+ """
+ self.do_command("focus", [locator,])
+
+
+ def key_press(self,locator,keySequence):
+ """
+ Simulates a user pressing and releasing a key.
+
+ 'locator' is an element locator
+ 'keySequence' is Either be a string("\" followed by the numeric keycode of the key to be pressed, normally the ASCII value of that key), or a single character. For example: "w", "\119".
+ """
+ self.do_command("keyPress", [locator,keySequence,])
+
+
+ def shift_key_down(self):
+ """
+ Press the shift key and hold it down until doShiftUp() is called or a new page is loaded.
+
+ """
+ self.do_command("shiftKeyDown", [])
+
+
+ def shift_key_up(self):
+ """
+ Release the shift key.
+
+ """
+ self.do_command("shiftKeyUp", [])
+
+
+ def meta_key_down(self):
+ """
+ Press the meta key and hold it down until doMetaUp() is called or a new page is loaded.
+
+ """
+ self.do_command("metaKeyDown", [])
+
+
+ def meta_key_up(self):
+ """
+ Release the meta key.
+
+ """
+ self.do_command("metaKeyUp", [])
+
+
+ def alt_key_down(self):
+ """
+ Press the alt key and hold it down until doAltUp() is called or a new page is loaded.
+
+ """
+ self.do_command("altKeyDown", [])
+
+
+ def alt_key_up(self):
+ """
+ Release the alt key.
+
+ """
+ self.do_command("altKeyUp", [])
+
+
+ def control_key_down(self):
+ """
+ Press the control key and hold it down until doControlUp() is called or a new page is loaded.
+
+ """
+ self.do_command("controlKeyDown", [])
+
+
+ def control_key_up(self):
+ """
+ Release the control key.
+
+ """
+ self.do_command("controlKeyUp", [])
+
+
+ def key_down(self,locator,keySequence):
+ """
+ Simulates a user pressing a key (without releasing it yet).
+
+ 'locator' is an element locator
+ 'keySequence' is Either be a string("\" followed by the numeric keycode of the key to be pressed, normally the ASCII value of that key), or a single character. For example: "w", "\119".
+ """
+ self.do_command("keyDown", [locator,keySequence,])
+
+
+ def key_up(self,locator,keySequence):
+ """
+ Simulates a user releasing a key.
+
+ 'locator' is an element locator
+ 'keySequence' is Either be a string("\" followed by the numeric keycode of the key to be pressed, normally the ASCII value of that key), or a single character. For example: "w", "\119".
+ """
+ self.do_command("keyUp", [locator,keySequence,])
+
+
+ def mouse_over(self,locator):
+ """
+ Simulates a user hovering a mouse over the specified element.
+
+ 'locator' is an element locator
+ """
+ self.do_command("mouseOver", [locator,])
+
+
+ def mouse_out(self,locator):
+ """
+ Simulates a user moving the mouse pointer away from the specified element.
+
+ 'locator' is an element locator
+ """
+ self.do_command("mouseOut", [locator,])
+
+
+ def mouse_down(self,locator):
+ """
+ Simulates a user pressing the left mouse button (without releasing it yet) on
+ the specified element.
+
+ 'locator' is an element locator
+ """
+ self.do_command("mouseDown", [locator,])
+
+
+ def mouse_down_right(self,locator):
+ """
+ Simulates a user pressing the right mouse button (without releasing it yet) on
+ the specified element.
+
+ 'locator' is an element locator
+ """
+ self.do_command("mouseDownRight", [locator,])
+
+
+ def mouse_down_at(self,locator,coordString):
+ """
+ Simulates a user pressing the left mouse button (without releasing it yet) at
+ the specified location.
+
+ 'locator' is an element locator
+ 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator.
+ """
+ self.do_command("mouseDownAt", [locator,coordString,])
+
+
+ def mouse_down_right_at(self,locator,coordString):
+ """
+ Simulates a user pressing the right mouse button (without releasing it yet) at
+ the specified location.
+
+ 'locator' is an element locator
+ 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator.
+ """
+ self.do_command("mouseDownRightAt", [locator,coordString,])
+
+
+ def mouse_up(self,locator):
+ """
+ Simulates the event that occurs when the user releases the mouse button (i.e., stops
+ holding the button down) on the specified element.
+
+ 'locator' is an element locator
+ """
+ self.do_command("mouseUp", [locator,])
+
+
+ def mouse_up_right(self,locator):
+ """
+ Simulates the event that occurs when the user releases the right mouse button (i.e., stops
+ holding the button down) on the specified element.
+
+ 'locator' is an element locator
+ """
+ self.do_command("mouseUpRight", [locator,])
+
+
+ def mouse_up_at(self,locator,coordString):
+ """
+ Simulates the event that occurs when the user releases the mouse button (i.e., stops
+ holding the button down) at the specified location.
+
+ 'locator' is an element locator
+ 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator.
+ """
+ self.do_command("mouseUpAt", [locator,coordString,])
+
+
+ def mouse_up_right_at(self,locator,coordString):
+ """
+ Simulates the event that occurs when the user releases the right mouse button (i.e., stops
+ holding the button down) at the specified location.
+
+ 'locator' is an element locator
+ 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator.
+ """
+ self.do_command("mouseUpRightAt", [locator,coordString,])
+
+
+ def mouse_move(self,locator):
+ """
+ Simulates a user pressing the mouse button (without releasing it yet) on
+ the specified element.
+
+ 'locator' is an element locator
+ """
+ self.do_command("mouseMove", [locator,])
+
+
+ def mouse_move_at(self,locator,coordString):
+ """
+ Simulates a user pressing the mouse button (without releasing it yet) on
+ the specified element.
+
+ 'locator' is an element locator
+ 'coordString' is specifies the x,y position (i.e. - 10,20) of the mouse event relative to the element returned by the locator.
+ """
+ self.do_command("mouseMoveAt", [locator,coordString,])
+
+
+ def type(self,locator,value):
+ """
+ Sets the value of an input field, as though you typed it in.
+
+
+ Can also be used to set the value of combo boxes, check boxes, etc. In these cases,
+ value should be the value of the option selected, not the visible text.
+
+
+ 'locator' is an element locator
+ 'value' is the value to type
+ """
+ self.do_command("type", [locator,value,])
+
+
+ def type_keys(self,locator,value):
+ """
+ Simulates keystroke events on the specified element, as though you typed the value key-by-key.
+
+
+ This is a convenience method for calling keyDown, keyUp, keyPress for every character in the specified string;
+ this is useful for dynamic UI widgets (like auto-completing combo boxes) that require explicit key events.
+
+ Unlike the simple "type" command, which forces the specified value into the page directly, this command
+ may or may not have any visible effect, even in cases where typing keys would normally have a visible effect.
+ For example, if you use "typeKeys" on a form element, you may or may not see the results of what you typed in
+ the field.
+
+ In some cases, you may need to use the simple "type" command to set the value of the field and then the "typeKeys" command to
+ send the keystroke events corresponding to what you just typed.
+
+
+ 'locator' is an element locator
+ 'value' is the value to type
+ """
+ self.do_command("typeKeys", [locator,value,])
+
+
+ def set_speed(self,value):
+ """
+ Set execution speed (i.e., set the millisecond length of a delay which will follow each selenium operation). By default, there is no such delay, i.e.,
+ the delay is 0 milliseconds.
+
+ 'value' is the number of milliseconds to pause after operation
+ """
+ self.do_command("setSpeed", [value,])
+
+
+ def get_speed(self):
+ """
+ Get execution speed (i.e., get the millisecond length of the delay following each selenium operation). By default, there is no such delay, i.e.,
+ the delay is 0 milliseconds.
+
+ See also setSpeed.
+
+ """
+ return self.get_string("getSpeed", [])
+
+ def get_log(self):
+ """
+ Get RC logs associated with current session.
+
+ """
+ return self.get_string("getLog", [])
+
+
+ def check(self,locator):
+ """
+ Check a toggle-button (checkbox/radio)
+
+ 'locator' is an element locator
+ """
+ self.do_command("check", [locator,])
+
+
+ def uncheck(self,locator):
+ """
+ Uncheck a toggle-button (checkbox/radio)
+
+ 'locator' is an element locator
+ """
+ self.do_command("uncheck", [locator,])
+
+
+ def select(self,selectLocator,optionLocator):
+ """
+ Select an option from a drop-down using an option locator.
+
+
+
+ Option locators provide different ways of specifying options of an HTML
+ Select element (e.g. for selecting a specific option, or for asserting
+ that the selected option satisfies a specification). There are several
+ forms of Select Option Locator.
+
+
+ * \ **label**\ =\ *labelPattern*:
+ matches options based on their labels, i.e. the visible text. (This
+ is the default.)
+
+ * label=regexp:^[Oo]ther
+
+
+ * \ **value**\ =\ *valuePattern*:
+ matches options based on their values.
+
+ * value=other
+
+
+ * \ **id**\ =\ *id*:
+
+ matches options based on their ids.
+
+ * id=option1
+
+
+ * \ **index**\ =\ *index*:
+ matches an option based on its index (offset from zero).
+
+ * index=2
+
+
+
+
+
+ If no option locator prefix is provided, the default behaviour is to match on \ **label**\ .
+
+
+
+ 'selectLocator' is an element locator identifying a drop-down menu
+ 'optionLocator' is an option locator (a label by default)
+ """
+ self.do_command("select", [selectLocator,optionLocator,])
+
+
+ def add_selection(self,locator,optionLocator):
+ """
+ Add a selection to the set of selected options in a multi-select element using an option locator.
+
+ @see #doSelect for details of option locators
+
+ 'locator' is an element locator identifying a multi-select box
+ 'optionLocator' is an option locator (a label by default)
+ """
+ self.do_command("addSelection", [locator,optionLocator,])
+
+
+ def remove_selection(self,locator,optionLocator):
+ """
+ Remove a selection from the set of selected options in a multi-select element using an option locator.
+
+ @see #doSelect for details of option locators
+
+ 'locator' is an element locator identifying a multi-select box
+ 'optionLocator' is an option locator (a label by default)
+ """
+ self.do_command("removeSelection", [locator,optionLocator,])
+
+
+ def remove_all_selections(self,locator):
+ """
+ Unselects all of the selected options in a multi-select element.
+
+ 'locator' is an element locator identifying a multi-select box
+ """
+ self.do_command("removeAllSelections", [locator,])
+
+
+ def submit(self,formLocator):
+ """
+ Submit the specified form. This is particularly useful for forms without
+ submit buttons, e.g. single-input "Search" forms.
+
+ 'formLocator' is an element locator for the form you want to submit
+ """
+ self.do_command("submit", [formLocator,])
+
+ def open(self,url,ignoreResponseCode=True):
+ """
+ Opens an URL in the test frame. This accepts both relative and absolute
+ URLs.
+
+ The "open" command waits for the page to load before proceeding,
+ ie. the "AndWait" suffix is implicit.
+
+ \ *Note*: The URL must be on the same domain as the runner HTML
+ due to security restrictions in the browser (Same Origin Policy). If you
+ need to open an URL on another domain, use the Selenium Server to start a
+ new browser session on that domain.
+
+ 'url' is the URL to open; may be relative or absolute
+ 'ignoreResponseCode' if set to true: doesnt send ajax HEAD/GET request; if set to false: sends ajax HEAD/GET request to the url and reports error code if any as response to open.
+ """
+ self.do_command("open", [url,ignoreResponseCode])
+
+
+ def open_window(self,url,windowID):
+ """
+ Opens a popup window (if a window with that ID isn't already open).
+ After opening the window, you'll need to select it using the selectWindow
+ command.
+
+
+ This command can also be a useful workaround for bug SEL-339. In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the "onLoad" event, for example).
+ In those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using
+ an empty (blank) url, like this: openWindow("", "myFunnyWindow").
+
+
+ 'url' is the URL to open, which can be blank
+ 'windowID' is the JavaScript window ID of the window to select
+ """
+ self.do_command("openWindow", [url,windowID,])
+
+
+ def select_window(self,windowID):
+ """
+ Selects a popup window using a window locator; once a popup window has been selected, all
+ commands go to that window. To select the main window again, use null
+ as the target.
+
+
+
+
+ Window locators provide different ways of specifying the window object:
+ by title, by internal JavaScript "name," or by JavaScript variable.
+
+
+ * \ **title**\ =\ *My Special Window*:
+ Finds the window using the text that appears in the title bar. Be careful;
+ two windows can share the same title. If that happens, this locator will
+ just pick one.
+
+ * \ **name**\ =\ *myWindow*:
+ Finds the window using its internal JavaScript "name" property. This is the second
+ parameter "windowName" passed to the JavaScript method window.open(url, windowName, windowFeatures, replaceFlag)
+ (which Selenium intercepts).
+
+ * \ **var**\ =\ *variableName*:
+ Some pop-up windows are unnamed (anonymous), but are associated with a JavaScript variable name in the current
+ application window, e.g. "window.foo = window.open(url);". In those cases, you can open the window using
+ "var=foo".
+
+
+
+
+ If no window locator prefix is provided, we'll try to guess what you mean like this:
+
+ 1.) if windowID is null, (or the string "null") then it is assumed the user is referring to the original window instantiated by the browser).
+
+ 2.) if the value of the "windowID" parameter is a JavaScript variable name in the current application window, then it is assumed
+ that this variable contains the return value from a call to the JavaScript window.open() method.
+
+ 3.) Otherwise, selenium looks in a hash it maintains that maps string names to window "names".
+
+ 4.) If \ *that* fails, we'll try looping over all of the known windows to try to find the appropriate "title".
+ Since "title" is not necessarily unique, this may have unexpected behavior.
+
+ If you're having trouble figuring out the name of a window that you want to manipulate, look at the Selenium log messages
+ which identify the names of windows created via window.open (and therefore intercepted by Selenium). You will see messages
+ like the following for each window as it is opened:
+
+ ``debug: window.open call intercepted; window ID (which you can use with selectWindow()) is "myNewWindow"``
+
+ In some cases, Selenium will be unable to intercept a call to window.open (if the call occurs during or before the "onLoad" event, for example).
+ (This is bug SEL-339.) In those cases, you can force Selenium to notice the open window's name by using the Selenium openWindow command, using
+ an empty (blank) url, like this: openWindow("", "myFunnyWindow").
+
+
+ 'windowID' is the JavaScript window ID of the window to select
+ """
+ self.do_command("selectWindow", [windowID,])
+
+
+ def select_pop_up(self,windowID):
+ """
+ Simplifies the process of selecting a popup window (and does not offer
+ functionality beyond what ``selectWindow()`` already provides).
+
+ * If ``windowID`` is either not specified, or specified as
+ "null", the first non-top window is selected. The top window is the one
+ that would be selected by ``selectWindow()`` without providing a
+ ``windowID`` . This should not be used when more than one popup
+ window is in play.
+ * Otherwise, the window will be looked up considering
+ ``windowID`` as the following in order: 1) the "name" of the
+ window, as specified to ``window.open()``; 2) a javascript
+ variable which is a reference to a window; and 3) the title of the
+ window. This is the same ordered lookup performed by
+ ``selectWindow`` .
+
+
+
+ 'windowID' is an identifier for the popup window, which can take on a number of different meanings
+ """
+ self.do_command("selectPopUp", [windowID,])
+
+
+ def deselect_pop_up(self):
+ """
+ Selects the main window. Functionally equivalent to using
+ ``selectWindow()`` and specifying no value for
+ ``windowID``.
+
+ """
+ self.do_command("deselectPopUp", [])
+
+
+ def select_frame(self,locator):
+ """
+ Selects a frame within the current window. (You may invoke this command
+ multiple times to select nested frames.) To select the parent frame, use
+ "relative=parent" as a locator; to select the top frame, use "relative=top".
+ You can also select a frame by its 0-based index number; select the first frame with
+ "index=0", or the third frame with "index=2".
+
+
+ You may also use a DOM expression to identify the frame you want directly,
+ like this: ``dom=frames["main"].frames["subframe"]``
+
+
+ 'locator' is an element locator identifying a frame or iframe