From 943d4a77b2a0ee0d0c93c3ce07f1a5afc854b063 Mon Sep 17 00:00:00 2001 From: "Alex.Shi" Date: Fri, 7 Aug 2020 12:25:59 +0300 Subject: [PATCH] add query-tree fn (#269) * add query-tree fn * update --- README.md | 20 +++++++++++++++++++ resources/html/test2.html | 34 +++++++++++++++++++++++++++++++- src/etaoin/api.clj | 41 ++++++++++++++++++++++++++++++--------- test/etaoin/api_test.clj | 13 +++++++++++++ 4 files changed, 98 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 8f6173c6..eb56839b 100644 --- a/README.md +++ b/README.md @@ -427,6 +427,26 @@ Finally it is also possible to obtain the *nth* element directly by using Note the use of `click-el` here, as `query-all` returns an element, not a selector that can be passed to `click` directly. +#### Getting elements like in a tree + +`query-tree` takes selectors and acts like a tree. +Every next selector queries elements from the previous ones. +The fist selector relies on find-elements, and the rest ones use find-elements-from + + ```clojure + (query-tree driver {:tag :div} {:tag :a}) + ``` + + means + + ``` + {:tag :div} -> [div1 div2 div3] + div1 -> [a1 a2 a3] + div2 -> [a4 a5 a6] + div3 -> [a7 a8 a9] + ``` + so the result will be [a1 ... a9] + ### Interacting with queried elements To interact with elements found via a query you have to pass the query result to diff --git a/resources/html/test2.html b/resources/html/test2.html index 8da5a529..9e253291 100644 --- a/resources/html/test2.html +++ b/resources/html/test2.html @@ -1,3 +1,35 @@ - +
+
+
+
    +
  • 1
  • +
  • 2
  • +
  • 3
  • +
  • 4
  • +
  • 5
  • +
+
+
+
+
    +
  • 6
  • +
  • 7
  • +
  • 8
  • +
+
+
+ +
+
+ link1 +
+ link2 +
diff --git a/src/etaoin/api.clj b/src/etaoin/api.clj index 32b4370a..2174b96a 100644 --- a/src/etaoin/api.clj +++ b/src/etaoin/api.clj @@ -627,6 +627,29 @@ el (apply query driver q (butlast more))] (find-elements-from* driver el loc term)))) +(defn query-tree + "Takes selectors and acts like a tree. + Every next selector queries elements from the previous ones. + The fist selector relies on find-elements, + and the rest ones use find-elements-from + + {:tag :div} {:tag :a} + means + {:tag :div} -> [div1 div2 div3] + div1 -> [a1 a2 a3] + div2 -> [a4 a5 a6] + div3 -> [a7 a8 a9] + so the result will be [a1 ... a9] + " + [driver q & qs] + (reduce (fn [elements q] + (let [[loc term] (query/expand driver q)] + (set (mapcat (fn [e] + (find-elements-from* driver e loc term)) + elements)))) + (let [[loc term] (query/expand driver q)] + (find-elements* driver loc term)) + qs)) (defn child "Finds a single element under given root element." @@ -721,7 +744,7 @@ - does not work in Phantom.js since it does not have a virtual mouse API; - does not work in Safari. -" + " [driver q-from q-to] (mouse-move-to driver q-from) (with-mouse-btn driver @@ -954,7 +977,7 @@ - `:y2`: bottom right `y` coordinate; - `:width`: width as a difference b/w `:x2` and `:x1`; - `:height`: height as a difference b/w `:y2` and `:y1`. -" + " [driver q] (let [el (query driver q) {:keys [width height]} (get-element-size-el driver el) @@ -978,7 +1001,7 @@ intersection. Returns true or false. -" + " [driver q1 q2] (let [a (get-element-box driver q1) b (get-element-box driver q2)] @@ -1056,7 +1079,7 @@ (def driver (firefox)) (get-element-attr driver {:tag :a} :class) >> \"link link__external link__button\" ;; see note above -" + " [driver q name] (get-element-attr-el driver (query driver q) name)) @@ -1104,7 +1127,7 @@ (def driver (firefox)) (get-element-css driver {:id :content} :background-color) >> \"rgb(204, 204, 204)\" ;; or \"rgba(204, 204, 204, 1)\" -" + " [driver q prop] (get-element-css-el driver (query driver q) prop)) @@ -1146,7 +1169,7 @@ For element `el` in `

hello

` it will be \"

hello

\" string. -" + " [driver q] (get-element-inner-html-el driver (query driver q))) @@ -1179,7 +1202,7 @@ "Returns inner element's text. For `

hello

` it will be \"hello\" string. -" + " [driver q] (get-element-text-el driver (query driver q))) @@ -1250,7 +1273,7 @@ - `driver`: a driver instance, - `cookie-name`: a string/keyword witn a cookie name. -" + " [driver cookie-name] (->> driver get-cookies @@ -2682,7 +2705,7 @@ - `driver`: driver instance, - `file`: either a path to a file or a native `java.io.File` instance. -" + " {:arglists '([driver file])} dispatch-driver) diff --git a/test/etaoin/api_test.clj b/test/etaoin/api_test.clj index 7072133c..981979d9 100644 --- a/test/etaoin/api_test.clj +++ b/test/etaoin/api_test.clj @@ -584,6 +584,19 @@ (is (= (vec tag-names) ["div" "b" "p" "span"]))))) +(deftest test-query-tree + (let [url (-> "html/test2.html" io/resource str) + _ (go *driver* url) + all-div (query-tree *driver* {:tag :div}) + all-li (query-tree *driver* {:tag :li}) + li-three-level (query-tree + *driver* {:tag :div} {:tag :div} {:tag :div} {:tag :li}) + tag-a (query-tree *driver* {:tag :div} {:tag :div} {:tag :a})] + (is (= 6 (count all-div))) + (is (= 8 (count all-li))) + (is (= 5 (count li-three-level))) + (is (= 1 (count tag-a))))) + (deftest test-child (let [parent-el (query *driver* {:css "#wc3-barks"}) child-el (child *driver* parent-el {:css ".crypt-lord"})