mirror of
https://github.com/MontFerret/ferret.git
synced 2025-11-06 08:39:09 +02:00
Feature/#105 elements count (#109)
* #105 Added ELEMENTS_COUNT function * Some minor updates * Invalid return type
This commit is contained in:
@@ -366,6 +366,13 @@ func (doc *HTMLDocument) InnerTextBySelectorAll(selector values.String) *values.
|
|||||||
return doc.element.InnerTextBySelectorAll(selector)
|
return doc.element.InnerTextBySelectorAll(selector)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (doc *HTMLDocument) CountBySelector(selector values.String) values.Int {
|
||||||
|
doc.Lock()
|
||||||
|
defer doc.Unlock()
|
||||||
|
|
||||||
|
return doc.element.CountBySelector(selector)
|
||||||
|
}
|
||||||
|
|
||||||
func (doc *HTMLDocument) ClickBySelector(selector values.String) (values.Boolean, error) {
|
func (doc *HTMLDocument) ClickBySelector(selector values.String) (values.Boolean, error) {
|
||||||
res, err := eval.Eval(
|
res, err := eval.Eval(
|
||||||
doc.client,
|
doc.client,
|
||||||
@@ -567,6 +574,11 @@ func (doc *HTMLDocument) WaitForClassAll(selector, class values.String, timeout
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (doc *HTMLDocument) WaitForNavigation(timeout values.Int) error {
|
func (doc *HTMLDocument) WaitForNavigation(timeout values.Int) error {
|
||||||
|
// do not wait
|
||||||
|
if timeout == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
onEvent := make(chan struct{})
|
onEvent := make(chan struct{})
|
||||||
listener := func(_ interface{}) {
|
listener := func(_ interface{}) {
|
||||||
close(onEvent)
|
close(onEvent)
|
||||||
|
|||||||
@@ -681,6 +681,29 @@ func (el *HTMLElement) InnerHTMLBySelectorAll(selector values.String) *values.Ar
|
|||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (el *HTMLElement) CountBySelector(selector values.String) values.Int {
|
||||||
|
if !el.IsConnected() {
|
||||||
|
return values.ZeroInt
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := contextWithTimeout()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// TODO: Can we use RemoteObjectID or BackendID instead of NodeId?
|
||||||
|
selectorArgs := dom.NewQuerySelectorAllArgs(el.id.nodeID, selector.String())
|
||||||
|
res, err := el.client.DOM.QuerySelectorAll(ctx, selectorArgs)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
el.logError(err).
|
||||||
|
Str("selector", selector.String()).
|
||||||
|
Msg("failed to retrieve nodes by selector")
|
||||||
|
|
||||||
|
return values.ZeroInt
|
||||||
|
}
|
||||||
|
|
||||||
|
return values.NewInt(len(res.NodeIDs))
|
||||||
|
}
|
||||||
|
|
||||||
func (el *HTMLElement) Click() (values.Boolean, error) {
|
func (el *HTMLElement) Click() (values.Boolean, error) {
|
||||||
ctx, cancel := contextWithTimeout()
|
ctx, cancel := contextWithTimeout()
|
||||||
|
|
||||||
|
|||||||
@@ -238,6 +238,16 @@ func (el *HTMLElement) InnerTextBySelectorAll(selector values.String) *values.Ar
|
|||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (el *HTMLElement) CountBySelector(selector values.String) values.Int {
|
||||||
|
selection := el.selection.Find(selector.String())
|
||||||
|
|
||||||
|
if selection == nil {
|
||||||
|
return values.ZeroInt
|
||||||
|
}
|
||||||
|
|
||||||
|
return values.NewInt(selection.Size())
|
||||||
|
}
|
||||||
|
|
||||||
func (el *HTMLElement) parseAttrs() *values.Object {
|
func (el *HTMLElement) parseAttrs() *values.Object {
|
||||||
obj := values.NewObject()
|
obj := values.NewObject()
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package static_test
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"github.com/MontFerret/ferret/pkg/html/static"
|
"github.com/MontFerret/ferret/pkg/html/static"
|
||||||
|
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -297,7 +298,7 @@ func TestElement(t *testing.T) {
|
|||||||
So(el.Length(), ShouldEqual, 4)
|
So(el.Length(), ShouldEqual, 4)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey(".Read", t, func() {
|
Convey(".Value", t, func() {
|
||||||
buff := bytes.NewBuffer([]byte(`
|
buff := bytes.NewBuffer([]byte(`
|
||||||
<html>
|
<html>
|
||||||
<head></head>
|
<head></head>
|
||||||
@@ -385,14 +386,34 @@ func TestElement(t *testing.T) {
|
|||||||
|
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
el, err := static.NewHTMLElement(doc.Find("body .card-img-top:nth-child(1)"))
|
el, err := static.NewHTMLElement(doc.Selection)
|
||||||
|
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
v := el.NodeName()
|
found := el.QuerySelector(values.NewString("body .card-img-top:nth-child(1)"))
|
||||||
|
|
||||||
|
So(found, ShouldNotEqual, values.None)
|
||||||
|
|
||||||
|
v := found.(values.HTMLNode).NodeName()
|
||||||
|
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
So(v, ShouldEqual, "img")
|
So(v, ShouldEqual, "img")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Convey(".CountBySelector", t, func() {
|
||||||
|
buff := bytes.NewBuffer([]byte(doc))
|
||||||
|
|
||||||
|
doc, err := goquery.NewDocumentFromReader(buff)
|
||||||
|
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
el, err := static.NewHTMLElement(doc.Selection)
|
||||||
|
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
v := el.CountBySelector(values.NewString("head meta"))
|
||||||
|
|
||||||
|
So(v, ShouldEqual, 4)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ type (
|
|||||||
InnerTextBySelector(selector String) String
|
InnerTextBySelector(selector String) String
|
||||||
|
|
||||||
InnerTextBySelectorAll(selector String) *Array
|
InnerTextBySelectorAll(selector String) *Array
|
||||||
|
|
||||||
|
CountBySelector(selector String) Int
|
||||||
}
|
}
|
||||||
|
|
||||||
HTMLDocument interface {
|
HTMLDocument interface {
|
||||||
|
|||||||
24
pkg/stdlib/html/elements_count.go
Normal file
24
pkg/stdlib/html/elements_count.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package html
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||||
|
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a number of found HTML elements by a given CSS selector.
|
||||||
|
* Returns an empty array if element not found.
|
||||||
|
* @param docOrEl (HTMLDocument|HTMLElement) - Parent document or element.
|
||||||
|
* @param selector (String) - CSS selector.
|
||||||
|
* @returns (Int) - A number of found HTML elements by a given CSS selector.
|
||||||
|
*/
|
||||||
|
func ElementsCount(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||||
|
el, selector, err := queryArgs(args)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return values.None, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return el.CountBySelector(selector), nil
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ func NewLib() map[string]core.Function {
|
|||||||
"DOCUMENT_PARSE": DocumentParse,
|
"DOCUMENT_PARSE": DocumentParse,
|
||||||
"ELEMENT": Element,
|
"ELEMENT": Element,
|
||||||
"ELEMENTS": Elements,
|
"ELEMENTS": Elements,
|
||||||
|
"ELEMENTS_COUNT": ElementsCount,
|
||||||
"WAIT_ELEMENT": WaitElement,
|
"WAIT_ELEMENT": WaitElement,
|
||||||
"WAIT_NAVIGATION": WaitNavigation,
|
"WAIT_NAVIGATION": WaitNavigation,
|
||||||
"WAIT_CLASS": WaitClass,
|
"WAIT_CLASS": WaitClass,
|
||||||
|
|||||||
Reference in New Issue
Block a user