Go Language Crawler + regelmäßige einfache Verwendung

Vorwort

Viele Leute mögen denken, dass Crawling die ausschließliche Fähigkeit von Python ist, aber tatsächlich kann die Verwendung der Go-Sprache bessere Ergebnisse erzielen

was ist ein reptil

Eine Sache, die wir verstehen müssen, bevor wir mit der Implementierung eines Crawlers beginnen, ist, was ein Crawler ist. Ein Web-Crawler (auch als Web-Spider, Web- Roboter und in der FOAF -Community häufiger als Web-Chaser bezeichnet ) ist ein Programm oder Skript , das nach bestimmten Regeln automatisch Informationen aus dem World Wide Web durchsucht . Andere weniger gebräuchliche Namen sind Ant, Autoindex, Emulator oder Wurm.

Wie schreibt man einen Crawler?

Die folgenden Punkte sind beim Schreiben eines Crawler-Programms zu beachten

  1. Geben Sie die Ziel-URL an

  2. Senden Sie eine Anfrage, erhalten Sie ein Antwortpaket

  3. Filterdaten speichern

  4. Verwenden Sie Analysedaten

Crawler-Implementierung

Die Baidu Tieba-Webseite ist einfach zu crawlen

Nehmen Sie als Beispiel die Chongqing University of Posts and Telecommunications

Laut URL ist zu erkennen, dass hinter der pn jeweils eine 50 extra steht.

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

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

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

Nachdem wir die Regel gefunden haben, können wir sie konkret implementieren.Wir müssen das net/http-Paket verwenden, um die Daten der Seite zu erhalten und sie durch IO-Operation in der Datei zu speichern

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)
}

Durchsuchen Sie die gleichzeitige Version der Baidu Tieba-Webseite

Ein wichtiges Sprachmerkmal der Go-Sprache ist, dass sie von Natur aus hohe Parallelität unterstützt und Crawler und Parallelität perfekt kombiniert werden können.Das Crawlen mit hoher Parallelität kann die Effizienz von Crawlern erheblich verbessern. Die Implementierung von hoher Nebenläufigkeit ist nicht schwierig.Wir müssen nur eine Coroutine starten und sie mit der Haupt-Coroutine synchronisieren.Andere Operationen sind ähnlich wie bei der nicht-nebenläufigen Version.

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)
}

regulären Ausdruck

Ein regulärer Ausdruck , auch bekannt als regulärer Ausdruck , (regulärer Ausdruck, in Code oft als regex, regexp oder RE abgekürzt), ist ein Textmuster, das gewöhnliche Zeichen (z. B. Buchstaben zwischen a und z) und Sonderzeichen ( "Metazeichen" genannt), ein Konzept aus der Informatik . Reguläre Ausdrücke verwenden eine einzelne Zeichenfolge, um eine Reihe von Zeichenfolgen zu beschreiben und abzugleichen, die einer syntaktischen Regel entsprechen, und werden normalerweise verwendet, um Text abzurufen und zu ersetzen, der einem Muster (einer Regel) entspricht.

Viele Programmiersprachen unterstützen die String-Manipulation mit regulären Ausdrücken. Beispielsweise ist eine leistungsstarke Engine für reguläre Ausdrücke in Perl integriert. Das Konzept der regulären Ausdrücke wurde zuerst durch Tools in Unix (wie sed und grep ) populär gemacht und später in Scala, PHP, C#, Java, C++, Objective-c, Perl, Swift, VBScript, Javascript, Ruby, Python weit verbreitet , und mehr. Reguläre Ausdrücke werden normalerweise als "regex" abgekürzt, wobei regexp, regex im Singular und regexps, regexes und regexen im Plural stehen.

Charaktertest

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

Dezimaltest

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-Tab-Test

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

Verwenden Sie reguläre Ausdrücke zum Crawlen von Titeln in Baidu Tieba (hohe Parallelität)

Titel-Regex überprüfen 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)
}

Epilog

Wenn etwas unklar ist, können Sie mir gerne Fragen stellen, und ich werde mein Bestes geben, um sie zu beantworten.

Hier ist meine GitHub-Homepage  github.com/L2ncE

Willkommen bei Follow /Star/Fork

Ich denke du magst

Origin juejin.im/post/7118691494415826975
Empfohlen
Rangfolge