goquery爬虫Boss直聘信息

· · 3284 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

---

title: goquery爬虫Boss直聘信息

tags: go,goquery

author: Clown95

---

#  背景

Hello小伙伴们,在之前的文章中,我们对go的爬虫库goquery进行了简单的介绍,今天我们就来进行一个爬虫BOSS直聘Golang招聘信息的实战项目。

![](https://imgconvert.csdnimg.cn/aHR0cDovL3d3MS5zaW5haW1nLmNuL2xhcmdlLzVmZTc5MTA2bHkxZzI1Z3ZkM2FuOWoyMTVvMHY4anhxLmpwZw?x-oss-process=image/format,png)

# 需求

在写代码之前,我们先了解下我们需要爬取什么内容。

![](https://imgconvert.csdnimg.cn/aHR0cDovL3d3MS5zaW5haW1nLmNuL2xhcmdlLzVmZTc5MTA2bHkxZzI1anh1NjE0dmoyMTQyMDVzd2c5LmpwZw?x-oss-process=image/format,png)

`招聘要求`我们鼠标悬停在列表上,会出现一个悬浮窗里面有`职位描述`

![](https://imgconvert.csdnimg.cn/aHR0cDovL3d3MS5zaW5haW1nLmNuL2xhcmdlLzVmZTc5MTA2bHkxZzI1anpzbmNtYmoyMTVrMG9hdGVqLmpwZw?x-oss-process=image/format,png)

根据网站给出的信息我们可以爬虫到以下内容:

- 工作岗位

- 薪资范围

- 公司地址

- 工作经验

- 学历要求

- 公司名称

- 公司信息

-  招聘要求

# 源文件说明

我们先看一个列表的HTML代码,了解我们需要爬取的内容在哪个标签。

```html

<li>

    <div class="job-primary">

        <div class="info-primary">

            <h3 class="name">

                <a href="/job_detail/6177f4eb544e15f81n172dm8GVI~.html" data-jid="6177f4eb544e15f81n172dm8GVI~" data-itemid="1" data-lid="1rzMXyp7wgw.search" data-jobid="19124190" data-index="0" ka="search_list_1" target="_blank">

                    <div class="job-title">Golang</div>

                    <span class="red">15k-30k</span>

                    <div class="info-detail"></div>

                </a>

            </h3>

            <p>北京 朝阳区 四惠<em class="vline"></em>3-5年<em class="vline"></em>本科</p>

        </div>

        <div class="info-company">

            <div class="company-text">

                <h3 class="name"><a href="/gongsi/a40445e10ec47e2b1Xx83tm-.html" ka="search_list_company_1_custompage" target="_blank">元征科技</a></h3>

                <p>互联网<em class="vline"></em>已上市<em class="vline"></em>1000-9999人</p>

            </div>

        </div>

        <div class="info-publis">

            <h3 class="name"><img src="https://img.bosszhipin.com/beijin/mcs/useravatar/20180828/41c31311d7c965b71e51ad58a3be8eca6a4d2e0010b6eada6c207131ca360c65_s.jpg?x-oss-process=image/resize,w_40,limit_0" />罗女士<em class="vline"></em>HRBP</h3>

            <p></p>

        </div>

        <a href="javascript:;" data-url="/gchat/addRelation.json?jobId=6177f4eb544e15f81n172dm8GVI~&lid=1rzMXyp7wgw.search" redirect-url="/geek/new/index/chat?id=9e2e5060ec68738a1X1729y4EVQ~" target="_blank" class="btn btn-startchat">立即沟通

        </a>

    </div>

</li>

```

通过上面的代码我们可以看到:

- 工作岗位是在div class="info-primary"下面的div class="job-title"

- 薪资范围是在div class="info-primary"下面的span class="red"

- 公司地址+工作经验 +学历要求是在div class="info-primary"下面的p标签

- 公司名称是在div class="info-company"下面的h3 标签class="name"

- 公司信息是在div class="info-company"下面的p标签

-  招聘要求是Json接口有两种方法一是可以直接获取a标签中的json,而是获取a标签中的data-jid属性和data-lid属性拼接json

# 代码编写

1. 浏览器的User-age设置

大部分网站都具备一定的反爬虫能力,最简单的就是判断访问网页的客户端是否是浏览器,所以我们现在需要模拟下浏览器的`User-Agent`

```go

//常见浏览器的User-Agent

var UserAgentList = []string{"Mozilla/5.0 (compatible, MSIE 10.0, Windows NT, DigExt)",

"Mozilla/4.0 (compatible, MSIE 7.0, Windows NT 5.1, 360SE)",

"Mozilla/4.0 (compatible, MSIE 8.0, Windows NT 6.0, Trident/4.0)",

"Mozilla/5.0 (compatible, MSIE 9.0, Windows NT 6.1, Trident/5.0,",

"Opera/9.80 (Windows NT 6.1, U, en) Presto/2.8.131 Version/11.11",

"Mozilla/4.0 (compatible, MSIE 7.0, Windows NT 5.1, TencentTraveler 4.0)",

"Mozilla/5.0 (Windows, U, Windows NT 6.1, en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",

"Mozilla/5.0 (Macintosh, Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11",

"Mozilla/5.0 (Macintosh, U, Intel Mac OS X 10_6_8, en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",

"Mozilla/5.0 (Linux, U, Android 3.0, en-us, Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13",

"Mozilla/5.0 (iPad, U, CPU OS 4_3_3 like Mac OS X, en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",

"Mozilla/4.0 (compatible, MSIE 7.0, Windows NT 5.1, Trident/4.0, SE 2.X MetaSr 1.0, SE 2.X MetaSr 1.0, .NET CLR 2.0.50727, SE 2.X MetaSr 1.0)",

"Mozilla/5.0 (iPhone, U, CPU iPhone OS 4_3_3 like Mac OS X, en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",

"MQQBrowser/26 Mozilla/5.0 (Linux, U, Android 2.3.7, zh-cn, MB200 Build/GRJ22, CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"}

//从上面列表中随机获取一个User-Agent

func GetRandomUserAgent() string {

r := rand.New(rand.NewSource(time.Now().UnixNano()))

return UserAgentList[r.Intn(len(UserAgentList))]

}

```

2. 获取网页

我们爬虫的第一步就是先要获取目标页面的源代码。

```go

func GetHtml(bossurl string) *http.Response {

proxyurl := "http://122.136.212.132:53281"  //代理IP,需要自己更换

proxy, _ := url.Parse(proxyurl)  // 解析代理IP

netTransport := &http.Transport{  //要管理代理、TLS配置、keep-alive、压缩和其他设置,可以创建一个Transport

Proxy:                http.ProxyURL(proxy),

MaxIdleConnsPerHost:  10,

ResponseHeaderTimeout: time.Second*2,  //超时设置

}

client := &http.Client{  //要管理HTTP客户端的头域、重定向策略和其他设置,创建一个Client

Timeout:  time.Second * 2,

Transport: netTransport,

}

req, err := http.NewRequest("GET", bossurl, nil) //NewRequest使用指定的方法、网址和可选的主题创建并返回一个新的*Request。

if err != nil {

log.Println(err)

}

req.Header.Add("User-Agent", models.GetRandomUserAgent()) //模拟浏览器User-Agent

resp, err := client.Do(req) //Do方法发送请求,返回HTTP回复

if err != nil {

log.Println(err)

}

return resp  //返回网页响应

}

```

可以看到代码中,通过`http.Transpor`添加了代理IP,并且设置了超时时间。接着通过`http.Client`创建了一个客户端设置代理IP。为什么需要添加代理IP呢?这是为了防止我们本机的IP,因为访问目标网站过多而被拉黑。简单的来说也是防反爬虫的一种必备方法,我们的代码中只使用了一个代理仅作为演示。在实际开发中,你应该拥有一个代理池能够验证代理的有效性,并随机更换代理。

3. 解析网页内容

网页内容的解析是我们程序的核心,我们使用GoQuery遍历的匹配我们需要的信息。因为使用方都一样,在这边我们侧重说下`招聘需求`的解析。

```go

func ParseHtml(resp *http.Response){

defer resp.Body.Close()

dom, err := goquery.NewDocumentFromReader(resp.Body)

if err != nil {

log.Fatalln(err)

}

dom.Find(".job-primary").Each(func(i int, selection *goquery.Selection) {

time.Sleep(3 * time.Second)                                                  //防止访问次数过于频繁

fmt.Println("公司名称:", selection.Find(".info-company .name").Text())            //公司名称

fmt.Println("公司简介:", selection.Find(".info-company .company-text p ").Text()) //公司简单信息

fmt.Println("招聘岗位:", selection.Find(".info-primary .job-title").Text())      //招聘岗位

fmt.Println("简单信息:", selection.Find(".info-primary p").Text())                // 公司地址+ 工作经验+ 学历要求

fmt.Println("薪资范围:", selection.Find(".info-primary .red").Text())            // 薪资

data_lid, _ := selection.Find(".info-primary a").Attr("data-lid")

data_jid, _ := selection.Find(".info-primary a").Attr("data-jid")

jobJson := fmt.Sprintf("https://www.zhipin.com/wapi/zpgeek/view/job/card.json?jid=%s&lid=%s", data_jid, data_lid)

fmt.Println("招聘要求:", GetJobInfo(jobJson))

fmt.Println()

})

}

```

这段代码可以看出,我们的程序是首先获取到json的两个参数信息`data_jid`和`data_lid`,然后拼接成一个完成的json接口。`GetJobInfo()`函数还未给出,我们稍后在看。

我们随便打开一个josn地址复制内容到`json.cn`解析下,可以看到主要的信息还是一个html。

![](https://imgconvert.csdnimg.cn/aHR0cDovL3d3MS5zaW5haW1nLmNuL2xhcmdlLzVmZTc5MTA2bHkxZzI2bHJhdHEyZ2oyMW1tMTF3ZTFkLmpwZw?x-oss-process=image/format,png)

因此我们先定义一个结构体用来解析json

```go

type JsInfo struct {

Code    int    `json:"code"`

Message string `json:"message"`

ZpData  struct {

HTML string `json:"html"`

} `json:"zpData"`

}

```

然后我们在封装一个`GetJobInfo()`函数进行Json内容的截取。因为json的主要内容是个html信息,所以我们仍然使用GoQery进行爬取。

```go

func GetJobInfo(url string) (string) {

respjson, _ := http.Get(url)

resp_byte, _ := ioutil.ReadAll(respjson.Body)

respHtml := string(resp_byte)

var job models.JsInfo

json.Unmarshal([]byte(respHtml), &job)

dom, err := goquery.NewDocumentFromReader(strings.NewReader(job.ZpData.HTML))

if err != nil {

fmt.Println(err)

}

var s string

dom.Find(".detail-bottom-text").Each(func(i int, selection *goquery.Selection) {

s = selection.Text()

})

return s

}

```

4. 主函数

主函数的内容比较简单,因为BOSS直聘的翻页跳转是通过ur实现的,我们通过for循环遍历10页的内容,并且添加sleep函数,防止访问过于频繁从而导致我们的IP被拉黑。

```go

func main() {

for page := 1; page < 10; page++ {

bossurl := fmt.Sprintf("https://www.zhipin.com/c101010100-p100116/?page=%d&ka=page-%d", page, page)

time.Sleep(3*time.Second) // 增加延时防止网站拉黑IP

resp :=GetHtml(bossurl)

ParseHtml(resp)

}

}

```

# 总结

我们的爬虫小实战到此就完成了,为了防止IP被拉黑,我没有使用并发,有兴趣的小伙伴可以改善下我们的代码。我必须要再次强调,我们在爬虫的时候一定要设置代理IP,因为大部分网站都设置了反爬虫机制,如果我们IP在同一时间内访问次数过多,我们真实的IP会被网站运营商短暂或者永久性拉黑,这会影响到其他用户对网站的正常使用。

最后我们我们看下运行结果。

![](https://imgconvert.csdnimg.cn/aHR0cDovL3d3MS5zaW5haW1nLmNuL2xhcmdlLzVmZTc5MTA2bHkxZzI2bWZ0bnpmc2oyMTFpMTV5YWxxLmpwZw?x-oss-process=image/format,png)


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:

查看原文:goquery爬虫Boss直聘信息

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3284 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传