言語クローラーに行く+通常の簡単な使用

序文

多くの人は、クロールはPythonの排他的なスキルであると考えるかもしれませんが、実際には、Go言語を使用するとより良い結果が得られる可能性があります

爬虫類とは

クローラーの実装を開始する前に理解しなければならないことの1つは、クローラーとは何かということです。Webクローラー(Webスパイダー、Webロボットとも呼ばれ、 FOAFコミュニティではWebチェイサーとも呼ばれます)は、特定のルールに従ってWorldWideWebから情報を自動的にクロールするプログラムまたはスクリプトです。その他のあまり一般的に使用されない名前は、ant、autoindex、emulator、またはwormです。

クローラーの書き方

クローラープログラムを作成する際には、次の点に注意してください。

  1. ターゲットURLを指定します

  2. リクエストを送信し、レスポンスパケットを取得します

  3. フィルタデータを保存する

  4. 分析データを使用する

クローラーの実装

BaiduTiebaのWebページは簡単にクロールできます

例として重慶郵電大学を取り上げます

URLによると、毎回pnの後ろに50が余分にあることがわかります。

tieba.baidu.com/f?kw=%E9%87…

tieba.baidu.com/f?kw=%E9%87…

tieba.baidu.com/f?kw=%E9%87…

ルールを見つけたら、具体的に実装できます。net/ httpパッケージを使用してページのデータを取得し、IO操作でファイルに保存する必要があります。

package main
​
import (
    "fmt"
    "io"
    "net/http"
    "os"
    "strconv"
)
​
func httpGet(url string) (res string, err error) {
    resp, err1 := http.Get(url)
    if err != nil {
        err = err1 //内部错误传出
        return
    }
    defer resp.Body.Close()
​
    //循环读取数据  传出给调用者
    buf := make([]byte, 4096)
    for {
        n, err2 := resp.Body.Read(buf)
        if n == 0 {
            fmt.Println("读取完成")
            break
        }
        if err2 != nil && err2 != io.EOF {
            err = err2
            return
        }
        //累加数据
        res += string(buf[:n])
    }
    return
}
​
func query(start int, end int) {
    fmt.Printf("正在爬取%d页到%d页...\n", start, end)
​
    //循环爬取数据
    for i := start; i <= end; i++ {
        url := "https://tieba.baidu.com/f?kw=%E9%87%8D%E5%BA%86%E9%82%AE%E7%94%B5%E5%A4%A7%E5%AD%A6&ie=utf-8&pn=" + strconv.Itoa((i-1)*50)
        res, err := httpGet(url)
        if err != nil {
            fmt.Println("err = ", err)
            continue
        }
        //保存为文件
        f, err := os.Create("第" + strconv.Itoa(i) + "页" + ".html")
        if err != nil {
            fmt.Println("err = ", err)
            continue
        }
        f.WriteString(res)
        f.Close() //保存好一个文件就关闭一个
    }
}
​
func main() {
    //指定起始终止页
    var start, end int
    fmt.Print("请输入爬取的起始页(>=1):")
    fmt.Scan(&start)
    fmt.Print("请输入爬取的终止页(>=start):")
    fmt.Scan(&end)
​
    query(start, end)
}

BaiduTiebaWebページの同時バージョンをクロールする

Go言語の主な言語機能は、高い同時実行性を自然にサポートし、クローラーと同時実行性を完全に組み合わせることができることです。高い同時実行性でクロールすると、クローラーの効率が大幅に向上します。高並行性の実装は難しくありません。コルーチンを開始してメインコルーチンと同期するだけで済みます。その他の操作は、非並行バージョンと同様です。

package main
​
import (
   "fmt"
   "io"
   "net/http"
   "os"
   "strconv"
)
​
func httpGet(url string) (res string, err error) {
   resp, err1 := http.Get(url)
   if err != nil {
      err = err1 //内部错误传出
      return
   }
   defer resp.Body.Close()
​
   //循环读取数据  传出给调用者
   buf := make([]byte, 4096)
   for {
      n, err2 := resp.Body.Read(buf)
      if n == 0 {
         break
      }
      if err2 != nil && err2 != io.EOF {
         err = err2
         return
      }
      //累加数据
      res += string(buf[:n])
   }
   return
}
​
//爬取单个页面的函数
func spiderPage(i int, page chan int) {
   url := "https://tieba.baidu.com/f?kw=%E9%87%8D%E5%BA%86%E9%82%AE%E7%94%B5%E5%A4%A7%E5%AD%A6&ie=utf-8&pn=" + strconv.Itoa((i-1)*50)
   res, err := httpGet(url)
   if err != nil {
      fmt.Println("err = ", err)
      return
   }
   //保存为文件
   f, err := os.Create("第" + strconv.Itoa(i) + "页" + ".html")
   if err != nil {
      fmt.Println("err = ", err)
      return
   }
   f.WriteString(res)
   f.Close() //保存好一个文件就关闭一个
​
   page <- i //与主协程完成同步
}
​
func query(start int, end int) {
   fmt.Printf("正在爬取%d页到%d页...\n", start, end)
​
   page := make(chan int)
   //循环爬取数据
   for i := start; i <= end; i++ {
      go spiderPage(i, page)
   }
   for i := start; i <= end; i++ {
      fmt.Printf("第%d个页面完成爬取完成\n", <-page)
   }
}
​
func main() {
   //指定起始终止页
   var start, end int
   fmt.Print("请输入爬取的起始页(>=1):")
   fmt.Scan(&start)
   fmt.Print("请输入爬取的终止页(>=start):")
   fmt.Scan(&end)
​
   query(start, end)
}

正規表現

正規表現(正規表現とも呼ばれます)(正規表現コードではregex、regexp、またはREと省略されることが多い)は、通常の文字(たとえば、aとzの間の文字)と特殊文字( 「メタ文字」と呼ばれる)、コンピュータサイエンスの概念。正規表現は、単一の文字列を使用して、構文規則に一致する一連の文字列を記述および一致させ、通常、パターン(規則)に一致するテキストを取得して置換するために使用されます。

多くのプログラミング言語は、正規表現を使用した文字列操作をサポートしています。たとえば、強力な正規表現エンジンがPerlに組み込まれています。正規表現の概念は、 Unixのツール( sedgrepなど)によって最初に普及し、その後、Scala、PHP、C#、Java、C ++、Objective-c、Perl、Swift、VBScript、Javascript、Ruby、Pythonで広く使用されました。 、 もっと。正規表現は通常、「regex」と省略され、regexp、regexは単数形、regexps、regexes、およびregexenは複数形になります。

性格検査

package main
​
import (
    "fmt"
    "regexp"
)
​
func main() {
    str := "abc a7c mfc cat 8ca azc cba"
    //解析
    ret := regexp.MustCompile(`a.c`)
    //提取
    res := ret.FindAllStringSubmatch(str, -1)
    //打印
    fmt.Println(res)
}
//输出
[[abc] [a7c] [azc]]
​
进程 已完成,退出代码为 0

10進テスト

package main
​
import (
    "fmt"
    "regexp"
)
​
func main() {
    str := "3.14 123.123 .68 haha 1.0 abc 7. ab.3 66.6 123."
    //解析
    ret := regexp.MustCompile(`[0-9]+.[0-9]+`)
    //提取
    res := ret.FindAllStringSubmatch(str, -1)
    //打印
    fmt.Println(res)
}
//输出
3.14] [123.123] [1.0] [66.6]]
​
进程 已完成,退出代码为 0

Webタブテスト

package main
​
import (
    "fmt"
    "regexp"
)
​
func main() {
    str := `<div class="wrapper">
                <ul style='margin-left: 3px;' id='main-menu' >
                    <li><a href="index.php">首 页</a></li>
                    <li ><a href="user.php" >个人服务</a></li>                           
                    <li><a href="jwglFiles/index.php" target='_blank'  >教学管理文件</a></li>
                    <li><a href="#">培养方案</a> 
                        <ul>
                            <li><a href="pyfa2020/index.php" target='_blank'>2020版培养方案</a></li>
                            <li><a href="pyfa/index.php" target='_blank'>2016版培养方案</a></li>
                            <li><a href="infoNavi.php?dId=000303" target='_blank'>其他版培养方案</a></li>
                            <li><a href="lxs/pyfa/index.php" target='_blank'>留学生</a></li>
                        </ul>
                    </li>                                                                                                   
                    <li><a href="bszn/index.php" target='_blank'  >办事指南</a></li> 
                    <li><a href="kebiao/index.php"   target='_bank'>课表查询</a></li>
                    <li><a href="jxjc/index.php"  target='_bank'  >进程与调停课</a></li>
                    <li><a href="ksap/index.php"  target='_bank'  >考试安排</a></li>         
                    <li><a href="infoNavi.php?dId=000308"  target='_bank'  >表格下载</a></li>
                    <li><a href="infoNavi.php?dId=000310"  target='_bank'  >校历</a></li>
                    <!--
                    <li ><a href="history/index.php" target="_blank">历史数据</a></li> 
                    <li><a href="websiteNavi.php" class="topMenu" >功能网站</a></li>
                    <li><a href="historyData.php" class="topMenu" >数据中心</a></li>  
                    <li ><a href="jwzxlxs/index.php" target="_blank">留学生</a></li>
                    -->

                    <li><a href="infoNavi.php?dId=0007"  target='_bank'  >党建工作</a></li>
                    <li><a href="contact.php" class="popInfo" >联系我们</a></li>  
                </ul>  
                <div style="float: right;color: rgb(221, 221, 221);padding: 9px 10px;">`
    //解析
    ret := regexp.MustCompile(`<li><a href="(?s:(.*?))"`)
    //提取
    res := ret.FindAllStringSubmatch(str, -1)
    //打印
    for _, one := range res {
        //fmt.Println("one[0]=", one[0])
        fmt.Println(one[1])//返回的是一个数组
    }
}
//输出内容
index.php
jwglFiles/index.php
#
pyfa2020/index.php
pyfa/index.php
infoNavi.php?dId=000303
lxs/pyfa/index.php
bszn/index.php
kebiao/index.php
jxjc/index.php
ksap/index.php
infoNavi.php?dId=000308
infoNavi.php?dId=000310
websiteNavi.php
historyData.php
infoNavi.php?dId=0007
contact.php

Baidu Tiebaでタイトルをクロールするために正規表現を使用する(同時実行性が高い)

タイトルの正規表現を確認してください class="j_th_tit ">(?s:(.*?))</a>

package main
​
import (
    "fmt"
    "io"
    "net/http"
    "os"
    "regexp"
    "strconv"
)
​
func httpGet(url string) (res string, err error) {
    resp, err1 := http.Get(url)
    if err != nil {
        err = err1 //内部错误传出
        return
    }
    defer resp.Body.Close()
​
    //循环读取数据  传出给调用者
    buf := make([]byte, 4096)
    for {
        n, err2 := resp.Body.Read(buf)
        if n == 0 {
            break
        }
        if err2 != nil && err2 != io.EOF {
            err = err2
            return
        }
        //累加数据
        res += string(buf[:n])
    }
    return
}
​
func saveFile(i int, title [][]string) {
    f, err := os.Create("第" + strconv.Itoa(i) + "页.txt")
    if err != nil {
        fmt.Println("err = ", err)
        return
    }
    defer f.Close()
    n := len(title)
    for i := 0; i < n; i++ {
        f.WriteString(title[i][1] + "\n")
    }
}
​
//爬取单个页面的函数
func spiderPage(i int, page chan int) {
    url := "https://tieba.baidu.com/f?kw=%E9%87%8D%E5%BA%86%E9%82%AE%E7%94%B5%E5%A4%A7%E5%AD%A6&ie=utf-8&pn=" + strconv.Itoa((i-1)*50)
    res, err := httpGet(url)
    if err != nil {
        fmt.Println("err = ", err)
        return
    }
​
    ret := regexp.MustCompile(`class="j_th_tit ">(?s:(.*?))</a>`)
    titles := ret.FindAllStringSubmatch(res, -1)
    saveFile(i, titles)
    page <- i //与主协程完成同步
}
​
func query(start int, end int) {
    fmt.Printf("正在爬取%d页到%d页...\n", start, end)
​
    page := make(chan int)
    //循环爬取数据
    for i := start; i <= end; i++ {
        go spiderPage(i, page)
    }
    for i := start; i <= end; i++ {
        fmt.Printf("第%d个页面完成爬取完成\n", <-page)
    }
}
​
func main() {
    //指定起始终止页
    var start, end int
    fmt.Print("请输入爬取的起始页(>=1):")
    fmt.Scan(&start)
    fmt.Print("请输入爬取的终止页(>=start):")
    fmt.Scan(&end)
​
    query(start, end)
}

エピローグ

ご不明な点がございましたら、お気軽にご質問ください。できる限りお答えいたします。

これが私のGitHubホームページ github.com/L2ncEです

/ Star/Forkをフォローする皆さんを歓迎します

おすすめ

転載: juejin.im/post/7118691494415826975