『Go 语言实现简易爬虫:市值前100数字货币交易信息』

大家好,我是谢伟,一名程序员。之前接触的语言是Python, 编程领域学会的第一个技能是『爬虫』,凭借着爬虫技术先后在两个创业公司从事的是『网络爬虫』这份活。

研究生毕业后,基于各方面的考虑,选择的是现在的这份工作。主要的是从事『云计算』方面的工作,再细化点,主要从事云计算中的 PaaS 部署相关的工作。

目前正在着手的任务是开发一款命令行工具。支持 PaaS 部署相关的各种命令,且开发语言是 go。

我熟悉的是 Python ,借着之前的编程基础,顺利的转到了 go 语言。很自觉的会比较两款语言的相似和不同之处。同时我越来越理解到:『编程语言只是工具』这句话的含义。

  • 编程语言只是工具

    编程最重要的是逻辑,不管是什么领域的开发,逻辑才是最重要的。所以『架构师』这一职业,对逻辑的要求就很高,他需要技术选型、方案设计、方案评估等一系列技能。

    编程只是实现或者验证方案是否合适。

    逻辑很重要。

  • 示例很重要

    这是我从 Python 转而学习 go 语言中总结出来的经验。为了了解各种各样的 go 语言的特性,我有一个工程专门用来进行 go 编程语言示例的学习。即:想要验证一个库或者函数的时候,达到你需要的效果,最好的方法是进行最小示例的验证。

    比如:之前开发命令行工具需要支持查询命令表格显示这一功能。就不断的使用示例的学习方法快速上手,快速开发。

  • 快速上手

    企业需要的职员是来干活的,需要产出价值,完成任务的。并没有过多的时间让你学习。需要的是快速上手的能力。前期可以有短暂的输入时间。之后需要边输入边产出。快速上手,实现价值交付。

  • 不断的修改

    编程不可能一步到位,除非你是传说中的编程天才。代码需要不断的修改,修改的同时对编程语言各种熟悉,同时需要不断的完善代码,能复用的就复用。函数应该是编程中最常见的了,函数不能编写过长。凡是稍微有点处理动作的都应该独立出一个函数进行复用。主函数的处理动作应该是越简单明了越好。不管是以后重构还是增加功能都能很好的实现。

  • 学习各种编程思想

    随着系统的越来越复杂,一定需要学习软件行业先进的编程思想,解决复杂的问题,比如 DDD (领域驱动开发), TDD(测试驱动开发)..., 这是我下一个的研究点...

  • 总结很重要

    内部是会有各种各样的会议:计划会、总结会、迭代会、复盘会...,等等,所以导致一天其实真正的开发时间并不是很多,其中还会被各种各样的干扰而导致中断,最终的编程效率其实不是很高,自身除了需要进行合理的时间管理之外,我觉得总结很重要,这些会一般是针对团队的,你需要和自己真正的扯上关系才能不断的成长,比如:迭代总结会,通常是分析团队的任务的完成率,做的好的地方和不好的地方,针对你个人你也应该不断的总结自己好的地方和不好的地方,不然,时间过的很快,嗖的一下几年过去了,得不到应有的成长。


言归正传:下面使用 go 语言实现一个简单的爬虫。已经有了 python 爬虫技能,为什么需要进行 go 爬虫的实现版?为了更加的熟悉 go 的语言特性。

我们已经知道:一个简易的标准爬虫的步骤是

  • HTTP 获取网页内容
  • 进行网页内容解析
  • 对解析的内容进行处理

获取网页内容:

使用 HTTP 不同动作获取网页内容

网页内容解析:

正则表达式或者各种解析工具

解析的内容的处理:

文件处理、数据库处理等

最近数字货币很火,当然风险也很大,这里我们不谈数字货币。我们的目标是爬虫市值前100 的数字货币的相关信息。

抓取网站:https://www.feixiaohao.com/

抓取内容:0、排名 1、名称 2、流通市值 3、价格 4、流通数量 5、成交额 6、涨幅

效果:输出市值前 100 的数字货币的上述7个字段的信息

定义结构体

表示某个数字货币的信息。

type CoinInfo struct {
    Rank         string `json:"rank"`
    Name         string `json:"name"`
    CurrentCount string `json:"current_count"`
    CurrentPrice string `json:"current_price"`
    CurrentMark  string `json:"current_mark"`
    Count        string `json:"count"`
    Change       string `json:"change"`
}

获取网页内容

  • net/http
func (h *HttpClientImpl) Get(url string) ([]byte, error) {
    client := &http.Client{}
    req, err := httpclient.NewRequest("GET", url, nil)
    if err != nil {

        return nil, err
    }

    resp, err := client.Do(req)
    if err != nil {

        return nil, err
    }

    defer resp.Body.Close()
    respBody, err := ioutil.ReadAll(resp.Body)
    if err != nil {

        return nil, err
    }

    if resp.StatusCode < 200 || resp.StatusCode >= 300 {
        err = errors.New("GET: http client.Do[" + url + "] response error, status code: " +
            string(resp.StatusCode) + ", response body: " + string(respBody))
        //log.Error("infra", err)
        return respBody, err
    }
    return respBody, nil
}

  • goquery : 解析网页的库

第三方库,需要自己安装

doc, err := goquery.NewDocument("https://www.feixiaohao.com/")

解析网页内容

以网页源代码中的一个数字货币为例:

<tr id="bitcoin">
    <td>1</td>
    <td>
        <a href="/currencies/bitcoin/"  target="_blank">
            <img src="//static.feixiaohao.com/coin/7033f2f2c2a16094bbb3bafc47205ba8_small.png" alt="BTC-比特币">BTC-比特币
        </a>
    </td>
    
    <td  class="market-cap" data-usd="134254523787" data-cny="844272998288" data-btc="16887331">¥8,443亿 </td> 
        <td><a href="/currencies/bitcoin/#markets"  target="_blank" class="price" data-usd="7964" data-cny="50081"  data-btc="1">¥50,081</a></td>
        <td>1,686万</td>
        <td><a href="/currencies/bitcoin/#markets"  target="_blank" class="volume" data-usd="7039549769.62554"  data-cny="44268915134.0379" data-btc="888529.229834415">¥4,426,892万</a></td>
         <td class="change">
             <span  class="text-red">-9.65%</span>
        </td>
                                        <td class="char">
                <span class="line2" data-peity='{"stroke": "#3ca316"}'>8782,8484,8375,8298,7750,7356,6876,6088,6467,7053,7657,7483,8271,8106,7774,8171,8589,8321,8305,8002,8319,8493,8631,8980,8677,8496,8613,8080</span>
                                  

则:各字段解析如下:

doc.Find("table tbody tr").Each(func(i int, selector *goquery.Selection) {
    var data CoinInfo
    Rank := selector.Find("td").Eq(0).Text()
    CoinName := strings.TrimSpace(selector.Find("td").Eq(1).Text())
    CurrentCount := selector.Find("td").Eq(2).Text()
    CurrentPrice := selector.Find("td").Eq(3).Text()
    CurrentMark := selector.Find("td").Eq(4).Text()
    Count := selector.Find("td").Eq(5).Text()
    Change := strings.TrimSpace(selector.Find("td").Eq(6).Text())

不懂的可以看看goquery 函数方法,结合网页源代码一起看。

json 格式输出

Data, _ := json.MarshalIndent(allData, "", "  ")
fmt.Println(string(Data))

全部代码:注意核心代码很少

type CoinInfo struct {
    Rank         string `json:"rank"`
    Name         string `json:"name"`
    CurrentCount string `json:"current_count"`
    CurrentPrice string `json:"current_price"`
    CurrentMark  string `json:"current_mark"`
    Count        string `json:"count"`
    Change       string `json:"change"`
}

func queryExampleTwo() {
    doc, err := goquery.NewDocument("https://www.feixiaohao.com/")
    if err != nil {
        log.Fatal(err)
    }
    var allData []CoinInfo
    doc.Find("table tbody tr").Each(func(i int, selector *goquery.Selection) {
        var data CoinInfo
        Rank := selector.Find("td").Eq(0).Text()
        CoinName := strings.TrimSpace(selector.Find("td").Eq(1).Text())
        CurrentCount := selector.Find("td").Eq(2).Text()
        CurrentPrice := selector.Find("td").Eq(3).Text()
        CurrentMark := selector.Find("td").Eq(4).Text()
        Count := selector.Find("td").Eq(5).Text()
        Change := strings.TrimSpace(selector.Find("td").Eq(6).Text())
        data = CoinInfo{
            Rank:         Rank,
            Name:         CoinName,
            CurrentCount: CurrentCount,
            CurrentPrice: CurrentPrice,
            CurrentMark:  CurrentMark,
            Count:        Count,
            Change:       Change,
        }
        allData = append(allData, data)
    })
    Data, _ := json.MarshalIndent(allData, "", "  ")
    fmt.Println(string(Data))
}

结果:

[
  {
    "rank": "1",
    "name": "BTC-比特币",
    "current_count": "¥8,444亿 ",
    "current_price": "¥50,091",
    "current_mark": "1,686万",
    "count": "¥4,413,172万",
    "change": "-9.84%"
  },
  {
    "rank": "2",
    "name": "ETH-以太坊",
    "current_count": "¥4,902亿 ",
    "current_price": "¥5,025",
    "current_mark": "9,755万",
    "count": "¥1,749,536万",
    "change": "-9.68%"
  },
  {
    "rank": "3",
    "name": "XRP-瑞波币",
    "current_count": "¥2,335亿 ",
    "current_price": "¥5.98",
    "current_mark": "3,902,901万*",
    "count": "¥1,765,933万",
    "change": "-15.33%"
  },
  ...
 ]

上文就是一个简易的爬虫示例,主要使用的是goquery 这个解析网页的第三方库的使用,更多的用法和其他的第三方库差不多,甚至你能看出各种编程语言的相通之处。

除此之外,希望你能更加理解:编程语言只是工具。这句话的含义。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容