腾讯招聘爬虫

一、网站分析

1、确定网站的类型(动态/静态)

-  查看以下页面的网页源代码,发现里面全是一些JS文件的路径,而并无实际的页面数据,则判定当前网站为【动态】页面。

 

2、确定数据传递方式

- 对于动态网页数据都是AJAX技术使用XHR对象实现的,数据以JSON格式的数据传递,本例以 Chrome浏览器的控制台 来进行数据的抓包,则右击【检查】--> 直接切换至【Network】 --> 选项卡中的【XHR】,来查看哪些请求中是包含了关于职业的相关信息数据。

 

3、确定请求URL与请求信息

- 查看当前包含数据的URL地址及请求方式:

- ① 表示包含请求数据的URL;② 表示请求的方法。

- 查看请求头信息【headers:用于伪装当前请求是否为爬虫】:

 

参数解读】通过多次分析(详细分析不再一一赘述,请按照分析结果自行查询):

timestamp:1605619289180【明显是:13位的时间戳,Python实现方法:int(time.time()*1000)

countryId:1 【表示左侧 国家/地区 编号】

cityId:1 【表示左侧 城市 编号】

- bgIds:29294 【表示左侧 事业 编号 】

- productId: 【这个多次选择之后,发现没有什么编号,一直是为空值】

- categoryId: 40001001,40001002,40001003,40001004,40001005,40001006 【表示左侧 职业类别 编号】

- parentCategoryId:  【表示父分类的编号,如技术、产品、设计等】

- attrId:  1 【表示招聘类型,社招之类,可以用于控制,灵活搜索查询类别】

- keyword:  python 【表示查询关键字,可以用于控制,灵活搜索查询职位】

- pageIndex: 1 【表示当前的页码,可以控制页码】

- pageSize: 10 【表示每页数量,每页10条数据(固定不变)】

- language: zh-cn 【语言,表示当前的使用的语言(固定不变)】

- area:cn  【貌似是表示中国(固定不变)】

总结】一级页码请求的URL地址:‘https://careers.tencent.com/tencentcareer/api/post/Query?timestamp={}&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword={}&pageIndex={}&pageSize=10&language=zh-cn&area=cn',只需传入时间戳查询职位查询的页码 3个参数(其他参数自定义,本文章不做过多的构建阐述)。

 

4、分析职位的数量

- 通过设置查询的关键字,可以得到查询的结果数据;如果需要爬取多页,则需要分析出当前页面中共有多少条数据结果?也就可以循环对应的次数实现

- 例如:以上搜索了【爬虫】相关的职位,腾讯招聘为我们提供的招聘数据只有 7条,而我们需要关注当前招聘的总数在 XHR 中的一个请求中的,所以我们要实现的是找到对应的请求,获取总条数值,方便我们在后面进行循环,实现多页的爬取。

 

5、分析二级页面【每条职位详细数据】

(1)分析数据来源

- 通过分析,在 控制台的【XHR】选中的请求中,查看到了对应的数据。

 

(2)分析对应的请求地址及相关参数

- ① 表示请求的URL地址;② 表示请求的方式。 

 

- 请求头信息(header):用于构建请求详情页的头信息。

- 请求参数

   - timestamp: 1605663485617 【明显是:13位的时间戳,Python实现方法:int(time.time()*1000)

   - postId: 1257927461836955648 【表示当前职位的 ID号】

   - language:  zh-cn  【语言,表示当前的使用的语言(固定不变)】

总结】如果要获取请求详情页则需要从一级页面解析出 每条职位信息的ID号 ,URL地址为:'https://careers.tencent.com/tencentcareer/api/post/ByPostId?timestamp={}&postId={}&language=zh-cn',需要传入 时间戳 职位ID号 

 


二、爬取一级页面数据

1、获取一级页面数据(职位ID号

- 找到对应职位信息的URL地址,粘贴到浏览器的一个新的选项卡中,粘贴正常的响应JOSN数据,可以使用JOSN解析【https://www.json.cn/】格式化输出,更加清晰查看到当前的数据结构,能够好的实现数据的提取。

# !/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:blning
# File:TencentJob.py

import time
from urllib import parse
from fake_useragent import UserAgent
import requests


class TencentJobSpier:
    def __init__(self):
        # timestamp:时间戳;keyword:查询参数;pageIndex:查询页面
        self.url = 'https://careers.tencent.com/tencentcareer/api/post/Query?timestamp={}&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword={}&pageIndex={}&pageSize=10&language=zh-cn&area=cn'

        # 构建请求头(使用 fake_useragent 构建随机的请求头)
        self.header = {'User-Agent': UserAgent().random}

        # 存储所有的 职位ID号
        self.jobID_list = []


    def get_html(self, url):
        '''
            根据不同的请求URL和请求头信息获取对应的页面JSON格式数据
        :param url: 发送请求的URL地址
        :param headers: 一级页面或二级页面的请求头信息
        :param params: 一级页面或二级页面的请求参数
        :return: 请求成功返回HTML页面的JSON格式数据,否则返回None
        '''
        try:
            response = requests.get(url=url, headers=self.header, timeout=5)
            if response.status_code == 200:
                return response.json()
            else:
                return None
        except Exception as e:
            print(f'请求异常:{e}')
            return None


    def parse_one_html(self, kword):
        '''
            解析获取职位数据的ID号,并存储至self.jobID_list列表中
        :param kword: 查询的职位名称
        :return: None
        '''
        timestamp = int(time.time() * 1000)
        keyword = parse.quote(kword)
        url = self.url.format(timestamp, keyword, 1)
        one_html_data = self.get_html(url)
        if one_html_data:
            datas = one_html_data["Data"]["Posts"]
            for data in datas:
                self.jobID_list.append(data["PostId"])


    # 主函数
    def main(self):
        kword = input('请输入要查询的职位:')
        self.parse_one_html(kword)
        print(self.jobID_list)


if __name__ == '__main__':
    tencentJob = TencentJobSpier()
    tencentJob.main()

 

三、解析二级页码数据

- 同样将对应URL地址中的数据通过使用JOSN解析【https://www.json.cn/】格式化输出。

# !/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:blning
# File:TencentJob.py

import random
import time
from urllib import parse
from fake_useragent import UserAgent
import requests


class TencentJobSpier:
    def __init__(self):
        # 二级页面的URL地址
        self.two_url = 'https://careers.tencent.com/tencentcareer/api/post/ByPostId?timestamp={}&postId={}&language=zh-cn'

        # 构建请求头(使用 fake_useragent 构建随机的请求头)
        self.header = {'User-Agent': UserAgent().random}

        # 存储所有的 职位ID号
        self.jobID_list = []

        # 存储所有的 职位数据
        self.jobData_list = []


    def parse_two_html(self, PostID):
        '''
            解析二级页面数据,存储至self.jobData_list列表中
        :param PostID: 职位的ID号
        :return: None
        '''
        timestamp = int(time.time() * 1000)
        url = self.two_url.format(timestamp, PostID)
        two_html_data = self.get_html(url)
        if two_html_data:
            job_name = two_html_data["Data"]["RecruitPostName"]
            job_location = two_html_data["Data"]["LocationName"]
            job_category = two_html_data["Data"]["CategoryName"]
            job_responsibility = two_html_data["Data"]["Responsibility"]
            job_requirement = two_html_data["Data"]["Requirement"]
            job_lastUpdateTime = two_html_data["Data"]["LastUpdateTime"]
            self.jobData_list.append((job_name, job_location, job_category, job_responsibility, job_requirement, job_lastUpdateTime))

    # 主函数
    def main(self):
        kword = input('请输入要查询的职位:')
        self.parse_one_html(kword)
        for postID in self.jobID_list:
            print(f'正在请求的职位ID为:{postID}')
            self.parse_two_html(postID)
            time.sleep(random.uniform(1,3))
        print(self.jobData_list)

if __name__ == '__main__':
    tencentJob = TencentJobSpier()
    tencentJob.main()

 

四、多页的爬取

- 获取输入职位总数为多少,计算出爬取的页数,及:page = totalNum // 10 + 1,总得数量在首页就有,则可以直接获取。

class TencentJobSpier:
     def parse_one_html(self, kword, page, id_list):
        '''
            解析获取职位数据的ID号,并存储至self.jobID_list列表中
        :param kword: 查询的职位名称
        :param page: 请求的页码数
        :param id_list: 存储每页所有的职位ID列表
        :return: None
        '''
        timestamp = int(time.time() * 1000)
        keyword = parse.quote(kword)
        url = self.url.format(timestamp, keyword, page)
        one_html_data = self.get_html(url)
        if one_html_data:
            datas = one_html_data["Data"]["Posts"]
            for data in datas:
                id_list.append(data["PostId"])


    def get_total(self, kword):
        '''
            获取首页的职位总数并返回
        :param kword: 查询中的职位关键字
        :return: 职位的总招聘数量
        '''
        timestamp = int(time.time() * 1000)
        keyword = parse.quote(kword)
        url = self.url.format(timestamp, keyword, 1)
        html = self.get_html(url)
        return html["Data"]["Count"]


    # 主函数
    def main(self):
        kword = input('请输入要查询的职位:')
        total = self.get_total(kword)
        page = total // 10 + 1
        for i in range(1, total+1):
            print(f'正在爬取第 {i} 页数据....')
            id_list = []       # 由于每次请求需要存储本页的职位ID做为爬取对象,则每次循环则需要清空
            self.parse_one_html(kword, i, id_list)
            for postID in id_list:
                print(f'正在请求的职位ID为:{postID}')
                self.parse_two_html(postID)
                time.sleep(random.uniform(1,3))   # 每个详细页休眠
            time.sleep(random.uniform(1, 3))     # 每次循环请求下一页休眠
        print(self.jobData_list, len(self.jobData_list))


if __name__ == '__main__':
    tencentJob = TencentJobSpier()
    tencentJob.main()

 

五、最终代码

# !/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:blning
# File:TencentJob.py

import random
import time
from urllib import parse
from fake_useragent import UserAgent
import requests

class TencentJobSpier:
    def __init__(self):
        # timestamp:时间戳;keyword:查询参数;pageIndex:查询页面
        self.url = 'https://careers.tencent.com/tencentcareer/api/post/Query?timestamp={}&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword={}&pageIndex={}&pageSize=10&language=zh-cn&area=cn'

        # 二级页面的URL地址
        self.two_url = 'https://careers.tencent.com/tencentcareer/api/post/ByPostId?timestamp={}&postId={}&language=zh-cn'

        # 构建请求头(使用 fake_useragent 构建随机的请求头)
        self.header = {'User-Agent': UserAgent().random}

        # 存储所有的 职位数据
        self.jobData_list = []



    def get_html(self, url):
        '''
            根据不同的请求URL和请求头信息获取对应的页面JSON格式数据
        :param url: 发送请求的URL地址
        :param headers: 一级页面或二级页面的请求头信息
        :param params: 一级页面或二级页面的请求参数
        :return: 请求成功返回HTML页面的JSON格式数据,否则返回None
        '''
        try:
            response = requests.get(url=url, headers=self.header, timeout=5)
            if response.status_code == 200:
                return response.json()
            else:
                return None
        except Exception as e:
            print(f'请求异常:{e}')
            return None


    def parse_one_html(self, kword, page, id_list):
        '''
            解析获取职位数据的ID号,并存储至self.jobID_list列表中
        :param kword: 查询的职位名称
        :param page: 请求的页码数
        :param id_list: 存储每页所有的职位ID列表
        :return: None
        '''
        timestamp = int(time.time() * 1000)
        keyword = parse.quote(kword)
        url = self.url.format(timestamp, keyword, page)
        one_html_data = self.get_html(url)
        if one_html_data:
            datas = one_html_data["Data"]["Posts"]
            for data in datas:
                id_list.append(data["PostId"])


    def parse_two_html(self, PostID):
        '''
            解析二级页面数据,存储至self.jobData_list列表中
        :param PostID: 职位的ID号
        :return: None
        '''
        timestamp = int(time.time() * 1000)
        url = self.two_url.format(timestamp, PostID)
        two_html_data = self.get_html(url)
        if two_html_data:
            job_name = two_html_data["Data"]["RecruitPostName"]
            job_location = two_html_data["Data"]["LocationName"]
            job_category = two_html_data["Data"]["CategoryName"]
            job_responsibility = two_html_data["Data"]["Responsibility"]
            job_requirement = two_html_data["Data"]["Requirement"]
            job_lastUpdateTime = two_html_data["Data"]["LastUpdateTime"]
            self.jobData_list.append((job_name, job_location, job_category, job_responsibility, job_requirement, job_lastUpdateTime))


    def get_total(self, kword):
        '''
            获取首页的职位总数并返回
        :param kword: 查询中的职位关键字
        :return: 职位的总招聘数量
        '''
        timestamp = int(time.time() * 1000)
        keyword = parse.quote(kword)
        url = self.url.format(timestamp, keyword, 1)
        html = self.get_html(url)
        return html["Data"]["Count"]


    # 主函数
    def main(self):
        kword = input('请输入要查询的职位:')
        total = self.get_total(kword)
        page = total // 10 + 1
        for i in range(1, total+1):
            print(f'正在爬取第 {i} 页数据....')
            id_list = []  # 由于每次请求需要存储本页的职位ID做为爬取对象,则每次循环则需要清空
            self.parse_one_html(kword, i, id_list)
            for postID in id_list:
                print(f'正在请求的职位ID为:{postID}')
                self.parse_two_html(postID)
                time.sleep(random.uniform(1,3))   # 每个详细页休眠
            time.sleep(random.uniform(1, 3))     # 每次循环请求下一页休眠
        print(self.jobData_list, len(self.jobData_list))


if __name__ == '__main__':
    tencentJob = TencentJobSpier()
    tencentJob.main()

结语】以上整个程序的实现逻辑,还存在很多不全面的地方,欢迎各位大佬指点;如果觉得笔者不易,请给予点赞,给予我记录更多文章的动力!!

  • 13
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值