php是最好的语言

golang并发爬取本网站

涉及到解析html的扩展是goquery 可以去git下载就好了 本程序主要是两个线程 

一个线程爬取分页的详情链接 然后把链接相关数据 存进chan 

另一线程从chan拿取详情链接 获取详情数据 然后把数据存进去另一个chan 最后插入数据库

package main

import (
   "fmt"
   "regexp"
   "log"
   "net/http"
   "github.com/PuerkitoBio/goquery"
   "strings"
   "github.com/jmoiron/sqlx"
   _ "github.com/go-sql-driver/mysql"
)

//数据格式
type Pdata struct {
   title string `json:"title"`
   href string `json:"href"`
   author string `json:"author"`
   text string `json:"text"`
}

//var Db

func Init() *sqlx.DB {
   db,err := sqlx.Open(`mysql`,"root:xt@tcp(127.0.0.1:3306)/test")
   if err != nil{
      log.Print(err.Error())
   }
   return db
}

func InsertData(allData []Pdata)(){
   Db := Init()

   for _,value := range allData{
      _,err := Db.Exec("insert into jjj set title = ?,href = ?,author = ?,content = ?",value.title,value.href,value.author,value.text)
      log.Print(err)
   }

}

//解析页面返回的数据
func getData(ch chan Pdata){
   for i := 1;i < 16;i++{
      href   :=     fmt.Sprintf("http://phpindex.win/?page=%d",i)

      resp   := getHrefData(href)

      doc, _     :=     goquery.NewDocumentFromResponse(resp)

      doc.Find(".auth1").Each(func(i int, selection *goquery.Selection) {
         var tempD Pdata

         tempD.title    =  selection.Find("header > h2").Text()
         href,_           := selection.Find("header > h2 > a").Attr("href")
         tempD.href        =  href

         author           :=     getRegexp(selection.Find("footer > h5 > em").Eq(0).Text(),"作者:(.+)")
         tempD.author   =  author

         ch <- tempD
      })

   }
   close(ch)
   log.Print("获取列表结束")
}

//获取详情数据
func getDetailsData(ch chan Pdata,allData chan Pdata)  {
   for v := range ch{
      href := fmt.Sprintf(v.href)
      index := strings.Index(href, "http")
      if index == -1{
         continue
      }
      resp := getHrefData(href)

      doc, _ := goquery.NewDocumentFromResponse(resp)

      text := doc.Find(".auth1 > section").Text()

      v.text = text
      allData <- v
   }

   close(allData)
   log.Print("获取详情结束")
   
// 这段代码效果一样  
// for{
// if v,ok:=<-ch;ok==true{
//    href := fmt.Sprintf(v.href)
//    index := strings.Index(href, "http")
//    if index == -1{
//       continue
//    }
//    resp := getHrefData(href)
//
//    doc, _ := goquery.NewDocumentFromResponse(resp)
//
//    text := doc.Find(".auth1 > section").Text()
//
//    v.text = text
//    allData <- v
// }else {        //通道关闭
//    //fmt.Println(num)
//    break
// }
//}
//
//close(allData)
//log.Print("获取详情结束")
}

//获取页面数据返回解析
func getHrefData(href string) *http.Response {
   client        := &http.Client{}
   req, err   := http.NewRequest("GET",href, nil)
   if err != nil {
      log.Fatal(err)
   }

   resp, err  := client.Do(req)
   if err != nil {
      log.Fatal(err)
   }
   return resp
}

//通过正则提取数据
func getRegexp(ss,regexpS string) string {
   r, _   := regexp.Compile(regexpS)
   dd        := r.FindStringSubmatch(ss)

   if len(dd) < 2{
      return ""
   }

   return dd[1]

}

func main() {
   ch        := make(chan Pdata,10)
   allData := make(chan Pdata,5)
   var allDataInsert []Pdata

   go getData(ch)//获取第一层的数据
   go getDetailsData(ch,allData)//获取详情的数据

   //这里也可以弄成并发
   for v := range allData{
      allDataInsert = append(allDataInsert, v)
   }

   InsertData(allDataInsert)

   log.Print("结束")
   //log.Print(allData)
}


作者:xTao 分类:LNMP 浏览:2383 评论:0