title: 使用go chromedp爬蟲
tags: go,chromedp
author: Clown95
背景
最近小夥伴通過某些手段獲取到了別人網站上的會員信息,所以他想讓我把會員賬號爬取下來。
其實網站的內容很簡單,但是難就難在不知道怎能控制翻頁,它既不是通過url參數進行翻頁,也不是通過ajax參數翻頁。最終我選擇chromedp
這個庫模擬瀏覽器操作,進行數據爬取。
其實這個頁面的爬取方式我之前已經寫過一篇文章,但是進行代碼複用的時候,發現chromedp
庫更新了原來的代碼已經不兼容了,因此重新寫一篇記錄下以防以後還需使用。
原來的文章 : go使用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
,這樣我們可以直接獲取的文本內容。但是這個頁面比較坑的地方是它的標籤是<tbody></tbody>
,我之前獲取這個標籤的內容怎麼都獲取不到,所以我折中一下獲取<tbody>
標籤的Html內容。
翻頁的實現,我是通過模擬點擊 >
標籤來實現的。
// 任務 主要執行翻頁功能和或者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)
}
}