mirror of
https://github.com/MontFerret/ferret.git
synced 2025-07-15 01:25:00 +02:00
#13 Added WAIT_ELEMENT function
This commit is contained in:
@ -2,11 +2,14 @@ package browser
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/mafredri/cdp"
|
||||
"github.com/mafredri/cdp/protocol/dom"
|
||||
"github.com/mafredri/cdp/rpcc"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type HtmlDocument struct {
|
||||
@ -108,3 +111,23 @@ func (doc *HtmlDocument) Compare(other core.Value) int {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *HtmlDocument) WaitForSelector(selector values.String, timeout values.Int) error {
|
||||
task := NewWaitTask(
|
||||
doc.client,
|
||||
fmt.Sprintf(`
|
||||
el = document.querySelector("%s");
|
||||
|
||||
if (el != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
`, selector),
|
||||
time.Millisecond*time.Duration(timeout),
|
||||
)
|
||||
|
||||
_, err := task.Run()
|
||||
|
||||
return err
|
||||
}
|
||||
|
96
pkg/stdlib/html/driver/browser/wait.go
Normal file
96
pkg/stdlib/html/driver/browser/wait.go
Normal file
@ -0,0 +1,96 @@
|
||||
package browser
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/mafredri/cdp"
|
||||
"github.com/mafredri/cdp/protocol/runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
type WaitTask struct {
|
||||
client *cdp.Client
|
||||
predicate string
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
func NewWaitTask(
|
||||
client *cdp.Client,
|
||||
predicate string,
|
||||
timeout time.Duration,
|
||||
) *WaitTask {
|
||||
return &WaitTask{
|
||||
client,
|
||||
fmt.Sprintf("((function () {%s})())", predicate),
|
||||
timeout,
|
||||
}
|
||||
}
|
||||
|
||||
func (task *WaitTask) Run() (core.Value, error) {
|
||||
var result core.Value = values.None
|
||||
var err error
|
||||
var done bool
|
||||
timer := time.NewTimer(task.timeout)
|
||||
|
||||
for !done {
|
||||
select {
|
||||
case <-timer.C:
|
||||
err = core.ErrTimeout
|
||||
done = true
|
||||
default:
|
||||
out, e := task.exec()
|
||||
|
||||
if e != nil {
|
||||
done = true
|
||||
timer.Stop()
|
||||
err = e
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if out != values.None {
|
||||
timer.Stop()
|
||||
|
||||
result = out
|
||||
done = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (task *WaitTask) exec() (core.Value, error) {
|
||||
args := runtime.NewEvaluateArgs(task.predicate).SetReturnByValue(true)
|
||||
out, err := task.client.Runtime.Evaluate(context.Background(), args)
|
||||
|
||||
if err != nil {
|
||||
return values.None, err
|
||||
}
|
||||
|
||||
if out.ExceptionDetails != nil {
|
||||
ex := out.ExceptionDetails
|
||||
return values.None, core.Error(
|
||||
core.ErrUnexpected,
|
||||
fmt.Sprintf("%s %s", ex.Text, *ex.Exception.Description),
|
||||
)
|
||||
}
|
||||
|
||||
if out.Result.Type != "undefined" {
|
||||
var o interface{}
|
||||
|
||||
err := json.Unmarshal(out.Result.Value, &o)
|
||||
|
||||
if err != nil {
|
||||
return values.None, core.Error(core.ErrUnexpected, err.Error())
|
||||
}
|
||||
|
||||
return values.Parse(o), nil
|
||||
}
|
||||
|
||||
return values.None, nil
|
||||
}
|
@ -2,6 +2,8 @@ package driver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/MontFerret/ferret/pkg/stdlib/html/driver/browser"
|
||||
"github.com/MontFerret/ferret/pkg/stdlib/html/driver/http"
|
||||
@ -19,16 +21,16 @@ func ToContext(ctx context.Context, name string, drv Driver) context.Context {
|
||||
return context.WithValue(ctx, name, drv)
|
||||
}
|
||||
|
||||
func FromContext(ctx context.Context, name string) Driver {
|
||||
func FromContext(ctx context.Context, name string) (Driver, error) {
|
||||
val := ctx.Value(name)
|
||||
|
||||
drv, ok := val.(Driver)
|
||||
|
||||
if ok {
|
||||
return drv
|
||||
return drv, nil
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil, core.Error(core.ErrNotFound, fmt.Sprintf("%s driver", name))
|
||||
}
|
||||
|
||||
func WithCdpDriver(ctx context.Context, addr string) context.Context {
|
||||
|
Reference in New Issue
Block a user