使用go chromedp爬虫 (新)


title: 使用go chromedp爬虫
tags: go,chromedp
author: Clown95


背景

最近小伙伴通过某些手段获取到了别人网站上的会员信息,所以他想让我把会员账号爬取下来。

image

其实网站的内容很简单,但是难就难在不知道怎能控制翻页,它既不是通过url参数进行翻页,也不是通过ajax参数翻页。最终我选择chromedp这个库模拟浏览器操作,进行数据爬取。

其实这个页面的爬取方式我之前已经写过一篇文章,但是进行代码复用的时候,发现chromedp库更新了原来的代码已经不兼容了,因此重新写一篇记录下以防以后还需使用。

这篇文章和之前文章,爬取的内容都是一样,所以我不在详细的说明。

具体实现

设置Cookie

首先我需要使用chromedp设置浏览器Cookie来模拟登录状态

// 任务 主要用来设置cookie ,获取登录账号后的页面
func VisitWeb(url string, cookies ...string) chromedp.Tasks {
    //创建一个chrome任务
    return chromedp.Tasks{
        //ActionFunc是一个适配器,允许使用普通函数作为操作。
        chromedp.ActionFunc(func(ctx context.Context) error {
            // 设置Cookie存活时间
            expr := cdp.TimeSinceEpoch(time.Now().Add(180 * 24 * time.Hour))
            // 添加Cookie到chrome
            for i := 0; i < len(cookies); i += 2 {
                //SetCookie使用给定的cookie数据设置一个cookie; 如果存在,可能会覆盖等效的cookie。
                success, err := network.SetCookie(cookies[i], cookies[i+1]).
                    // 设置cookie到期时间
                    WithExpires(&expr).
                    // 设置cookie作用的站点
                    WithDomain("dl.xzg01.com:83"). //访问网站主体
                    // 设置httponly,防止XSS攻击
                    WithHTTPOnly(true).
                    //Do根据提供的上下文执行Network.setCookie。
                    Do(ctx)
                if err != nil {
                    return err
                }
                if !success {
                    return fmt.Errorf("could not set cookie %q to %q", cookies[i], cookies[i+1])
                }
            }
            return nil
        }),
        // 跳转指定的url地址 
        chromedp.Navigate(url),
    }
}

获取内容

设置好Cookie后,接下来就是获取网站内容,一般获取内容我们使用的是chromedp.Text,这样我们可以直接获取的文本内容。但是这个页面比较坑的地方是它的标签是,我之前获取这个标签的内容怎么都获取不到,所以我折中一下获取标签的Html内容。

翻页的实现,我是通过模拟点击 > 标签来实现的。

image

// 任务 主要执行翻页功能和或者html
func DoCrawler(res *string) chromedp.Tasks {
    return chromedp.Tasks{
        //下面注释掉的 Navigate 不要随便添加,如果添加上每次执行都相当于刷新,这样就永远翻不了页
        //chromedp.Navigate("http://dl.xzg01.com:83/OpRoot/MemberScoreList.aspx?uid=0&op=0&uname=003008"),
        chromedp.Sleep(1000),                // 等待
        chromedp.WaitVisible(`#form1`, chromedp.ByQuery), //等待id=from1页面可见  ByQuery是使用DOM选择器查找
        chromedp.Sleep(2*time.Second),
        // Click 是元素查询操作,它将鼠标单击事件发送到与选择器匹配的第一个元素节点。
        chromedp.Click(`.pagination li:nth-last-child(4) a`, chromedp.ByQuery), //点击翻页
        chromedp.OuterHTML(`tbody`, res, chromedp.ByQuery),        //获取tbody标签的html
    }
}

数据处理

现在我们已经获取到html的内容了,但是我们只需要会员账号,所以我们需要对数据进行处理。

因为tbody标签,goquery无法获取到它的内容,所以我们把tbody替换成table

func ReplaceStr(text string) string {
    return strings.Replace(text, "tbody", "table", -1)
}

可能有用户会使用手机来注册账号,所以我们使用一个函数验证账号是否是手机号码

func IsMobile(text string) bool {
    match,_:=regexp.MatchString(`^((\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][01356789]|[4][579]|[6][2567]))\d{8}$`,text)
    return  match
}

我们还需要把数据保存成文本

func WirteText(savefile string,txt string) {
    f, err := os.OpenFile(savefile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0777)
    if err != nil {
        fmt.Println("os Create error: ", err)
        return
    }
    defer f.Close()
    bw := bufio.NewWriter(f)
    bw.WriteString(txt + "\n")
    bw.Flush()
}

接下来我们就使用goquery来进行数据筛选

func GetAccount(text string) {

    dom, err := goquery.NewDocumentFromReader(strings.NewReader(ReplaceStr(text)))
    if err != nil {
        log.Fatalln(err)
    }
    dom.Find("tr").Each(func(i int, selection *goquery.Selection) {
        s:= selection.Find("td").Eq(6).Text()
        fmt.Println(s)
        WirteText("Acount.txt",s)
        if IsMobile(s) {
            WirteText("Mobile.txt",s)
        }
    })
}

执行

package main

import (
    "chromedp/crawler"
    "chromedp/filtrate"
    "context"
    "github.com/chromedp/chromedp"
    "log"
)

func main() {

    ctx, cancel := chromedp.NewContext(
        context.Background(),
        chromedp.WithLogf(log.Printf),
    )
    defer cancel()

    //执行任务
    url := "http://dl.xzg01.com:83/OpRoot/MemberScoreList.aspx?uid=0&op=0&uname=003008"
    err:= chromedp.Run(ctx, crawler.VisitWeb(url,
        "ASP.NET_SessionId", "zkamxkic4oiuwyc5obzgl2oj",
        "__cfduid", "d04d769b567cbe9e6f24369423b440f0d1575981989",
        "security_session_verify", "af027d69fbfbf4c925819043a50740b5",
    ))
    if err != nil {
        log.Fatal(err)
    }
    var res string
    for i := 1; i < 27170; i++ {
        //执行
        err = chromedp.Run(ctx, crawler.DoCrawler(&res)) //执行爬虫任务
        if err != nil {
            log.Fatal(err)
        }
        filtrate.GetAccount(res)
    }
}

你可能感兴趣的:(使用go chromedp爬虫 (新))