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)
}