如何用 Go 實作一個簡單的 PTT 爬蟲

閱讀時間約 9 分鐘


raw-image

👨‍💻 簡介

最近想要透過小實作來撰寫筆記,達到做中學的效果,因此就來實作個小爬蟲順便結合前面學到的package做一個小複習。

建立HTTP Client

Go的net/http package 提供了一個HTTP Client,用來發送各種HTTP請求。

  • http.Get:發送GET請求。
  • http.Post:發送POST請求。
  • http.NewRequest:建立一個新的HTTP請求。

語法如下:

// 發送GET請求
func http.Get(url string) (resp *http.Response, err error)

// 發送POST請求
func http.Post(url, contentType string, body io.Reader) (resp *http.Response, err error)

// 建立一個新的HTTP請求
func http.NewRequest(method, url string, body io.Reader) (*http.Request, error)

常見的Response可以使用以下欄位

type Response struct {
Status string // e.g. "200 OK"
StatusCode int // e.g. 200
Proto string // e.g. "HTTP/1.0"
Header Header
Body io.ReadCloser
...
}

接著看一下io.ReadCloser

type ReadCloser interface {
Reader
Closer
}

可以看到ReadCloser是 interface,接著來看一下Reader

type Reader interface {
Read(p []byte) (n int, err error)
}

Reader也是一個interface,裡面有定義了Read方法,因此可以推測出resp.Body(作為一個 io.ReadCloser)也實現了 io.Reader interface。

package main

import (
"fmt"
"io"
"net/http"
)
func main() {
// 使用 http.Get 發送GET請求
resp, err := http.Get("https://www.example.com")
if err != nil {
fmt.Println("Error:", err)
return
}

// 拿到Body最後要確保有關閉連線
defer resp.Body.Close()

// 語法為func ReadAll(r io.Reader) ([]byte, error)
// 會回傳[]byte,要透過string package轉為string
body, _ := io.ReadAll(resp.Body)
fmt.Println("status code: ", resp.StatusCode)
fmt.Println("body: ")
fmt.Println(string(body))
}

在上面的範例中,簡單的使用http.Get取得網頁的相關資訊。接下來試著寫一個簡單的爬蟲,來爬取ptt。

爬取PTT八卦版標題

1. 建立http client以及自定義請求

client := &http.Client{}
req, err := http.NewRequest("GET", "https://www.ptt.cc/bbs/Gossiping/index.html", nil)
if err != nil {
log.Fatal(err)
}

因為八卦版會有詢問是否年滿18,因此會需要設定cookie,而要設定cookie則必須使用自定義請求的方式,使用自定義請求則必須自己建立client進行請求的發送。

2. 設定cookie

先去網站上看cookie的name跟value為多少

raw-image

接著設定對應的參數

// 設定cookie,可
req.AddCookie(&http.Cookie{Name: "over18", Value: "1"})

3. 發送請求

resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()

使用剛剛建立的client放入自定義請求就可以完成請求的發送並取得回傳。

4. 解析回傳資訊

在進行這一步之前需要先安裝一個 go package,github.com/PuerkitoBio/goquery,主要用來解析html的標籤屬性。

go get github.com/PuerkitoBio/goquery

等一下會用到的方法為

func NewDocumentFromReader(r io.Reader) (*Document, error)

而Document是一個struct

type Document struct {
*Selection
}

要根據css selector下去找資料,可以使用Find方法,而當找到匹配的元素時,對這個元素接著使用Each方法取得相關屬性,像是Text或是Attr等

func (s *Selection) Find(selector string) *Selection
func (s *Selection) Each(f func(int, *Selection)) *Selection

接著依照ptt的網站結構查看title的標籤為div,class為title,而裡面還有一層包著超連結,因此要爬取的路徑就可以依照下面的格式撰寫

doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
log.Fatal(err)
}

// 提取文章標題
doc.Find("div.title a").Each(func(index int, item *goquery.Selection) {
title := item.Text()
fmt.Println(title)
})

以下為完整程式碼

package main

import (
"fmt"
"log"
"net/http"
"github.com/PuerkitoBio/goquery"
)

func main() {
client := &http.Client{}
req, err := http.NewRequest("GET", "https://www.ptt.cc/bbs/Gossiping/index.html", nil)
if err != nil {
log.Fatal(err)
}

// 設定cookie模擬已滿18歲的使用者
req.AddCookie(&http.Cookie{Name: "over18", Value: "1"})

resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()

doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
log.Fatal(err)
}

// 提取文章標題
doc.Find("div.title a").Each(func(index int, item *goquery.Selection) {
title := item.Text()
fmt.Println(title)
})
}

📚Reference

17會員
83內容數
golang
留言0
查看全部
發表第一個留言支持創作者!
Alan的開發者天地 的其他內容
👨‍💻簡介 今天來介紹一個自己開發後端蠻常用的一個 package,promptui,拿來做menu真的很方便,promptui有兩個主要的輸入模式: Prompt:跳出單行使用者輸入。 Select:提供一個選項列表供使用者選擇。
👨‍💻 簡介 在處理string時,正則表達式是一個非常有用的工具。Go語言的regexp package 可以使用正則表達式,用來執行如檢查string是否匹配某個模式、提取匹配的subString等操作。
👨‍💻 簡介 一開始介紹基本資料型別時有稍微提到一點string的處理,今天介紹string的一些操作,像是檢查的功能、修改的功能、比較的功能等等。
👨‍💻 簡介 昨天講到 os package,今天繼續補充 os package底下的 exec package,這個package主要用來執行外部指令和處理指令的輸入和輸出,包括如何設定指令、執行指令以及處理輸出等等。
👨‍💻 簡介 今天快速介紹一下對檔案的操作所使用的package os,包括檔案和資料夾操作等。 檔案和資料夾操作 os package 可以執行各種檔案和資料夾操作,如建立、讀取、寫入、刪除檔案,以及取得資料夾內容等。
👨‍💻簡介 在 Go 語言中,reflect package是用來檢查和操作變數的type、value和struct。常見用法有檢察 type、調用方法,以及修改變數的value。今天簡單介紹 reflect package的主要功能、使用方法和常見用法。
👨‍💻簡介 今天來介紹一個自己開發後端蠻常用的一個 package,promptui,拿來做menu真的很方便,promptui有兩個主要的輸入模式: Prompt:跳出單行使用者輸入。 Select:提供一個選項列表供使用者選擇。
👨‍💻 簡介 在處理string時,正則表達式是一個非常有用的工具。Go語言的regexp package 可以使用正則表達式,用來執行如檢查string是否匹配某個模式、提取匹配的subString等操作。
👨‍💻 簡介 一開始介紹基本資料型別時有稍微提到一點string的處理,今天介紹string的一些操作,像是檢查的功能、修改的功能、比較的功能等等。
👨‍💻 簡介 昨天講到 os package,今天繼續補充 os package底下的 exec package,這個package主要用來執行外部指令和處理指令的輸入和輸出,包括如何設定指令、執行指令以及處理輸出等等。
👨‍💻 簡介 今天快速介紹一下對檔案的操作所使用的package os,包括檔案和資料夾操作等。 檔案和資料夾操作 os package 可以執行各種檔案和資料夾操作,如建立、讀取、寫入、刪除檔案,以及取得資料夾內容等。
👨‍💻簡介 在 Go 語言中,reflect package是用來檢查和操作變數的type、value和struct。常見用法有檢察 type、調用方法,以及修改變數的value。今天簡單介紹 reflect package的主要功能、使用方法和常見用法。
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
今天看到有人在微信po說用大模型翻譯藏文文獻比較,因此想說引用記錄下來,免的之後看不到了。 我目前沒有試用過,大家可以自己試試看! 原文參考自:如何用大模型翻譯藏文文獻 以下正文 1.翻譯品質對比 claude 3.5 sonnet某些層面上比Openai的Gpt4.0要好,對內容有註釋
Thumbnail
碩博士生常常面臨著繁重的研究任務,從文獻收集、實驗設計到論文撰寫,每一個步驟都需要長期規劃。然而,將長期目標分解為可以實踐的步驟卻是一大挑戰。透過「季目標」,你可以有效平衡短期和長期的研究計畫,穩步推進你的學術成就。 ▋季目標的核心意義 季目標可以被視為連接長期學術目標和每週
Thumbnail
最近,我在亞馬遜上購買了一本很有啟發性的書,書名叫《Buy Back Your Time》。這本書的作者是 Dan Martell,他是一位專門為企業創辦人提供諮詢服務的專家。書中提到的很多觀念讓我印象深刻,尤其是「買回你的時間」這個核心概念。 在這篇文章中,我想和大家分享一些關於這本書的
Thumbnail
眾所期待的超級烈空坐終於回歸啦,雖然這一次的是以菁英團體戰的方式來呈現,但有總比沒有好,接下來就跟著Hugo的文章一起來看看活動的詳細資訊吧!
Thumbnail
在結束一整年的社群日大回歸之後,2023年的最後一檔活動也已經公佈啦。總共有分別為期一個禮拜的冬日假期Part1及Part2,期間還有短短兩天的冬日仙境與詭角鹿團體戰日,就跟著Hugo一起來看看吧。
Thumbnail
你是否有過這樣的經驗:你遇到了一個電腦或網路相關的問題,你不知道如何解決,你上網搜尋了一番,卻發現沒有一個答案能夠幫助你?
Thumbnail
不知道如何下筆嗎?用自問自答的方式收集素材吧! 在《九宮格寫作術》一書中,作者推薦用「自問自答」的方式,收集寫文章的材料。 我發現如何用 Notion 這個軟體,更有效的實現九宮格寫作的精神; 就是用 Toggle list 的方式寫下問題,這樣就可以方便收合,讓大綱更清晰。
Thumbnail
你/妳很常要重複註冊同一個產品嗎?也許這個方式會有幫助。
Thumbnail
前言介紹 在 golang 1.16之後官方提供的工具包裡面有個 `embed` 可以使用,這使得把檔案嵌入 golang 的二進制編譯更為容易,以至於方便我們部署一些並非 .go 的副檔名檔案。 這裡要介紹的是如何把 vue 作為前端,編譯至我們的 golang 專案內,起一個網頁服務。 在開始
Thumbnail
我們大部分人描述自己工作內容其實很難用一句話帶過,很多時候會需要一些句型轉折
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
Thumbnail
Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
Thumbnail
今天看到有人在微信po說用大模型翻譯藏文文獻比較,因此想說引用記錄下來,免的之後看不到了。 我目前沒有試用過,大家可以自己試試看! 原文參考自:如何用大模型翻譯藏文文獻 以下正文 1.翻譯品質對比 claude 3.5 sonnet某些層面上比Openai的Gpt4.0要好,對內容有註釋
Thumbnail
碩博士生常常面臨著繁重的研究任務,從文獻收集、實驗設計到論文撰寫,每一個步驟都需要長期規劃。然而,將長期目標分解為可以實踐的步驟卻是一大挑戰。透過「季目標」,你可以有效平衡短期和長期的研究計畫,穩步推進你的學術成就。 ▋季目標的核心意義 季目標可以被視為連接長期學術目標和每週
Thumbnail
最近,我在亞馬遜上購買了一本很有啟發性的書,書名叫《Buy Back Your Time》。這本書的作者是 Dan Martell,他是一位專門為企業創辦人提供諮詢服務的專家。書中提到的很多觀念讓我印象深刻,尤其是「買回你的時間」這個核心概念。 在這篇文章中,我想和大家分享一些關於這本書的
Thumbnail
眾所期待的超級烈空坐終於回歸啦,雖然這一次的是以菁英團體戰的方式來呈現,但有總比沒有好,接下來就跟著Hugo的文章一起來看看活動的詳細資訊吧!
Thumbnail
在結束一整年的社群日大回歸之後,2023年的最後一檔活動也已經公佈啦。總共有分別為期一個禮拜的冬日假期Part1及Part2,期間還有短短兩天的冬日仙境與詭角鹿團體戰日,就跟著Hugo一起來看看吧。
Thumbnail
你是否有過這樣的經驗:你遇到了一個電腦或網路相關的問題,你不知道如何解決,你上網搜尋了一番,卻發現沒有一個答案能夠幫助你?
Thumbnail
不知道如何下筆嗎?用自問自答的方式收集素材吧! 在《九宮格寫作術》一書中,作者推薦用「自問自答」的方式,收集寫文章的材料。 我發現如何用 Notion 這個軟體,更有效的實現九宮格寫作的精神; 就是用 Toggle list 的方式寫下問題,這樣就可以方便收合,讓大綱更清晰。
Thumbnail
你/妳很常要重複註冊同一個產品嗎?也許這個方式會有幫助。
Thumbnail
前言介紹 在 golang 1.16之後官方提供的工具包裡面有個 `embed` 可以使用,這使得把檔案嵌入 golang 的二進制編譯更為容易,以至於方便我們部署一些並非 .go 的副檔名檔案。 這裡要介紹的是如何把 vue 作為前端,編譯至我們的 golang 專案內,起一個網頁服務。 在開始
Thumbnail
我們大部分人描述自己工作內容其實很難用一句話帶過,很多時候會需要一些句型轉折