-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathfind.go
105 lines (89 loc) · 2.63 KB
/
find.go
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
package sinonimos
import (
"errors"
"fmt"
"net/http"
"strings"
"github.com/gosimple/slug"
"github.com/yhat/scrape"
"golang.org/x/net/html"
"golang.org/x/net/html/atom"
"golang.org/x/text/encoding/charmap"
)
var (
// ErrNotFound is returned when an expression is not found on sinonimos.com.br.
ErrNotFound = errors.New("expression not found")
// ErrHTTPLayer is returned when internet connection is not available.
ErrHTTPLayer = errors.New("an error launched when trying to access the website")
// ErrInvalidFormatBody is returned when body from HTML response is not valid to parse.
ErrInvalidFormatBody = errors.New("it was not possible to parse the received html")
)
// Meaning contains information about an meaning.
//
// See Also
//
// Find
type Meaning struct {
Description string
Synonyms []string
Examples []string
}
// FindInput contains the input data require to Find.
//
// See Also
//
// Find
type FindInput struct {
Expression string
}
// FindOutput contains the output payload from Find.
//
// See Also
//
// Find
type FindOutput struct {
Meanings []Meaning
}
// Find try to find meanings for an expression on sinonimos.com.br.
func Find(input *FindInput) (*FindOutput, error) {
resp, err := http.Get(fmt.Sprintf("https://www.sinonimos.com.br/%s/", slug.Make(input.Expression)))
if err != nil {
return nil, ErrHTTPLayer
}
if resp.StatusCode == http.StatusNotFound {
return nil, ErrNotFound
}
body := charmap.ISO8859_1.NewDecoder().Reader(resp.Body)
root, err := html.Parse(body)
if err != nil {
return nil, ErrInvalidFormatBody
}
meaningSections := scrape.FindAll(root, scrape.ByClass("s-wrapper"))
meanings := make([]Meaning, len(meaningSections))
for j, meaningSection := range meaningSections {
if meaning, ok := scrape.Find(meaningSection, scrape.ByClass("sentido")); ok {
meanings[j].Description = strings.TrimSpace(scrape.Text(meaning))
}
synonyms := scrape.FindAll(meaningSection, synonymMatcher)
meanings[j].Synonyms = make([]string, len(synonyms))
for i, synonym := range synonyms {
meanings[j].Synonyms[i] = strings.TrimSpace(scrape.Text(synonym))
}
examples := scrape.FindAll(meaningSection, scrape.ByClass("exemplo"))
meanings[j].Examples = make([]string, len(examples))
for i, example := range examples {
meanings[j].Examples[i] = strings.TrimSpace(scrape.Text(example))
}
}
return &FindOutput{
Meanings: meanings,
}, nil
}
func synonymMatcher(n *html.Node) bool {
if n.DataAtom == atom.A || n.DataAtom == atom.Span {
if n.Parent != nil {
return scrape.Attr(n.Parent, "class") == "sinonimos" && scrape.Attr(n, "class") != "exemplo"
}
}
return false
}