2017-09-02 81 views
1

我是Go的新手,想要利用Go中的并发性来构建基本的刮板,以便从URL中提取标题,元描述和元关键字。如何将结果输出到Go中的并发Web刮板的CSV?

我能够将结果打印出来并发送到终端,但无法弄清楚如何将输出写入CSV。我已经尝试了许多我可以用Go的有限知识思考的变体,许多变体最终打破了并发性 - 所以失去了我的想法。

我的代码和URL输入文件如下 - 在此先感谢您的任何提示!

// file name: metascraper.go 
package main 

import (
    // import standard libraries 
    "encoding/csv" 
    "fmt" 
    "io" 
    "log" 
    "os" 
    "time" 
    // import third party libraries 
    "github.com/PuerkitoBio/goquery" 
) 

func csvParsing() { 
    file, err := os.Open("data/sample.csv") 
    checkError("Cannot open file ", err) 

    if err != nil { 
     // err is printable 
     // elements passed are separated by space automatically 
     fmt.Println("Error:", err) 
     return 
    } 

    // automatically call Close() at the end of current method 
    defer file.Close() 
    // 
    reader := csv.NewReader(file) 
    // options are available at: 
    // http://golang.org/src/pkg/encoding/csv/reader.go?s=3213:3671#L94 
    reader.Comma = ';' 
    lineCount := 0 

    fileWrite, err := os.Create("data/result.csv") 
    checkError("Cannot create file", err) 
    defer fileWrite.Close() 

    writer := csv.NewWriter(fileWrite) 
    defer writer.Flush() 

    for { 
     // read just one record 
     record, err := reader.Read() 
     // end-of-file is fitted into err 
     if err == io.EOF { 
      break 
     } else if err != nil { 
      fmt.Println("Error:", err) 
      return 
     } 

     go func(url string) { 
      // fmt.Println(msg) 
      doc, err := goquery.NewDocument(url) 
      if err != nil { 
       checkError("No URL", err) 
      } 

      metaDescription := make(chan string, 1) 
      pageTitle := make(chan string, 1) 

      go func() { 
       // time.Sleep(time.Second * 2) 
       // use CSS selector found with the browser inspector 
       // for each, use index and item 
       pageTitle <- doc.Find("title").Contents().Text() 

       doc.Find("meta").Each(func(index int, item *goquery.Selection) { 
        if item.AttrOr("name", "") == "description" { 
         metaDescription <- item.AttrOr("content", "") 
        } 
       }) 
      }() 
      select { 
      case res := <-metaDescription: 
       resTitle := <-pageTitle 
       fmt.Println(res) 
       fmt.Println(resTitle) 

       // Have been trying to output to CSV here but it's not working 

       // writer.Write([]string{url, resTitle, res}) 
       // err := writer.WriteString(`res`) 
       // checkError("Cannot write to file", err) 

      case <-time.After(time.Second * 2): 
       fmt.Println("timeout 2") 
      } 

     }(record[0]) 

     fmt.Println() 

     lineCount++ 
    } 
} 

func main() { 

    csvParsing() 

    //Code is to make sure there is a pause before program finishes so we can see output 
    var input string 
    fmt.Scanln(&input) 
} 

func checkError(message string, err error) { 
    if err != nil { 
     log.Fatal(message, err) 
    } 
} 

数据/ sample.csv输入文件使用URL:

http://jonathanmh.com 
    http://keshavmalani.com 
    http://google.com 
    http://bing.com 
    http://facebook.com 
+0

你有正确的想法,你只是简单地关闭'fileWriter',然后才有机会写信给它。 – Acidic

回答

0

在您提供的代码,你曾评论如下代码:

// Have been trying to output to CSV here but it's not working 
err = writer.Write([]string{url, resTitle, res}) 
checkError("Cannot write to file", err) 

此代码是正确的,除了你有一个问题。 在功能早些时候,你有下面的代码:

fileWrite, err := os.Create("data/result.csv") 
checkError("Cannot create file", err) 
defer fileWrite.Close() 

此代码导致的FileWriter关闭,一旦你csvParsing() FUNC退出。 因为您已经用延迟关闭了fileWriter,所以无法在并发函数中写入它。

解决方案: 你需要使用defer fileWrite.Close()您的并发FUNC或类似的东西在里面,所以你不要关闭FileWriter的你写它之前。

+0

我试过以下 'fmt.Println(resTitle) err:= writer.Write([] string {“url”,“resTitle”,“res”}) err2:= writer.Write([] string { (“不能写入文件”,错误) checkError(“无法写入文件”,错误2)' 并移动'defer fileWrite.Close()'在'lineCount ++'后'但我刚刚得到的空白CSV文件 这里是去游乐场链接:https://play.golang.org/p/eL1Bn8Xsv6 – credizian

+0

https://play.golang.org/p/1QwszPd7f7 此更新的链接应避免错误说“文件已关闭”。我通过删除'defer writer.Close()'来做到这一点。 如果您需要'defer writer.Close()'的示例,那么您可以使用等待组等待并发函数在文件关闭之前完成执行。 以下是一个示例:https://play.golang.org/p/RzLYEIW6CP – Acidic

+0

太棒了!谢谢你的工作 – credizian

相关问题