基于golang的爬虫demo,爬取微博用户的粉丝和关注者信息
注意:仅供学习交流,任何非法使用与作者无关!
目录
基于golang的爬虫demo,爬取微博用户的粉丝和关注者信息
一、背景与取材
现在大多数的爬虫程序都是基于python语言编写的,python具有相对完善的网络库,使用起来通俗易懂,特别适合小白入门。而且实现起来的效果也不错,也是爬虫界的实力担当。
博主选择了golang来编写,主要是选取golang支持原生并发,更轻量级的go协程更适合爬虫等高并发的程序。而且各个协程可以通过channel进行数据传输,极大地提高了爬取数据的效率,而这也是众多大厂作为服务器、云服务器开发的后后台编程语言。
好了,不再多说,上代码!
二、找规律
近年来微博为了防止数据被爬取,设置了很多的限制,但是新版本总是要对旧版本兼容那个,所以为了方便起见,使用老版本的API抓取。如下图
点击粉丝跳转到粉丝列表界面。如图
看到一页只能获取10条粉丝数据,然后进行翻页操作,查看翻页是否存在统一的规律。
此时,已经找到规律,页数根据请求的url里的page参数决定,而每页的最大数量是默认不可改变的。
如此可以拼接page参数,进行循环遍历获取每页的数据。
// 主要遍历页数伪代码如下
i = 1, max = 100;
who = 1642634100;
for i=1; i<max; i++{
url = "https://weibo.cn/" + who + "/fans?page=" + i;
r = RequestUrl(url);
res = append(res , r)
}
三、定位HTML的元素
因为要获取粉丝或关注的信息,所以使用网页的审查元素进行元素的定位。
找到后发现信息放在table中,找到第一个是头像,最外面是A标签的头像,可以匹配到用户id,然后下面是用户昵称,下面是粉丝数量。
如此提取对应的匹配元素,前期工作就顺利完成。接下来进入设计、编码阶段。
四、设计过程
1.找到的网页分页规律
https://weibo.cn/1642634100/follow?page=1
https://weibo.cn/1642634100/follow?page=2
找到总页数
<input type="submit" value="跳页" /> 1/20页
2.匹配获取到每个关注者、粉丝
<td valign="top" style="width: 52px"><a href="https://weibo.cn/u/7086871638"><img src="https://tvax1.sinaimg.cn/crop.34.0.201.201.50/007JBN3gly8g8la7ql3xaj306k08daa3.jpg?KID=imgbed,tva&Expires=1573966669&ssig=9MQ8F40iE1" alt="pic" /></a></td>
<td valign="top"><a href="https://weibo.cn/u/7086871638">情感读心</a><br />粉丝13216人<br /><a href="https://weibo.cn/attention/add?uid=7086871638&rl=1&st=dcdea8">关注她</a></td>
3.将抓取到的信息写入文件
五、上代码
注意:抓取信息的前提是有认证信息的,就是要把自己的cookie放进去。微博做了权限,不允许未授权获取用户信息。如下代码中要换成自己的cookie。
package main
import (
"fmt"
"io"
"net/http"
"os"
"regexp"
"strconv"
"strings"
)
type UserInfo struct {
UserId string
UserName string
Gender string
FansCount string
IsFollow string
}
func WriteFile(result, uid, title, fans, path string) {
filename := path + "\\" + title + "_" + uid + "_" + fans + ".txt"
f, err := os.Create(filename)
if err != nil {
fmt.Printf("os.Create err = ", err)
}
f.Write([]byte(result))
f.Close()
}
func GetPageClient(url string) (result string, err error) {
//伪装成浏览器客户端
client := &http.Client{}
req, err1 := http.NewRequest("GET", url, nil)
if err1 != nil {
err = err1
return
}
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36")
req.Header.Set("cookie", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
resp, err2 := client.Do(req)
if err2 != nil {
err = err2
return
}
defer resp.Body.Close()
for {
buf := make([]byte, 1024*4)
n, err := resp.Body.Read(buf)
if n == 0 {
break
}
if err != nil && err != io.EOF {
fmt.Println("resp.Body.Read err = ", err)
break
}
result += string(buf[:n])
}
return
}
func GetWork(uid, fans, path string) {
pageEnd := 1
title := "123"
url1 := "https://weibo.cn/" + uid + "/" + fans + "?page=1"
//fmt.Printf("第%d页%s的url = %s...\n", 1, fans, url1)
result, err := GetPageClient(url1)
if err != nil {
fmt.Println("GetPageClient err", err)
}
//匹配页数
rePage := regexp.MustCompile(`<input type="submit" value="跳页" /> 1/(?s:(.*?))页`)
if rePage == nil {
fmt.Println("regexp.MustCompile err")
}
pageCount := rePage.FindAllStringSubmatch(result, 1)
for _, data := range pageCount {
pageEnd, _ = strconv.Atoi(data[1])
}
//匹配title
reTitle := regexp.MustCompile(`<title>(.*)关注的人</title>`)
if reTitle == nil {
fmt.Println("regexp.MustCompile err")
}
titles := reTitle.FindAllStringSubmatch(result, 1)
for _, datas := range titles {
title = datas[1]
}
var results string
for i := 1; i <= pageEnd; i++ {
url := "https://weibo.cn/" + uid + "/" + fans + "?page=" + strconv.Itoa(i)
//fmt.Printf("第%d页%s的url = %s...\n", i, fans, url)
result, err := GetPageClient(url)
if err != nil {
fmt.Println("GetPageClient err", err)
}
//匹配结果
reUser := regexp.MustCompile(`<td valign="top"><a href="https://weibo.cn/u/(?s:(.*?))">(?s:(.*?))</a>(?s:(.*?))丝(?s:(.*?))人<br/>(?s:(.*?))</td>`)
if reUser == nil {
fmt.Println("regexp.MustCompile err")
}
var tmp UserInfo
userInfo := reUser.FindAllStringSubmatch(result, -1)
for _, data := range userInfo {
tmp.UserId = data[1]
tmp.UserName = data[2]
tmp.FansCount = data[4]
tmp.IsFollow = "false"
if strings.Contains(data[5], "已关注") {
tmp.Gender = "未知"
tmp.IsFollow = "true"
} else if strings.Contains(data[5], "他") {
tmp.Gender = "男"
} else if strings.Contains(data[5], "她") {
tmp.Gender = "女"
}
tmps := "{ UserId:" + tmp.UserId + " , UserName:" + tmp.UserName + " , FansCount:" + tmp.FansCount + " , Gender:" + tmp.Gender + " , IsFollow:" + tmp.IsFollow + " }\n"
results = results + tmps
fmt.Printf("爬取的信息:%+v\n", tmp)
}
}
WriteFile(results, uid, title, fans, path)
}
func main() {
var uid, fans, path, yes string
for {
fmt.Println("输入微博账号")
fmt.Scan(&uid)
fmt.Println("输入爬取关注者、粉丝(如fans、follow)")
fmt.Scan(&fans)
fmt.Println(`请输入保存路径(如C:\Users\Desktop)`)
fmt.Scan(&path)
GetWork(uid, fans, path)
fmt.Println("爬取完成,是否继续爬取?Y/N")
fmt.Scan(&yes)
if yes == "N" || yes == "n" {
break
}
}
}
六、如何获取cookie
打开浏览器,进入微博登录界面,输入正确的用户名密码。实现正常登陆操作获取cookie。
使用浏览器网络分析,拿到请求中的cookie。如下图
七、使用效果
注意:仅供学习交流,任何非法使用与作者无关!