Changes
This proposal introduces:
- New keyword
- New data structure
- Another returned value from a program execution
Background
Every time you scrape a website, Ferret does not return result until query execution completes. It keeps all results in memory and if an error occurs - all data is lost.
I.e. you either have all data or nothing.
Proposal
This proposal offers an optional alternative approach - asynchronous execution using streams.
Instead of keeping data in memory and waiting for the end of execution, we could return the results as soon as they arrive using stream based data structures.
On each iteration we would push results to a stream and a caller of a compiled query would receive it.
In situations when having all data is not critical, it will improve stability and efficiency.
Here is a possible syntax for an async execution:
import (
"context"
"encoding/json"
"fmt"
"os"
"github.com/MontFerret/ferret/pkg/compiler"
"github.com/MontFerret/ferret/pkg/drivers"
"github.com/MontFerret/ferret/pkg/drivers/cdp"
"github.com/MontFerret/ferret/pkg/drivers/http"
)
func main() {
query := `
LET doc = DOCUMENT('https://www.theverge.com/tech', { driver: "cdp" })
WAIT_ELEMENT(doc, '.c-compact-river__entry', 5000)
LET articles = ELEMENTS(doc, '.c-entry-box--compact__image-wrapper')
LET links = (
FOR article IN articles
RETURN article.attributes.href
)
FOR link IN links
// The Verge has pretty heavy pages, so let's increase the navigation wait time
NAVIGATE(doc, link, 20000)
WAIT_ELEMENT(doc, '.c-entry-content', 5000)
LET texter = ELEMENT(doc, '.c-entry-content')
YIELD texter.innerText
`
comp := compiler.New()
program, err := comp.Compile(query)
if err != nil {
panic(err)
}
ctx := drivers.WithContext(context.Background(), cdp.NewDriver())
out, err := program.Run(ctx)
if err != nil {
panic(err)
}
// .Run now returns io.Reader interface
// Even if a query does not use ASYNC iteration
data, err := ioutils.ReadAll(out)
}
Changes
This proposal introduces:
Background
Every time you scrape a website, Ferret does not return result until query execution completes. It keeps all results in memory and if an error occurs - all data is lost.
I.e. you either have all data or nothing.
Proposal
This proposal offers an optional alternative approach - asynchronous execution using streams.
Instead of keeping data in memory and waiting for the end of execution, we could return the results as soon as they arrive using stream based data structures.
On each iteration we would push results to a stream and a caller of a compiled query would receive it.
In situations when having all data is not critical, it will improve stability and efficiency.
Here is a possible syntax for an async execution: