2017-09-20 1 views
-1

J'essaie de créer un Web-Scraper en utilisant Go, je suis assez nouveau dans la langue et je ne suis pas sûr de ce que je fais mal en utilisant l'analyseur html. J'essaye d'analyser le html pour trouver des balises d'ancre mais je continue à obtenir html.TokenTypeEnd à la place.Analyse HTML avec Go

package main 

import (
    "fmt" 
    "golang.org/x/net/html" 
    "io/ioutil" 
    "net/http" 
) 

func GetHtml(url string) (text string, resp *http.Response, err error) { 
    var bytes []byte 
    if url == "https://www.coastal.edu/scs/employee" { 
     resp, err = http.Get(url) 
     if err != nil { 
      fmt.Println("There seems to ben an error with the Employee Console.") 
     } 
     bytes, err = ioutil.ReadAll(resp.Body) 
     if err != nil { 
      fmt.Println("Cannot read byte response from Employee Console.") 
     } 
     text = string(bytes) 
    } else { 
     fmt.Println("Issue with finding URL. Looking for: " + url) 
    } 

    return text, resp, err 
} 

func main() { 
    htmlSrc, response, err := GetHtml("https://www.coastal.edu/scs/employee") 
    if err != nil { 
     fmt.Println("Cannot read HTML source code.") 
    } 
    _ = htmlSrc 
    htmlTokens := html.NewTokenizer(response.Body) 
    i := 0 
    for i < 1 { 

     tt := htmlTokens.Next() 
     fmt.Printf("%T", tt) 
     switch tt { 

     case html.ErrorToken: 
      fmt.Println("End") 
      i++ 

     case html.TextToken: 
      fmt.Println(tt) 

     case html.StartTagToken: 
      t := htmlTokens.Token() 

      isAnchor := t.Data == "a" 
      if isAnchor { 
       fmt.Println("We found an anchor!") 
      } 

     } 

    } 

Je reçois html.TokenTypeEnd chaque fois que je suis l'impression fmt.Printf("%T", tt)

+0

Vous ne pouvez lire une fois que le 'response.Body'. Il a déjà été utilisé dans votre fonction 'GetHtml'. Pourquoi lisez-vous toute la chaîne html, puis la lançant quand même? – RayfenWindspear

+0

Je suis habitué à Python, alors j'ai pensé que je devais lire le code HTML et le renvoyer sous forme de chaîne. C'est le premier programme Go que j'ai écrit et je suis très nouveau dans la langue, alors j'essaie de le comprendre. – King

+0

Lorsque vous rencontrez 'io.Reader's ou' io.ReadCloser's, vous voulez éviter de tout lire dans une variable si vous le pouvez. Il existe des optimisations pour ces types qui peuvent rendre les choses plus efficaces si elles sont utilisées correctement. C'est pourquoi 'html.NewTokenizer' en prend un en premier lieu. Juste quelques conseils. Il est souvent tout à fait correct de 'ioutil.ReadAll' si vous êtes sûr que la réponse n'est pas énorme. – RayfenWindspear

Répondre

2

L'application lit à la fin du corps dans GetHtml. Le tokenizer renvoie html.TokenTypeEnd parce que lu sur le corps renvoie EOF.

Utilisez ce code:

htmlTokens := html.NewTokenizer(strings.NewReader(htmlSrc)) 

pour créer le tokenizer.

De même, fermez le corps de la réponse au GetHtml pour empêcher une fuite de connexion.

Le code peut être simplifié à:

response, err := http.Get("https://www.coastal.edu/scs/employee") 
    if err != nil { 
     log.Fatal(err) 
    } 
    defer resp.Body.Close() 
    htmlTokens := html.NewTokenizer(response.Body) 
loop: 
    for { 
     tt := htmlTokens.Next() 
     fmt.Printf("%T", tt) 
     switch tt { 
     case html.ErrorToken: 
      fmt.Println("End") 
      break loop 
     case html.TextToken: 
      fmt.Println(tt) 
     case html.StartTagToken: 
      t := htmlTokens.Token() 
      isAnchor := t.Data == "a" 
      if isAnchor { 
       fmt.Println("We found an anchor!") 
      } 
     } 
    } 
+0

Merci, cela a résolu le problème et je n'étais même pas au courant de la fuite de connexion. Je suis très nouveau à Go évidemment – King

+0

C'est en fait exactement ce que j'ai fait lol. Merci, bon conseil! – King