Go语言爬虫笔记 3

文章目录[x]
  1. 1:Go连接数据库
  2. 1.1:安装mysql数据库包
  3. 1.2:数据库连接
  4. 1.3:创建数据表
  5. 1.4:插入数据
  6. 1.5:删除数据
  7. 1.6:更新数据
  8. 1.7:查询数据
  9. 2:实战,建立自己的代理池
  10. 2.1:爬取代理
  11. 3:使用代理
  12. 4:参考文章

我们继续进阶,这次我们来连接数据库,然后继续爬代理ip网站,做一个简易的代理池功能。

Go连接数据库

数据库我们使用MySQL,来简单实现一下增删改查功能。

安装mysql数据库包

只需要一行命令即可安装包

go get -u github.com/go-sql-driver/mysql

数据库连接

这里同样拿代码作为例子,注释里面解释。

package main
import (
   "database/sql" //这个是Go自带的sql命令,我们还需要导入驱动才能正常运行
   "fmt"
   _"github.com/Go-SQL-Driver/MySQL" //这里我们导入驱动
   "strings"
)
//这里定义几个常量,作为数据库连接使用
const (
   userName = "proxy"
   password = "12345678"
   ip = "192.168.123.64"
   port = "3306"
   dbName = "proxy"
)

//Db数据库连接池
var DB *sql.DB

func main()  {
   InitDB()
}

//注意方法名大写
func InitDB()  {
   //构建连接:"用户名:密码@tcp(IP:端口)/数据库?charset=utf8"
   path := strings.Join([]string{userName, ":", password, "@tcp(",ip, ":", port, ")/", dbName, "?charset=utf8"}, "")
   //打开数据库,前者是驱动名,所以要导入: _ "github.com/go-sql-driver/mysql"
   DB, _ = sql.Open("mysql", path)
   //设置数据库最大连接数
   DB.SetConnMaxLifetime(100)
   //设置上数据库最大闲置连接数
   DB.SetMaxIdleConns(10)
   //验证连接
   if err := DB.Ping(); err != nil{
      fmt.Println("opon database fail")
      return
   }
   fmt.Println("connnect success")
}

创建数据表

参考文章里面没有创建表的介绍,不过我们可以利用自己学过的知识来简单尝试一下。

//创建数据表
func createTable() {
   tx,err:= DB.Begin()//获取数据库
   if(err!=nil){
      log.Fatal("数据库初始化失败")
   }
   _,err=tx.Exec("CREATE TABLE proxy (id int PRIMARY KEY,ip varchar(255),port varchar(10));")//这里是初始化命令
   err=tx.Commit() //这里是提交
   if(err==nil){
      log.Fatal("创建数据表成功!")
   }
}

注意,上面这个函数是在我前面连接数据库的基础上才可以实现。

看看效果(不得不感慨Go语言在那么高效率下依旧可以那么简单,不愧被誉为互联网语言):

插入数据

数据库的几大操作:增删改查,我们先来添加数据。同样只演示一段代码。

/*添加数据*/
func InsertData(ip string,port string) {
   //开启事务
   tx,err:=DB.Begin()
   if(err!=nil){
      //log.Fatal会返回一个错误警告,然后退出程序
      log.Fatal("开启事务失败")
   }
   //准备SQL语句(这里我们使用另一个方法连接数据库)
   stmt,err:=tx.Prepare("INSERT INTO proxy (ip,port) VALUES (?,?);")
   if err==nil{
      //没有错误就执行下面的语句(传递到sql语句中并准备执行)
      _,err=stmt.Exec(ip,port)
      if(err==nil){
         //提交事务
         err=tx.Commit()
         if(err==nil){
            fmt.Println("插入数据成功!")
         }
      }
   }
}

删除数据

说实话,其实这些操作都是一样的,因为我们都是直接执行SQL语句,所以我们只要熟练的掌握数据库的一些命令,要做这些事情就很简单了。

/*删除数据*/
func DeleteData(id int){
   tx,err:=DB.Begin()
   if(err!=nil){
      log.Fatal("开始事务失败")
   }
   _,err=tx.Exec("DELETE FROM proxy WHERE id=?",id)
   if(err==nil){
      err=tx.Commit()
      if(err==nil){
         fmt.Println("删除数据成功!")
      }
   }
}

更新数据

/*更新数据*/
func UpdateData(id int,ip string,port string){
   tx,err:=DB.Begin()
   if(err!=nil){
      log.Fatal("Error")
   }
   _,err=tx.Exec("UPDATE proxy SET ip=?,port=? WHERE id=?;",ip,port,id)
   if(err==nil){
      err=tx.Commit()
      if(err==nil){
         fmt.Println("更新数据成功!")
      }
   }
}

查询数据

/*查询数据*/
func QueryData(id int){
   //查询多行数据
   rows,err:=DB.Query("SELECT * FROM proxy")
   if err!=nil{
      log.Fatal("查询失败")
   }
   //把所有的数据都打印出来
   for rows.Next(){
      var id int
      var name,port string
      //把查询到的数据都赋值
      err=rows.Scan(&id,&name,&port)
      //打印数据
      if err==nil{
         fmt.Println(strconv.Itoa(id)+"."+name+":"+port)
      }
   }
   fmt.Println("---------")
   var name,port string
   //查询单行数据
   rows,err=DB.Query("SELECT ip,port FROM proxy WHERE id=?;",id)
   if(err==nil){
      rows.Next()
      err=rows.Scan(&name,&port)
      if(err==nil){
         fmt.Println(name+":"+port)
      }
   }
   err=DB.Close()
}

实战,建立自己的代理池

这里我们要分成两个部分,一部分是自己把所有的有用的代理到保存到我们的数据库内,还有一部分就是自己获取我们数据库内的数据进行代理。

爬取代理

package main

import (
   "database/sql"
   "fmt"
   _ "github.com/Go-SQL-Driver/MySQL" //这里我们导入驱动
   "github.com/gocolly/colly"
   "log"
   "strconv"
   "strings"
   "sync"
)

const (
   userName = "proxy"
   password = "12345678"
   ip = "192.168.123.64"
   port = "3306"
   dbName = "proxy"
)
//这里使用多线程来测试代理ip(使用waitgroup)
var wg=sync.WaitGroup{}
//数据库连接池
var DB *sql.DB

func main(){
   //先初始化数据库连接
   initDB()
   c:=colly.NewCollector()
   id:=1
   c.UserAgent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36"
   c.OnHTML("*",func(e *colly.HTMLElement) {
      //我们把所有的代理都放到一个数组里面
      var list []string
      e.ForEach(".odd", func(i2 int, e2 *colly.HTMLElement) {
         var ip string
         var port string
         e2.ForEach("td", func(i int, element *colly.HTMLElement) {
            //第一个获取的是ip,第二个是端口
            if i==1{
               ip=element.Text
            }else if i==2{
               port=element.Text
            }
         })
         list=append(list,"http://"+ip+":"+port)
      })
      //设置线程的数量
      wg.Add(len(list))
      //把获取到的所有的数据依次加到线程里面
      for i:=0;i< len(list);i++{
         go TestProxy(list[i])
      }
      //等待线程执行完成
      wg.Wait()
      //爬取下一页数据
      id++
      fmt.Println("-----开始爬取第"+strconv.Itoa(id)+"页数据-----")
      err:=e.Request.Visit("https://www.xicidaili.com/wt/"+strconv.Itoa(id))
      if(err!=nil){
         fmt.Println("进入下一页失败!")
      }
   })
   err:=c.Visit("https://www.xicidaili.com/wt/"+strconv.Itoa(id))
   if(err!=nil){
      log.Fatal(err)
   }
}

/*检测代理是否可用*/
func TestProxy(proxy string){
   c2:=colly.NewCollector()
   //设置代理
   err:=c2.SetProxy(proxy)
   if(err!=nil){
      fmt.Println("代理设置失败!")
   }
   //这里获取状态码然后判断是否代理成功
   c2.OnResponse(func(r *colly.Response) {
      fmt.Println(proxy+"状态码:"+strconv.Itoa(r.StatusCode))
      if(r.StatusCode==200){
         SaveData(proxy)
      }
   })
   err=c2.Visit("http://www.baidu.com")
   //这里说明线程执行完毕
   wg.Done()
}

/*把代理保存到数据库内*/
func SaveData(proxy string){
   tx,err:=DB.Begin()
   if(err==nil){
      id,err:=tx.Exec("INSERT INTO proxy (proxy) VALUES (?)",proxy)
      if(err==nil){
         err=tx.Commit()
         fmt.Println(id.LastInsertId())
      }
   }
}

/*数据库初始化*/
func initDB(){
   //构建连接:"用户名:密码@tcp(IP:端口)/数据库?charset=utf8"
   path := strings.Join([]string{userName, ":", password, "@tcp(",ip, ":", port, ")/", dbName, "?charset=utf8"}, "")
   //打开数据库,前者是驱动名,所以要导入: _ "github.com/go-sql-driver/mysql"
   DB, _ = sql.Open("mysql", path)
   //设置数据库最大连接数
   DB.SetConnMaxLifetime(100)
   //设置数据库最大闲置连接数
   DB.SetMaxIdleConns(10)
   //验证连接
   if err := DB.Ping(); err != nil{
      fmt.Println("opon database fail")
      return
   }
   fmt.Println("connnect success")
}

大概就是下面这个效果

使用代理

上面我们爬了30几页的数据,实际有用的只有20几个,而且估计再次使用的使用的时候估计没有几个有用。不管怎么样,我们来测试一波

不过感觉好像没用。。。可能是我爬的ip都已经失效了吧。。。

package main

import (
   "database/sql"
   "fmt"
   _ "github.com/Go-SQL-Driver/MySQL" //这里我们导入驱动
   "github.com/gocolly/colly"
   "github.com/gocolly/colly/proxy"
   "strings"
   "sync"
)

const (
   userName = "proxy"
   password = "12345678"
   ip = "192.168.123.64"
   port = "3306"
   dbName = "proxy"
)
//这里使用多线程来测试代理ip(使用waitgroup)
var wg=sync.WaitGroup{}
//数据库连接池
var DB *sql.DB

func main(){
   //先初始化数据库连接
   initDB()
   list:=GetData()
   //创建一个字符串保存所有的代理
   var proxys string
   //遍历数组,然后拼接字符串
   for _,proxy:=range list{
      proxys+=("\""+proxy+"\",")
   }
   fmt.Println(proxys)
   //允许重复访问同一个地址
   c:=colly.NewCollector(colly.AllowURLRevisit())
   //这里随机切换代理(也可以理解自己建立一个ip池)
   if p,err:=proxy.RoundRobinProxySwitcher(proxys);err==nil{
      //设置代理
      c.SetProxyFunc(p)
   }
   c.UserAgent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36"
   //这里对数据进行简单处理
   c.OnHTML(":contains('从国内测试') :first-child",func(e *colly.HTMLElement) {
      e.ForEach("p", func(i int, e2 *colly.HTMLElement) {
         if i==0{
            //把ip地址打印出来
            fmt.Print(e2.Text)
         }
      })
   })
   for i := 0; i < 5; i++ {
      _=c.Visit("http://ip111.cn/")
   }
}

/*获取数据库的所有数据*/
func GetData() []string{
   var list []string
   var data string
   rows,err:=DB.Query("SELECT proxy FROM proxy")
   if err==nil{
      for rows.Next(){
         err=rows.Scan(&data)
         if err==nil{
            //把查询到的数据加到数组里面
            list=append(list,data)
         }
      }
   }
   return list
}

/*数据库初始化*/
func initDB(){
   //构建连接:"用户名:密码@tcp(IP:端口)/数据库?charset=utf8"
   path := strings.Join([]string{userName, ":", password, "@tcp(",ip, ":", port, ")/", dbName, "?charset=utf8"}, "")
   //打开数据库,前者是驱动名,所以要导入: _ "github.com/go-sql-driver/mysql"
   DB, _ = sql.Open("mysql", path)
   //设置数据库最大连接数
   DB.SetConnMaxLifetime(100)
   //设置数据库最大闲置连接数
   DB.SetMaxIdleConns(10)
   //验证连接
   if err := DB.Ping(); err != nil{
      fmt.Println("opon database fail")
      return
   }
   fmt.Println("connnect success")
}

 

 

 

 

参考文章

1.Golang连接mysql数据库

2.golang学习之旅:使用go语言操作mysql数据库

3.SQL教程

点赞

发表评论

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像

Title - Artist
0:00