コード例 #1
0
def execute_selenium_script(request: ServiceRequestMessage):
    """执行Selenium脚本
    支持脚本文件或者具体的Python组件,会自动将工作单元参数和web driver对象注入到脚本当中

    - name: selenium_script
      type: browser.selenium
      args:
        request:
          session_id: var("session_id")
          script: str("file:///Users/chihongze/test.py")
          arg1: xxxx
          arg2: xxxx

    OR

    - name: selenium_script
      type: browser.selenium
      args:
        request:
          session_id: var("session_id")
          component: str("my.rpa.test")
          arg1: xxxx
          arg2: xxx
    """
    args = request.args
    session_id = args["session_id"]

    from playwell_rpa.browser import web_driver_manager
    web_driver = web_driver_manager.get_driver(session_id)

    if "script" in args:
        with open(args["script"], "r") as f:
            code = f.read()
            exec(
                code, {
                    "web_driver": web_driver,
                    "activity_id": request.activity_id,
                    "domain_id": request.domain_id,
                    "args": args
                })
        return Result.ok()
    elif "component" in args:
        component = pydoc.locate(args["component"])
        if not callable(component):
            return Result.fail(error_code="invalid_component",
                               message="The component is not callable")
        result = component(web_driver, request.activity_id, request.domain_id,
                           args)
        if result is None:
            return Result.ok()
        else:
            return Result.ok({"result": result})
    else:
        return Result.fail(error_code="invalid_arg",
                           message="没有指定要执行的Selenium脚本或组件")
コード例 #2
0
ファイル: http.py プロジェクト: tx-anin/playwell
 def _post_handler():
     try:
         message_data_seq = web_request.json
         for message_data in message_data_seq:
             self._buffer.put_nowait(self._decode_message(message_data))
         return Result.ok().to_dict()
     except Exception as e:
         logging.exception(e)
         return Result.fail(
             error_code="service_error",
             message=str(e)
         ).to_dict()
コード例 #3
0
ファイル: sms.py プロジェクト: tx-anin/playwell
def _batch_test():
    headers = {
        'Authorization':
        'WSSE realm="SDP",profile="UsernameToken",type="Appkey"',
        'X-WSSE':
        _build_wsse_header("m97WWjK5FtIV7h29jsnWCWDb4I8e",
                           "F13400QeCtVjUQ5Vm74Sj8zIw805")
    }

    sms_contents = [{
        "to": ["17600817832"],
        "templateId": "8856354b9b7e495fb6bd933882b9f9db",
        "templateParas": ["Chihz"],
        "signature": "企智未来"
    }]

    api_base = "https://api.rtc.huaweicloud.com:10443"
    channel_id = "8819080633619"
    body = {"from": channel_id, "smsContent": sms_contents}

    try:
        response = requests.post(url=urljoin(api_base,
                                             "/sms/batchSendDiffSms/v1"),
                                 headers=headers,
                                 json=body,
                                 verify=False)
        print(headers)
        print(response.text)

        send_result = response.json()

        if send_result["code"] == "000000":
            all_sms_status = {
                sms_status["originTo"]: sms_status["status"]
                for sms_status in send_result["result"]
            }
            results = []
            for sms_content in sms_contents:
                status = all_sms_status[sms_content["to"][0]]
                if status == "000000":
                    results.append(Result.ok())
                else:
                    results.append(Result.fail(error_code=status))
            return results
        else:
            return [Result.fail(error_code=send_result["code"])
                    ] * len(sms_contents)

    except Exception as e:
        logging.exception(e)
        return [Result.fail(error_code="sys_error", message=str(e))
                ] * len(sms_contents)
コード例 #4
0
def table_to_messages(request: ServiceRequestMessage):
    """可将表格转化为消息的服务
    - name: table.to_messages
      args:
        request:
          table: ref("memory_table", "students")
          message_bus: str("target_message_bus")
          message_type: str("notify_student")
          columns:
            - str("ID")
            - str("Name")
            - str("Phone")
          batch_size: 1000
          sleep: 5
    """
    args = request.args
    table = locate_from_request("table", request)
    message_type, message_bus_name = args["message_type"], args["message_bus"]
    col_names = args.get("columns", [])
    batch_size, sleep = args.get("batch_size", 1000), args.get("sleep", 0)

    message_bus = message_bus_manager.get_message_bus(message_bus_name)
    if message_bus is None:
        return Result.fail(error_code="bus_not_found",
                           message="Could not found message bus: %s" %
                           message_bus_name)

    messages = []
    ts = int(time.time() * 1000)
    for idx, row in enumerate(table):
        messages.append(
            Message(type=message_type,
                    sender="",
                    receiver="",
                    attr=row.view(col_names).map,
                    time=ts))

        if idx % batch_size == 0:
            message_bus.write(messages)
            messages = []
            ts = int(time.time() * 1000)

            if sleep != 0:
                time.sleep(sleep)

    if messages:
        message_bus.write(messages)

    return Result.ok()
コード例 #5
0
 def __init__(self,
              sender: str,
              receiver: str,
              time: int,
              activity_id: int,
              domain_id: str,
              action: str,
              status: str,
              error_code: str = "",
              message: str = "",
              data: dict = None):
     super().__init__(type=MessageTypes.RESPONSE,
                      sender=sender,
                      receiver=receiver,
                      attr={
                          ServiceResponseMessage.ATTR_ACTIVITY: activity_id,
                          ServiceResponseMessage.ATTR_DOMAIN: domain_id,
                          ServiceResponseMessage.ATTR_ACTION: action,
                          ServiceResponseMessage.ATTR_STATUS: status,
                          ServiceResponseMessage.ATTR_ERROR_CODE:
                          error_code,
                          ServiceResponseMessage.ATTR_MESSAGE: message,
                          ServiceResponseMessage.ATTR_DATA: data
                      },
                      time=time)
     self._activity_id = activity_id
     self._domain_id = domain_id
     self._action = action
     self._result = Result(
         status=status,
         error_code=error_code if error_code is not None else "",
         message=message if message is not None else "",
         data=data if data is not None else {})
コード例 #6
0
def declare_new_table(request: ServiceRequestMessage):
    """声明表格的元信息
    - name: create_table
      type: table.declare
      args:
        request:
          table: ref("excel_table", "students")
          columns:
            - name: str("id")
              title: str("ID")
            - name: str("name")
              title: str("姓名")
          meta:
            path: str("/tmp/test.xlsx")
            sheet: str("sheet")
            has_title: yes
    """
    args = request.args
    type, name, _, tmp = args["table"]
    columns = [Column(**col_data) for col_data in args.get("columns", [])]
    meta = args.get("meta", {})
    declare_table(type=type,
                  activity_id=request.activity_id,
                  domain_id=request.domain_id,
                  name=name,
                  columns=columns,
                  meta=meta,
                  tmp=tmp)
    return Result.ok()
コード例 #7
0
ファイル: html_content.py プロジェクト: tx-anin/playwell
def to_table(request: ServiceRequestMessage):
    """将HTML中的指定元素和属性提取成为Table对象
    - name: html_to_table
      type: html.to_table
      args:
        request:
          html: ref("memory_text", "html_text")
          elements: str(".gl-i-wrap")
          table: ref("excel_type", "the_table")
          columns:
            - element: str(".p-name a")
              attr: str("title")
            - element: str(".p-price .i")
              type: str("decimal")
              default: str("xxx")
    """
    args = request.args
    html_content = _get_html_content("html", request)

    bs = BeautifulSoup(html_content, 'html.parser')
    elements = bs.select(args["elements"])

    rows = []
    for element in elements:
        row = []
        for declare in args["columns"]:
            row.append(_get_value_from_element(element, declare))
        rows.append(row)

    table = locate_from_request("table", request)
    table.append_rows(rows)

    return Result.ok()
コード例 #8
0
 def __call__(self, requests: Sequence[ServiceRequestMessage]):
     connection = pymysql.connect(cursorclass=pymysql.cursors.DictCursor,
                                  **self._config)
     try:
         with connection.cursor() as cursor:
             for req in requests:
                 sql = req.args["sql"]
                 params = req.args["params"]
                 cursor.execute(sql, params)
         connection.commit()
         return [Result.ok()] * len(requests)
     except Exception as e:
         logging.exception(e)
         return [Result.fail(error_code="sys_error", message=str(e))
                 ] * len(requests)
     finally:
         connection.close()
コード例 #9
0
ファイル: sms.py プロジェクト: tx-anin/playwell
    def _batch_send(self, sms_contents: Sequence[dict]):
        try:
            headers = {
                'Authorization':
                'WSSE realm="SDP",profile="UsernameToken",type="Appkey"',
                'X-WSSE': _build_wsse_header(self._app_key, self._app_secret)
            }

            print(sms_contents)

            body = {"from": self._channel_id, "smsContent": sms_contents}

            response = requests.post(url=urljoin(self._api_base,
                                                 "/sms/batchSendDiffSms/v1"),
                                     headers=headers,
                                     json=body,
                                     verify=False)

            send_result = response.json()

            if send_result["code"] == "000000":
                all_sms_status = {
                    sms_status["originTo"]: sms_status["status"]
                    for sms_status in send_result["result"]
                }
                results = []
                for sms_content in sms_contents:
                    status = all_sms_status[sms_content["to"][0]]
                    if status == "000000":
                        results.append(Result.ok())
                    else:
                        results.append(Result.fail(error_code=status))
                return results
            else:
                return [Result.fail(error_code=send_result["code"])
                        ] * len(sms_contents)

        except Exception as e:
            logging.exception(e)
            return [Result.fail(error_code="sys_error", message=str(e))
                    ] * len(sms_contents)
コード例 #10
0
 def register_service_meta(self, service_meta: ServiceMeta):
     """Register service meta
     """
     from playwell.service.config import playwell_api
     response = requests.post(urljoin(playwell_api,
                                      "/v1/service_meta/register"),
                              json={
                                  "name": service_meta.name,
                                  "message_bus": service_meta.message_bus,
                                  "config": service_meta.config
                              })
     return Result.from_response(response)
コード例 #11
0
def close_browser(request: ServiceRequestMessage):
    """关闭一个浏览器会话
    - name: close_browser
      type: browser.close
      args:
        request:
          session_id: var("session_id")
    """
    session_id = request.args["session_id"]
    from playwell_rpa.browser import web_driver_manager
    web_driver_manager.close_driver(session_id)
    return Result.ok()
コード例 #12
0
 def refresh_all(self):
     """Refresh all service meta from API
     """
     from playwell.service.config import playwell_api
     result = Result.from_response(
         requests.get(urljoin(playwell_api, "/v1/service_meta/all")))
     if not result.is_ok():
         raise PlaywellServiceException(
             "Refresh service meta failure, the API return: %s" % result)
     self._all_service_meta = {
         service_meta["name"]: ServiceMeta(**service_meta)
         for service_meta in result.data["services"]
     }
コード例 #13
0
ファイル: bus.py プロジェクト: tx-anin/playwell
    def register_input_message_bus(self):
        """注册input message bus
        """
        from playwell.service.config import input_message_bus_config
        if not input_message_bus_config:
            return
        if self._input_message_bus is not None:
            raise PlaywellServiceException(
                "The input message bus has already been registered!")

        from playwell.service.config import playwell_api
        response = requests.post(urljoin(playwell_api,
                                         "/v1/message_bus/register"),
                                 json={"config": input_message_bus_config})
        result = Result.from_response(response)
        if not result.is_ok():
            raise PlaywellServiceException(
                "Register message bus error, the API return %s" % result)

        response = requests.post(
            urljoin(playwell_api, "/v1/message_bus/open"),
            json={"name": input_message_bus_config["name"]})
        result = Result.from_response(response)
        if not result.is_ok() and result.error_code != "already_opened":
            raise PlaywellServiceException(
                "Open message bus error, the API return: %s" % result)

        from playwell.service.message.http import HttpMessageBus
        self._input_message_bus = HttpMessageBus(
            name=input_message_bus_config["name"],
            clazz=input_message_bus_config["class"],
            alive=True,
            opened=True,
            available=True,
            config=input_message_bus_config)
        self._input_message_bus.init_web_server()
        self._all_playwell_message_bus[
            self._input_message_bus.name] = self._input_message_bus
コード例 #14
0
def table_to_list(request: ServiceRequestMessage):
    """将表格转化成list,并在Result中返回
    - name: table.to_list
      args:
        request:
          table: ref("excel_table", "students")
          row_style: str("list")
          columns:
            - str("id")
            - str("name")
        timeout: minutes(1)
      ctrl:
        - when: resultOk()
          context_vars:
            list: resultVar("list")
          then: call("next_action")
        - default: failBecause("to_list_failure")
    """
    table = locate_from_request("table", request)
    row_style = request.args.get("row_style", "map")
    col_names = request.args.get("columns", [])

    if table:
        lst = []
        for row in table:
            row = row.view(col_names)
            if row_style == "list":
                lst.append(row.elements)
            elif row_style == "map":
                lst.append(row.map)
            else:
                return Result.fail(error_code="invalid_row_style",
                                   message=("Invalid row style: %s" %
                                            row_style))
    else:
        lst = []

    return Result.ok(data={"list": lst})
コード例 #15
0
ファイル: form.py プロジェクト: tx-anin/playwell
def submit_form(request: ServiceRequestMessage):
    """该Action可以用于自动填充表单并提交
    - name: submit_form
      type: browser.form
      args:
        request:
          session_id: var("session_id")
          input:
            - css_selector: str(".username")
              input: str("Sam")
            - css_selector: str(".password")
              input: str("12345")
          submit:
            css_selector: str(".submit")
    """
    from playwell_rpa.browser import (web_driver_manager, select_element)
    args = request.args
    driver = web_driver_manager.get_driver(args["session_id"])

    # handle input elements
    input_elements = args["input"]
    for input_element_arg in input_elements:
        selector, selector_expr, input_value = None, None, None
        for k, v in input_element_arg.items():
            if k.endswith("_selector"):
                selector = k
                selector_expr = v
            elif k == "input":
                input_value = v
        input_element = select_element(driver, selector, selector_expr)
        input_element.click()
        input_element.send_keys(input_value)

    # click submit button
    submit_element_args = args["submit"]
    selector, selector_expr = submit_element_args.popitem()

    try:
        select_element(driver, selector, selector_expr).submit()
    except Exception as e:
        logging.warning("Submit error: %s, try click" % str(e))
        select_element(driver, selector, selector_expr).click()

    return Result.ok()
コード例 #16
0
ファイル: bus.py プロジェクト: tx-anin/playwell
    def refresh_all(self):
        from playwell.service.config import playwell_api
        response = requests.get(urljoin(playwell_api, "/v1/message_bus/all"))
        result = Result.from_response(response)
        if not result.is_ok():
            raise PlaywellServiceException(
                "Refresh message bus failure, the API return %s" % result)

        message_bus_data_seq = result.data.get("buses", [])
        all_names = set()
        for message_bus_data in message_bus_data_seq:
            name = message_bus_data["name"]
            clazz = message_bus_data["class"]
            all_names.add(name)
            if name in self._all_playwell_message_bus:
                message_bus = self._all_playwell_message_bus[name]
                if message_bus.opened != message_bus_data["opened"]:
                    message_bus.opened = message_bus_data["opened"]
                if message_bus.alive != message_bus_data["alive"]:
                    message_bus.alive = message_bus_data["alive"]
                if message_bus.available != message_bus_data["available"]:
                    message_bus.available = message_bus_data["available"]
            else:
                from playwell.service.message.http import HttpMessageBus
                if clazz == HttpMessageBus.CLASS_NAME:
                    message_bus = HttpMessageBus(
                        name=name,
                        clazz=clazz,
                        alive=message_bus_data["alive"],
                        opened=message_bus_data["opened"],
                        available=message_bus_data["available"],
                        config=message_bus_data.get("config", {}))
                    self._all_playwell_message_bus[
                        message_bus.name] = message_bus

        for message_bus in list(self._all_playwell_message_bus.values()):
            if message_bus.name not in all_names:
                del self._all_playwell_message_bus[message_bus.name]
コード例 #17
0
def click(request: ServiceRequestMessage):
    """click单元可以用于连续点击指定的一系列页面元素
    - name: click
      type: browser.click
      args:
        request:
          session_id: var("session_id")
          elements:
            - css_selector: str(".button_a")
            - name_selector: str("btn")
            - class_selector: str("btn")
    """
    args = request.args
    session_id, elements = args["session_id"], args["elements"]

    from playwell_rpa.browser import (web_driver_manager, select_element)
    driver = web_driver_manager.get_driver(session_id)
    for element_info in elements:
        selector, selector_expr = element_info.popitem()
        element = select_element(driver, selector, selector_expr)
        element.click()

    return Result.ok()
コード例 #18
0
def open_web_page(request: ServiceRequestMessage):
    """打开一个指定的web页面
    如果没有指定session_id,则会打开一个新的浏览器会话
    如果指定了session_id,则会直接使用已经存在的浏览器会话
    - name: open_browser
      type: browser.open
      args:
        request:
          browser: str("Chrome")
          url: str("https://www.apple.com")
          auto_close: yes
          wait:
            timeout: minutes(1)
            elements:
              - css_selector: str(".class_name")
          save_source: ref("source_code", text", "file:///tmp/index.html")
          gather:
            - name: str("id")
              css_selector: str("#id")
      ctrl:
        - when: resultOk()
          then: call("next")
          context_vars:
            browser_session_id: resultVar("session_id")
    """
    args = request.args

    url = args["url"]
    wait = args.get("wait", {})
    gather_elements = args.get("gather", [])

    from playwell_rpa.browser import (web_driver_manager, select_element)

    if "browser" in args:
        session_id = web_driver_manager.create_driver(
            activity_id=request.activity_id,
            domain_id=request.domain_id,
            browser=args["browser"],
            tmp=args.get("auto_close", True))
    else:
        session_id = args["session_id"]
    driver = web_driver_manager.get_driver(session_id)

    if "page_load_timeout" in args:
        driver.set_page_load_timeout(args["page_load_timeout"])
    if "script_timeout" in args:
        driver.set_script_timeout(args["script_timeout"])

    if wait:
        timeout = wait["timeout"]
        driver.implicitly_wait(timeout)

    try:
        driver.get(url)
    except TimeoutException:
        logging.warning("Page load timeout: %s" % url)

    if wait:
        elements = wait["elements"]
        for element in elements:
            selector, selector_expr = element.popitem()
            try:
                select_element(driver, selector, selector_expr)
            except NoSuchElementException as e:
                logging.exception(e)
                return Result.fail(error_code="wait_element_error",
                                   message=str(e))

    gathered = {}
    if gather_elements:
        for ge in gather_elements:
            try:
                item_name, text = None, None
                for k, v in ge.items():
                    if k == "name":
                        item_name = v
                    if k.endswith("_selector"):
                        text = select_element(driver, k, v).text
                gathered[item_name] = text
            except NoSuchElementException as e:
                logging.exception(e)

    if "save_source" in args:
        save_source = args["save_source"]
        from playwell_rpa.data.text import create_text
        text = create_text(type=save_source[0],
                           activity_id=request.activity_id,
                           domain_id=request.domain_id,
                           name=save_source[1],
                           meta=save_source[2],
                           tmp=save_source[3])
        text.write(driver.page_source)

    return Result.ok(data={"session_id": session_id, "gathered": gathered})
コード例 #19
0
ファイル: system.py プロジェクト: tx-anin/playwell
def exec_cmd(request: ServiceRequestMessage):
    cmd = request.args["cmd"]
    os.system(cmd)
    return Result.ok()
コード例 #20
0
def add(request_messages: Sequence[ServiceRequestMessage]):
    return [
        Result.ok({"result": req.args["a"] + req.args["b"]})
        for req in request_messages
    ]