总目标
爬取百度贴吧指定词条搜索结果的多页,并保存指定页面
工作流程
1. 明确目标 Url
2. 发送请求,获取应答数据包。 http.Get(url)
3. 保存文件内容
一、寻找url
来到贴吧首页,F12开启浏览器抓包,随便输入一个词条搜索
抓到搜索后的首页url
https://tieba.baidu.com/f/search/res?ie=utf-8&qw=%E7%8E%8B%E8%80%85
第二页url:
https://tieba.baidu.com/f/search/res?isnew=1&kw=&qw=%CD%F5%D5%DF&rn=10&un=&only_thread=0&sm=1&sd=&ed=&pn=2
第三页url:
https://tieba.baidu.com/f/search/res?isnew=1&kw=&qw=%CD%F5%D5%DF&rn=10&un=&only_thread=0&sm=1&sd=&ed=&pn=3
对比可以发现pn参数为几返回的页面就是第几页
qw参数是搜索的词条,被url强制编码的中文字符
rn是每页显示条数
删去无用参数,得到需要请求的url:
https://tieba.baidu.com/f/search/res?isnew=1&qw=%CD%F5%D5%DF&rn=10&pn=3
二、发送请求(http.Get)
使用http.Get 发起get请求
封装一个get函数,接收要搜索的关键词和页数
并返回爬取的网页body
func get(str string, page int) string {
url := fmt.Sprintf("https://tieba.baidu.com/f/search/res?isnew=1&qw=%s&rn=10&pn=%d", url.QueryEscape(str), page)
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
}
return string(body)
}
三、保存文件
封装一个函数,作为保存文件
func save_file(body string, i int) {
file, err := os.Create("第" + strconv.Itoa(i) + "页.html")
if err != nil {
fmt.Println(err)
}
file.WriteString(body)
file.Close()
}
四、主程序组装
获取用户输入,然后进行爬取和保存
func main() {
var str string
var num1 int
var num2 int
fmt.Println("输入要搜索的关键词")
fmt.Scanln(&str)
fmt.Println("请输入要爬取第几页到第几页 例:1 10")
fmt.Scanln(&num1, &num2)
fmt.Println(str, num1, num2)
for i := 1; i <= num2; i++ {
body := get(str, i)
save_file(body, i)
}
}
直接运行
成功!,由于这个io操作文件导致速度很慢
所以说加入协程
五、加入并发
定义一个 waitgroup、读写锁
加入协程、waitgroup,给io操作加上读写锁
最终代码
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"strconv"
"sync"
)
func get(str string, page int) {
defer wg.Done()
url := fmt.Sprintf("https://tieba.baidu.com/f/search/res?isnew=1&qw=%s&rn=10&pn=%d", url.QueryEscape(str), page)
resp, err := http.Get(url)
if err != nil {
fmt.Println(err)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
}
lock.RLock()
save_file(string(body), page)
lock.RUnlock()
}
func save_file(body string, i int) {
file, err := os.Create("./main/htmls/第" + strconv.Itoa(i) + "页.html")
if err != nil {
fmt.Println(err)
}
file.WriteString(body)
file.Close()
fmt.Println("第" + strconv.Itoa(i) + "页爬取成功")
}
var wg sync.WaitGroup
var lock sync.RWMutex
func main() {
var str string
var num1 int
var num2 int
fmt.Println("输入要搜索的关键词")
fmt.Scanln(&str)
fmt.Println("请输入要爬取第几页到第几页 例:1 10")
fmt.Scanln(&num1, &num2)
fmt.Println(str, num1, num2)
for i := 1; i <= num2; i++ {
wg.Add(1)
go get(str, i)
}
wg.Wait()
}
运行后会发现速度特别快