go使用chromedp爬蟲(舊)


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


由於chromedp的更新,該文章的代碼已經不兼容,因此我重寫了一篇,並且代碼更爲詳細,小夥伴們可以點擊下面的超鏈接閱讀。

使用go chromedp爬蟲

背景

最近朋友讓我幫忙爬取一個網站上面的數據,當時看到頁面覺得很簡單,雖然有25000多頁,但是網站沒有反爬蟲機制,只要多開幾個協程就行。

當我簡單的爬取第一頁之後,發現url沒有page參數。好吧,查看翻頁的源代碼看看,javascript:__doPostBack('anpDataPager','2') 看到這個翻頁我有點頭疼,是aps寫的後臺,通過js調dll內部跳轉的。

考慮到一般翻頁無非是url和ajax。我又去控制檯查看ajax,打開控制檯選中XHR,結果讓我有點懵逼,根本就沒有ajax。

我當時就打退堂鼓了,但是又考慮到跟朋友一口一個保證,沒辦法硬着頭皮來吧,那就在url上嘗試使用anpDataPager傳參看看,還是不行,那就再換curpage依然不行,當我嘗試了N遍了常用的curpage參數後,這種方法也以失敗告終。

沒法比,答應別人的事情當然得盡力完成,就突發奇想使用按鍵精靈這裏腳本語言,模擬手動操作。因爲需要查找翻頁按鈕操作,我只能前臺運行。但是有一個很棘手的問題,網站所在服務器速度很慢,大概2-4秒才能顯示出數據,而且數據量稍大25675頁,我這模擬下去,我得幾天不幹活。

百度搜索看看有沒有其他大佬遇到過類似的情況,你別說還真有,但是大佬使用的Python 模擬提交form __VIEWSTATE __EVENTTARGET __EVENTARGUMENT __EVENTVALIDATION 這四個數據,我用go模仿大佬的方法不知道怎麼就是不行。

那就在繼續搜索下,看到可以用seleniumchromedp 來模擬瀏覽器操作,最終選擇了chromedp

chromedp 介紹

chromedp包是一種更快,更簡單的方法,可以使用無外部依賴關係(即Selenium,PhantomJS等)來驅動支持Go中的Chrome DevTools協議的瀏覽器 。

安裝

go get -u github.com/chromedp/chromedp

注意:需要安裝chrome瀏覽器或者chromedrive

使用

官方提供的Demo

https://github.com/chromedp/examples

Api查詢地址

https://godoc.org/github.com/chromedp/chromedp

需要爬的內容

<tbody>
                    
                            <tr>
                                <td>1</td>
                                <td>2019/3/22 11:11:31</td>
                                <td>400</td>
                                <td>1,000,000</td>
                                <td>1,000</td>
                                <td>1,000,400</td>
                                <td>aabb123</td>
                                <td> </td>
                                <td>92fox</td>
                                <td>92fox</td>
                                <td>上分</td>
                            </tr>
                        
                        .....
						
                </tbody>

我直接貼上我爬蟲的代碼

package main

import (
	"context"
	"errors"
	"github.com/chromedp/cdproto/cdp"
	"github.com/chromedp/cdproto/network"
	"time"
	"log"
	"github.com/chromedp/chromedp"
)

var res string  // 定義全局變量,用來保存爬蟲的數據

func main() {
	var err error
		
	// 創建鏈接
	ctxt, cancel := context.WithCancel(context.Background())
	defer cancel()
 
 	//創建chrome.New()創建新的chrome實例
	c, err := chromedp.New(ctxt, chromedp.WithLog(log.Printf)) 
	if err != nil {
		log.Fatal(err)
	}
	x, err := chromedp.New(ctxt, chromedp.WithLog(log.Printf))
	if err != nil {
		log.Fatal(err)
	}
	//執行任務
	err = c.Run(ctxt, visitWeb("http://dl.gaggjz.pw:8086/OpRoot/MemberScoreList.aspx?uid=0&op=0&uname=sdafsadsaf"))
	if err != nil {
		log.Fatal(err)
	}
	// 循環翻頁
	for i := 1; i < 25000; i++ {
		//執行
		err = x.Run(ctxt, DoCrawler()) //執行爬蟲任務
		WirteTXT(res)// res的內容寫入文本 
	}

}

// 任務 主要用來設置cookie ,獲取登錄賬號後的頁面
func visitWeb(url string) chromedp.Tasks {

	return chromedp.Tasks{	
		chromedp.ActionFunc(func(ctxt context.Context, h cdp.Executor) error {
			expr := cdp.TimeSinceEpoch(time.Now().Add(180 * 24 * time.Hour))
			success, err := network.SetCookie("ASP.NET_SessionId", "這裏是值"). //設置cookie
				WithExpires(&expr).
				WithDomain("dl.gaggjz.pw:8086"). //訪問網站主體
				WithHTTPOnly(true).
				Do(ctxt, h)
			if err != nil {
				return err
			}
			if !success {
				return errors.New("could not set cookie")
			}

			return nil
		}),
		chromedp.Navigate(url), //頁面跳轉
	}
}
// 任務 主要執行翻頁功能和或者html
func DoCrawler() chromedp.Tasks {

	//sel =fmt.Sprintf(`javascript:__doPostBack('anpDataPager','%s')`,"2")

	return chromedp.Tasks{
		chromedp.Sleep(1*time.Second), // 等待
		chromedp.WaitVisible(`#form1`, chromedp.ByQuery),//等待id=from1頁面可見  ByQuery是使用DOM選擇器查找
		chromedp.Sleep(1*time.Second), 
		chromedp.Click(`.pagination li:nth-last-child(4) a`, chromedp.ByQuery),//點擊翻頁
		chromedp.OuterHTML(`tbody`, &res, chromedp.ByQuery), //獲取改 tbody標籤的html
	}
}


func WirteTXT(txt  string ) {
	f, err := os.OpenFile("1.txt", 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()
}

總結

通過代碼可以看到我創建了chromedp.Tasks 任務,第一個任務主要就是爲了設置cookie即模擬登錄,第二個任務是最重要的,它主要用來點擊下一頁按鈕和獲取指定html內容。因爲第一次接觸chromedp,所以我剛開始把兩個任務放在一個任務裏,就造成了第一頁和第二頁來回跳轉。所以突發奇想創建了2個任務。當然我後來才知道,單獨執行第二個任務的時候,可以手動輸入地址和登錄賬號,程序也是可以執行的,就是有個缺點,執行一段時間可能cookie失效,需要重新登錄。要注意的是chromedp使用的是DOM 原生選擇器,我剛開始看到ByQuery 以爲可以使用JQuery選擇器,一直篩選不到內容。 還有一個坑點就是,我爬取的td標籤是在tbody內的,直接使用chromedp.Text()獲取不到內容,所以退而求次,獲取了html,但是我發現goquery 讀取文本里面的html也不能獲取到td的內容,最後我把tbody替換成table,可以成功的獲取到內容。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章