51job 数据采集和分析

一.网络爬虫设计方案:

1.主题网络爬虫名称:51job 招聘网站信息数据采集

2.主题网络爬虫爬取的内容:采集python岗位薪资,职位,城市,学历等信息

3.主题式网络爬虫设计方案概述:进入网站搜索python并勾选对应学历,确定网址url后翻页获取每一页的html代码并解析出对应数据,期间进行数据清洗,将不规范数据从源头去除,然后保存至字典,再利用 xlsxwriter 模块存入excel表格,最后进行数据可视化处理,绘制各城市薪资占比,各学历岗位热度,各学历薪资分布等信息图

 

二.主题页面的结构特征分析:

1.主题页面结构特征分析:每一条对应的岗位信息都在class='el' 的div标签中,我们可使用xpath解析出每一个div再对每一条岗位进行解析,这样可以避免结构不同所带来的数据不精准现象。

2.页面解析

 

三:网络爬虫程序设计:

1.数据采集

import requests
from lxml import etree
from xlsxwriter import Workbook

# urls_0*列表存放的网址是通过修改url参数page实现的,循环100次即得到前100页的url,这里我们爬取四种学历对应的所以页数

# 博士学历,06
urls_06 = []
for page in range(1, 5):
    urls_06.append("https://search.51job.com/list/000000,000000,0000,00,9,99,python,2,{}.html?lang=c&postchannel=0000&workyear=99&cotype=99&degreefrom=06&jobterm=99&companysize=99&ord_field=0&dibiaoid=0&line=&welfare=".format(page))

"https://search.51job.com/list/000000,000000,0000,00,9,99,python,2,1.html?lang=c&postchannel=0000&workyear=99&cotype=99&degreefrom=03&jobterm=99&companysize=99&ord_field=0&dibiaoid=0&line=&welfare="
"https://search.51job.com/list/000000,000000,0000,00,9,99,python,2,1.html?lang=c&postchannel=0000&workyear=99&cotype=99&degreefrom=04&jobterm=99&companysize=99&ord_field=0&dibiaoid=0&line=&welfare="

# 硕士学历,05
urls_05 = []
for page in range(1, 59):
    urls_05.append("https://search.51job.com/list/000000,000000,0000,00,9,99,python,2,{}.html?lang=c&postchannel=0000&workyear=99&cotype=99&degreefrom=05&jobterm=99&companysize=99&ord_field=0&dibiaoid=0&line=&welfare=".format(page))


# 本科学历,04
urls_04 = []
for page in range(1, 407):
    urls_04.append("https://search.51job.com/list/000000,000000,0000,00,9,99,python,2,{}.html?lang=c&postchannel=0000&workyear=99&cotype=99&degreefrom=04&jobterm=99&companysize=99&ord_field=0&dibiaoid=0&line=&welfare=".format(page))


# 专科学历,03
urls_03 = []
for page in range(1, 103):
    urls_03.append("https://search.51job.com/list/000000,000000,0000,00,9,99,python,2,{}.html?lang=c&postchannel=0000&workyear=99&cotype=99&degreefrom=03&jobterm=99&companysize=99&ord_field=0&dibiaoid=0&line=&welfare=".format(page))


# 定义获取数据的函数
def get_data(tablename):
    # 声明四种学历,判断传入的tablename是哪种学历,对应取出urls
    educ = ['专科', '本科', '硕士', '博士']
    url_infos = [urls_03, urls_04, urls_05, urls_06]
    urls = []
    # 遍历判断出正确的学历目标url信息
    for k, i in enumerate(educ):
        if tablename == i:
            urls = url_infos[k]

    # infos用来存储所有信息
    infos = []

    # 取出一页的链接逐条爬取
    for url in urls:
        
        # 打印链接
        print(url)

        # 获取页面源码
        con = requests.get(url).content.decode("gbk")
        
        # 创建xpath对象解析页面
        xp = etree.HTML(con)
        
        # 因为在招聘平台上有个别公司没有给出薪资,所以我们不可以直接去所有信息,需要逐条判断
        html = xp.xpath("//div[@class='dw_table']//div[@class='el']")
        
        # 取出单条信息对应的xpath对象
        for h in html:
            
            # 解析出岗位名称
            title = h.xpath('p/span/a/text()')
            if title:
                
                # 将多余空格字符去除
                title = title[0].replace(' ', '')
                
            # 取出公司名称
            gs_name = h.xpath('span[@class="t2"]/a/text()')[0]
            
            # 取出工作地址
            work_address = h.xpath('span[@class="t3"]/text()')[0]
            
            # 取出薪资
            money = h.xpath('span[@class="t4"]/text()')
            
            # 判断该岗位是否开出薪资范围,如果有则取出,没有则用暂无提示
            if money:
                money = money[0]
            else:
                
                # money = '暂无'
                # 如果该公司没有给出明确的薪资范围则不在我们爬取的目标中,跳过此层循环
                continue
                
            # 将一个公司的对应信息存入infos列表中
            infos.append({
                '职位': title,
                '公司名': gs_name,
                '地址': work_address,
                '薪资': money
            })

    # 将信息列表infos存入excel表格,表格名称即tablename
    players = infos
    ordered_list = ["职位", "公司名", "地址", "薪资"]

    wb = Workbook("./excels/%s.xlsx" % tablename)
    ws = wb.add_worksheet("New Sheet")

    first_row = 0
    for header in ordered_list:
        col = ordered_list.index(header)
        ws.write(first_row, col, header)

    row = 1
    for player in players:
        for _key, _value in player.items():
            col = ordered_list.index(_key)
            ws.write(row, col, _value)
        row += 1
    wb.close()


# 定义列表存入四种学历
educ = ['专科', '本科', '硕士', '博士']

for v in educ:
    
    # 取出一条学历传入get_data函数
    get_data(v)

 

保存成功:

 

 

2.数据清洗和处理

为减少代码冗余,我们在采集过程中就引入了数据的处理和清洗

 

3.数据分析与可视化

(1)地区热度词云图

import io
import sys

import jieba
from matplotlib import pyplot as plt
import matplotlib as mpl
from wordcloud import WordCloud
from xlrd import open_workbook

f = ''

for filename in ['专科','本科','硕士','博士']:

    mpl.rcParams['font.sans-serif'] = ['KaiTi']

    mpl.rcParams['font.serif'] = ['KaiTi']

    # sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

    workbook = open_workbook(r'./excels/{}.xlsx'.format(filename))  # 打开xls文件

    sheet_name= workbook.sheet_names()  # 打印所有sheet名称,是个列表

    sheet = workbook.sheet_by_index(0)  # 根据sheet索引读取sheet中的所有内容

    content = sheet.col_values(2)[0:]  # 第3列内容

    for i in content:

        f += i[:2]


# 结巴分词,生成字符串,wordcloud无法直接生成正确的中文词云

cut_text = " ".join(jieba.cut(f))

wordcloud = WordCloud(

    # 设置字体,不然会出现口字乱码,文字的路径是电脑的字体一般路径,可以换成别的

    font_path="C:/Windows/Fonts/simfang.ttf",

    # 设置了背景,宽高

    background_color="white", width=2000, height=1200).generate(cut_text)

plt.imshow(wordcloud, interpolation="bilinear")

plt.axis("off")

plt.savefig('地区热度词云图.png')

效果:

 

(2) 岗位数量折线图示

import io
import sys

from matplotlib import pyplot as plt
import matplotlib as mpl
from xlrd import open_workbook

nums_list = []
for i in ['专科','本科','硕士','博士']:
    filename = i

    mpl.rcParams['font.sans-serif'] = ['KaiTi']
    mpl.rcParams['font.serif'] = ['KaiTi']
    # sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

    workbook = open_workbook(r'./excels/{}.xlsx'.format(filename))  # 打开xls文件
    sheet_name= workbook.sheet_names()  # 打印所有sheet名称,是个列表
    sheet = workbook.sheet_by_index(0)  # 根据sheet索引读取sheet中的所有内容
    content = sheet.col_values(0)[1:]  # 第1列内容
    nums_list.append(len(content))


input_values = ['专科','本科','硕士','博士']
squares = nums_list


# 生成折现图
plt.plot(input_values, squares, linewidth=2,)  # 调用绘制函数,传入输入参数和输出参数
plt.title("python岗位数量分布", fontsize=24)  # 指定标题,并设置标题字体大小
plt.xlabel("学历", fontsize=14)  # 指定X坐标轴的标签,并设置标签字体大小
plt.ylabel("岗位数量", fontsize=14)  # 指定Y坐标轴的标签,并设置标签字体大小
plt.tick_params(axis='both', labelsize=14)  # 参数axis值为both,代表要设置横纵的刻度标记,标记大小为14
plt.savefig("./岗位数量折线图示.png")  # 打开matplotlib查看器,并保存绘制的图形

 

(3)各学历对应职位占比

import io
import sys

from matplotlib import pyplot as plt
import matplotlib as mpl
from xlrd import open_workbook

filename = '专科'     # 替换学历名称运行程序即可得到四张图片

mpl.rcParams['font.sans-serif'] = ['KaiTi']

mpl.rcParams['font.serif'] = ['KaiTi']

sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

workbook = open_workbook(r'./excels/{}.xlsx'.format(filename))  # 打开xls文件

sheet_name= workbook.sheet_names()  # 打印所有sheet名称,是个列表

sheet = workbook.sheet_by_index(0)  # 根据sheet索引读取sheet中的所有内容

content = sheet.col_values(0)[1:]  # 第1列内容

new_con = []

for i in content:

    new_con.append(i.replace('\r','').replace('\n',''))

nums = []

temp = {}

for m in new_con:

    # 循环判断薪资是否在nums列表中
    if m not in nums:

        # 不在则添加一个值为该薪资的键
        nums.append(m)
        temp[m] = 0
    if m in nums:

        # 在则将该建对应的值加1
        temp[m] = temp[m] + 1

# 利用sorted函数对该字典排序

new_title = sorted(temp.items(), key=lambda item: item[1], reverse=True)[0:6]

nums = []

input_values = []

for i in new_title:

    nums.append(i[1])

    input_values.append(i[0])

sum_nums = sum(nums)

squares = [x/sum_nums for x in nums]

print(input_values)

print(squares)


# 保证圆形
plt.axes(aspect=1)
plt.pie(x=squares, labels=input_values, autopct='%3.1f %%')
plt.savefig("./岗位热度图示/{}岗位热度饼状图示.png".format(filename))

 

(4)各学历薪资状况

import io
import sys

from matplotlib import pyplot as plt
import matplotlib as mpl
from xlrd import open_workbook

filename = '专科'     # 替换学历名称运行程序即可得到四张图片

mpl.rcParams['font.sans-serif'] = ['KaiTi']
mpl.rcParams['font.serif'] = ['KaiTi']
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

workbook = open_workbook(r'./excels/{}.xlsx'.format(filename))  # 打开xls文件
sheet_name= workbook.sheet_names()  # 打印所有sheet名称,是个列表
sheet = workbook.sheet_by_index(0)  # 根据sheet索引读取sheet中的所有内容
content = sheet.col_values(3)[0:]  # 第4列内容

moneys = []
for i in content:
    if '月' in i:
        moneys.append(i[:-2])

nums = []   # num为临时变量,在下方提供判定作用


# money_num用来存储薪资范围最普遍的值
money_num = {}


for m in moneys:

    # 循环判断薪资是否在nums列表中
    if m not in nums:

        # 不在则添加一个值为该薪资的键
        nums.append(m)
        money_num[m] = 0
    if m in nums:

        # 在则将该建对应的值加1
        money_num[m] = money_num[m] + 1

# 利用sorted函数对该字典排序

new_money_nums = sorted(money_num.items(), key=lambda item: item[1], reverse=True)

x = []
y = []

for i in new_money_nums[0:8]:
    x.append(i[0])
    y.append(i[1])


plt.bar(x, y, align='center')

plt.title('python')
plt.ylabel('人数')
plt.xlabel('薪资')


plt.savefig("./薪资范围图示/{}薪资分布柱状图.png".format(filename))

 

 

 

 

 

 

(5)代码汇总

 

 

 

四:结论:

从分析中可知要想得到更好的生活,就要好好学习哈哈哈,更要明白难的知识才会更有含金量,如果不刻苦学习将来可能只是初级运维师,越努力越幸运。

这次项目也让我感受到了python的魅力,获益良多,让我对后期课程更加感兴趣! 以后肯定好好学习, 把以前的不足都补上 !

posted @ 2020-09-28 14:28  夏夜风  阅读(860)  评论(0编辑  收藏  举报