我们继续进阶,这次我们来连接数据库,然后继续爬代理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 mainimport (
“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.DBfunc 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数据库3.SQL教程