Go语言爬虫笔记 3


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

Go连接数据库

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

安装mysql数据库包

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

[block]

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

[/block]

数据库连接

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

[highlight lanaguage=”Go”]

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

[/highlight]

创建数据表

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

[block]

//创建数据表
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("创建数据表成功!")
   }
}

[/block]

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

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

插入数据

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

[block]

/*添加数据*/
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("插入数据成功!")
         }
      }
   }
}

[/block]

删除数据

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

[block]

/*删除数据*/
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("删除数据成功!")
      }
   }
}

[/block]

更新数据

[block]
/*更新数据*/
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("更新数据成功!")
      }
   }
}
[/block]

查询数据

[block]
/*查询数据*/
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()
}
[/block]

实战,建立自己的代理池

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

爬取代理

[highlight lanaguage="Go"]
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”)
}


[/highlight]

大概就是下面这个效果

使用代理

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

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

[highlight lanaguage=”Go”]

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


[/highlight]

 

 

 

 

参考文章

1.Golang连接mysql数据库

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

3.SQL教程


文章作者: 小游
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小游 !
  目录