目的:以豆瓣电影为例,爬取整个豆瓣电影静态页面信息
1.获取页面信息
go语言提供了httplib库能够获取静态页面的信息
movieHtml:=httplib.Get("http://douban.com/")
2.分析页面内容,用正则表达式匹配出相应的信息
比如匹配导演信息
该链接的标签
<a href="/celebrity/1025315/" rel="v:directedBy">彼得·海姆斯</a>
写一个model去匹配
//获取导演信息
func GetMovieDirector(movieHtml string) string{
if movieHtml==""{
return ""
}else{
reg:=regexp.MustCompile(`<a.*?rel="v:directedBy">(.*?)</a>`)
result:=reg.FindAllStringSubmatch(movieHtml,-1)
if len(result)==0{
return ""
}
director:=""
for i,_:=range result{
director+=result[i][1]+" "
}
return director
}
}
其他的信息也是如此,主要是正则表达式的运行,这样我们就能够得到一个电影的完整的信息了
获得后存入数据库就行了
3.制作爬虫
上面的是获取一个页面信息,那么怎么自动获得多个信息?
我们知道每个页面有好多个链接能够链接到其他页面,那么在爬取一个页面时候获取该页面的页面信息不就行了。那么我们可以设置一个爬取队列,开始先入队一个初始url,然后爬取该页面信息,爬取完成后在爬取该页面的链接,然后存入到爬取队列,如此循环。然而我们发现,很多链接是重复的,所以设置一个集合,存储爬取的页面,然后每次爬取前检测该url是否已经在爬取完成的集合中,如此便可实现一个简单爬虫。这里是用redis实现的消息队列。
爬虫流程代码
package controllers
import (
"crawl_movie/models"
"fmt"
"github.com/astaxie/beego"
"github.com/astaxie/beego/httplib"
"strings"
"time"
)
type CrawlMovieController struct {
beego.Controller
}
func (c *CrawlMovieController) Get(){
//连接redis
models.ConnectRedis("127.0.0.1:6379")
sUrl:="https://movie.douban.com/subject/33393084/?tag=热门&from=gaia_video"
//存储电影信息
var movieInfo models.MovieInfo
//把初始url加入队列
models.PutinQueue(sUrl)
for{
lenth:=models.GetQueueLength()
//如果队列为空,停止
if lenth==0{
break
}
//成功获取到url
sUrl=models.PopfromQueue()
if models.IsVisit(sUrl){
continue
}
movieHtml:=httplib.Get(sUrl)
//将网页html转换为string
sMovieHtml,err:=movieHtml.String()
if err!=nil{
c.Ctx.WriteString(fmt.Sprintf("err:%v\n",err))
}
movieInfo.Movie_name=models.GetMovieName(sMovieHtml)
//如果当前链接是电影,提取出电影信息并入库
if movieInfo.Movie_name!=""{
c.Ctx.WriteString("正在从"+sUrl+"爬取电影"+movieInfo.Movie_name+"\n")
movieInfo.Movie_release_time=models.GetMovieReleaseTime(sMovieHtml)
movieInfo.Movie_director=models.GetMovieDirector(sMovieHtml)
movieInfo.Movie_main_character=models.GetMainCharacter(sMovieHtml)
movieInfo.Movie_on_time=models.GetOnTime(sMovieHtml)
movieInfo.Movie_country=models.GetMovieCountry(sMovieHtml)
movieInfo.Movie_type=models.GetMovieType(sMovieHtml)
movieInfo.Movie_writer=models.GetMovieWriter(sMovieHtml)
movieInfo.Movie_grade=models.GetMovieMark(sMovieHtml)
movieInfo.Movie_length=models.GetMovieLength(sMovieHtml)
movieInfo.Movie_introduction=models.GetMovieIntroduction(sMovieHtml)
movieInfo.Movie_language=models.GetMovieLanguage(sMovieHtml)
movieInfo.Movie_other_name=models.GetMovieOtherName(sMovieHtml)
/*c.Ctx.WriteString(movieInfo.Movie_release_time+" ")
c.Ctx.WriteString(movieInfo.Movie_director+" ")
c.Ctx.WriteString(movieInfo.Movie_writer+" ")
c.Ctx.WriteString(movieInfo.Movie_main_character+" ")
c.Ctx.WriteString(movieInfo.Movie_type+" ")
c.Ctx.WriteString(movieInfo.Movie_country+" ")
c.Ctx.WriteString(movieInfo.Movie_on_time+" ")
c.Ctx.WriteString(movieInfo.Movie_length+" ")
c.Ctx.WriteString(movieInfo.Movie_grade+" ")
c.Ctx.WriteString(movieInfo.Movie_introduction+" ")
c.Ctx.WriteString(movieInfo.Movie_language+" ")
c.Ctx.WriteString(movieInfo.Movie_other_name+" ")*/
_,err:=models.AddMovie(&movieInfo)
if err!=nil{
panic(err)
}else{
c.Ctx.WriteString(sUrl+"爬取完成\n")
}
}
//获取链接中的url并加入到队列中
movies:=models.GetMovieUrls(sMovieHtml)
//c.Ctx.WriteString(fmt.Sprintf("%v",movies))
for _,url:=range movies{
url=strings.Trim(url,`"`)
models.PutinQueue(url)
//fmt.Println(i,":",url)
}
//将访问过的sUrl记录
models.AddToSet(sUrl)
//每次爬完间隔一会,防止网站封禁你的ip
time.Sleep(2)
//c.Ctx.WriteString(sMovieHtml)
}
c.Ctx.WriteString("end of crawling")
}
redis队列:
数据库:
爬取信息
可以发现在不停的爬取,爬取过程会遇到各种问题,有时候爬着爬着不动了,可能最后全是网站的无用链接了,这时候换个链接继续爬;爬的太频繁一般网站会封禁你一段时间的ip,所以最好还是控制好爬取速度。
项目地址:https://github.com/rj2017211811/crawlMovie