-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscrape.go
More file actions
executable file
·136 lines (111 loc) · 3.57 KB
/
Copy pathscrape.go
File metadata and controls
executable file
·136 lines (111 loc) · 3.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package scraper
import (
"reflect"
"strings"
"golang.org/x/net/html"
)
// ReplaceObj defines the data structure for an object, that has to be replaced
type ReplaceObj struct {
ToBeReplaced string `json:"toBeReplaced"`
Replacement string `json:"replacement"`
}
// FormatSettings defines the data structure for optional formatting settings of a LookUpElement
type FormatSettings struct {
Replacements []ReplaceObj `json:"replacements"`
Trim []string `json:"trim"`
AddBefore string `json:"addBefore"`
AddAfter string `json:"addAfter"`
}
// Settings defines the data structure for optional settings of a LookUpElement
type Settings struct {
FormatSettings FormatSettings `json:"formatting"`
DisallowRecursiveContent bool `json:"disallowRecursiveContent"`
}
// Tag defines the data structure for an HTML Tag
type Tag struct {
Typ string `json:"typ"`
Value string `json:"value"`
}
// HtmlElement defines the data structure for an HTML element
type HtmlElement struct {
Typ string `json:"typ"`
Tags []Tag `json:"tags"`
}
// Element defines the data structure for an element to be looked up by the scraper
type Element struct {
HtmlElement `json:"htmlElement"`
Settings `json:"settings"`
ContentIsFollowURL *Website `json:"followURL"`
Index int `json:"index"`
}
// Website defines the website data type for the scraper
type Website struct {
URL string `json:"URL"`
Elements []Element `json:"Elements"`
Separator string `json:"separator"`
}
// Scrape scrapes the website w, returning the found elements in a string each separated by Separator
func (w Website) Scrape(funcs *map[string]interface{}, vars ...interface{}) (string, error) {
if funcs != nil {
vls := reflect.ValueOf(&w).Elem()
for i := 0; i < vls.NumField(); i++ {
if vls.Field(i).Kind() == reflect.String {
vls.Field(i).Set(reflect.ValueOf(formatString(vls.Field(i).String(), *funcs, vars...)))
}
}
}
htmlData, err := GetHTML(w.URL)
if err != nil {
return "", err
}
node, err := GetHTMLNode(htmlData)
if err != nil {
return "", err
}
var elements []string
for _, el := range w.Elements {
if content, err := el.ScrapeTreeForElement(node); err != nil {
return "", err
} else {
elements = append(elements, content)
}
}
var elementString string
for k, v := range elements {
elementString += v
if k != len(elements)-1 {
elementString += w.Separator
}
}
return elementString, nil
}
// ScrapeTreeForElement scraped the node tree for a lookUpElement.Element and formats the content of it accordingly
func (e *Element) ScrapeTreeForElement(nodeTree *html.Node) (content string, err error) {
nodes, err := e.HtmlElement.GetElementNodes(nodeTree)
if err != nil {
return
}
// no node found or index out of range
if len := len(nodes) - 1; len < e.Index {
return "", newErr(ErrIdxOutOfRange, "element index out of range")
}
content = GetTextOfNode(nodes[e.Index], e.Settings.DisallowRecursiveContent)
for _, r := range e.Settings.FormatSettings.Replacements {
content = strings.ReplaceAll(content, r.ToBeReplaced, r.Replacement)
}
for _, v := range e.Settings.FormatSettings.Trim {
content = strings.Trim(content, v)
}
// add changes here
if len(e.Settings.FormatSettings.AddAfter) > 0 {
content += e.Settings.FormatSettings.AddAfter
}
if len(e.Settings.FormatSettings.AddBefore) > 0 {
content = e.Settings.FormatSettings.AddBefore + content
}
if e.ContentIsFollowURL != nil {
e.ContentIsFollowURL.URL = content
return e.ContentIsFollowURL.Scrape(nil)
}
return content, nil
}