美文网首页
Python采集招聘数据信息(+详情页)并实现可视化

Python采集招聘数据信息(+详情页)并实现可视化

作者: 颜狗一只 | 来源:发表于2022-06-19 20:11 被阅读0次

    本篇代码提供者: 青灯教育-自游老师


    [环境使用]:

    • Python 3.8
    • Pycharm

    [模块使用]:

    • requests >>> pip install requests
    • re
    • json
    • csv

    如果安装python第三方模块:

    1. win + R 输入 cmd 点击确定, 输入安装命令 pip install 模块名 (pip install requests) 回车
    2. 在pycharm中点击Terminal(终端) 输入安装命令

    如何配置pycharm里面的python解释器?

    1. 选择file(文件) >>> setting(设置) >>> Project(项目) >>> python interpreter(python解释器)

    2. 点击齿轮, 选择add

    3. 添加python安装路径


    pycharm如何安装插件?

    1. 选择file(文件) >>> setting(设置) >>> Plugins(插件)

    2. 点击 Marketplace 输入想要安装的插件名字 比如:翻译插件 输入 translation / 汉化插件 输入 Chinese

    3. 选择相应的插件点击 install(安装) 即可

    4. 安装成功之后 是会弹出 重启pycharm的选项 点击确定, 重启即可生效


    基本流程思路: <可以通用>

    一. 数据来源分析

    网页开发者工具进行抓包分析....

    1. F12打开开发者工具, 刷新网页
    2. 通过关键字进行搜索, 找到相应的数据, 查看response响应数据
    3. 确定数据之后, 查看headers确定请求url地址 请求方式 以及 请求参数

    二. 代码实现过程:

    1. 发送请求, 用python代码模拟浏览器对于url地址发送请求
    2. 获取数据, 获取服务器返回response响应数据
    3. 解析数据, 提取我们想要招聘信息数据
    4. 保存数据, 保存到表格文件里面

    代码

    导入模块

    # 导入数据请求模块
    import requests
    # 导入正则表达式模块
    import re
    # 导入json模块
    import json
    # 导入格式化输出模块
    import pprint
    # 导入csv模块
    import csv
    # 导入时间模块
    import time
    # 导入随机模块
    import random
    # 有没有用utf-8保存表格数据,乱码的?
    源码、解答、教程可加Q裙:832157862免费领取
    
    f = open('data多页_1.csv', mode='a', encoding='utf-8', newline='')  # 打开一个文件 data.csv
    csv_writer = csv.DictWriter(f, fieldnames=[
        '职位',
        '城市',
        '经验',
        '学历',
        '薪资',
        '公司',
        '福利待遇',
        '公司领域',
        '公司规模',
        '公司类型',
        '发布日期',
        '职位详情页',
        '公司详情页',
    ])
    csv_writer.writeheader()
    

    1. 发送请求,

    用python代码模拟浏览器对于url地址发送请求

    不要企图一节课, 掌握所有内容, 要学习听懂思路, 每一步我们为什么这么做...
    知道headers 1
    不知道headers 2

    headers 请求头, 作用伪装python代码, 伪装成浏览器
    字典形式, 构建完整键值对

    如果当你headers伪装不够的时候, 你可能会被服务器识别出来, 你是爬虫程序, 从而不给你相应的数据内容

    for page in range(1, 15):
        print(f'正在采集第{page}页的数据内容')
        time.sleep(random.randint(1, 2))
        url = f'https://search.51job.com/list/010000%252C020000%252C030200%252C040000%252C090200,000000,0000,00,9,99,python,2,{page}.html'
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36'
        }
        response = requests.get(url=url, headers=headers)
        print(response)  # <Response [200]> 响应对象
        源码、解答、教程可加Q裙:832157862免费领取
    

    2. 获取数据

    得到数据, 不是你想要数据内容, 你可能是被反爬了, 要多加一些伪装 <小伏笔>

    # print(response.text)  字符串数据类型
    

    3. 解析数据, 提取我们想要数据内容

    re.findall() 就是从什么地方去找什么样数据内容

    [0] 表示提取列表里面第一个元素 ---> list index out of range 所以你的列表是空列表

    用正则表达式/css/xpath提取数据返回是空列表 ---> 1. 你语法写错 2. response.text 没有你想要数据

    ---> 是不是被反爬(验证码 需要登陆) 是不是headers参数给少了 是不是被封IP

        html_data = re.findall('window.__SEARCH_RESULT__ = (.*?)</script>', response.text)[0]
        # print(html_data)
        json_data = json.loads(html_data)
        # pprint.pprint(json_data)
        # 通过字典取值方法 把职位信息列表提取出来, 通过for循环遍历一个一个提取职位信息
        for index in json_data['engine_jds']:
            # 根据冒号左边的内容, 提取冒号右边的内容
            # pprint.pprint(index)
            try:
                dit = {
                    '职位': index['job_title'],
                    '城市': index['attribute_text'][0],
                    '经验': index['attribute_text'][1],
                    '学历': index['attribute_text'][2],
                    '薪资': index['providesalary_text'],
                    '公司': index['company_name'],
                    '福利待遇': index['jobwelf'],
                    '公司领域': index['companyind_text'],
                    '公司规模': index['companysize_text'],
                    '公司类型': index['companytype_text'],
                    '发布日期': index['issuedate'],
                    '职位详情页': index['job_href'],
                    '公司详情页': index['company_href'],
                    源码、解答、教程可加Q裙:832157862免费领取
                }
                csv_writer.writerow(dit)
                print(dit)
            except:
                pass
    

    详情页数据

    ----> 爬虫基本思路是什么?

    数据来源分析

    请求响应 请求那个网站呢? 网址是什么 请求方式是什么 请求参数要什么?

    发送请求 ---> 获取数据 ---> 解析数据 ---> 保存数据

    导入模块

    import requests
    import parsel
    
    url = 'https://jobs.51job.com/shanghai-jdq/137393082.html?s=sou_sou_soulb&t=0_0'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36',
    }
    response = requests.get(url=url, headers=headers)
    response.encoding = response.apparent_encoding  # 自动识别编码
    print(response.text)
    selector = parsel.Selector(response.text)
    content_1 = selector.css('.cn').get()
    content_2 = selector.css('.tCompany_main').get()
    content = content_1 + content_2
    # 文件名 公司名字 + 职位名字
    with open('python.html', mode='w', encoding='utf-8') as f:
        f.write(content)
    

    可视化

    代码

    import pandas as pd
    from pyecharts.charts import *
    from pyecharts import options as opts
    import re
    from pyecharts.globals import ThemeType
    from pyecharts.commons.utils import JsCode
    
    df = pd.read_csv("招聘数据.csv")
    df.head()
    
    df.info()
    
    df['薪资'].unique()
    df['bottom']=df['薪资'].str.extract('^(\d+).*')
    df['top']=df['薪资'].str.extract('^.*?-(\d+).*')
    df['top'].fillna(df['bottom'],inplace=True)
    
    df['commision_pct']=df['薪资'].str.extract('^.*?·(\d{2})薪')
    df['commision_pct'].fillna(12,inplace=True)
    df['commision_pct']=df['commision_pct'].astype('float64')
    df['commision_pct']=df['commision_pct']/12
    
    df.dropna(inplace=True)
    源码、解答、教程可加Q裙:832157862免费领取
    df['bottom'] = df['bottom'].astype('int64')
    df['top'] = df['top'].astype('int64')
    df['平均薪资'] = (df['bottom']+df['top'])/2*df['commision_pct']
    df['平均薪资'] = df['平均薪资'].astype('int64')
    
    df.head()
    
    df['薪资'] = df['薪资'].apply(lambda x:re.sub('.*千/月', '0.3-0.7万/月', x))
    df["薪资"].unique()
    
    df['bottom'] = df['薪资'].str.extract('^(.*?)-.*?')
    df['top'] = df['薪资'].str.extract('^.*?-(\d\.\d|\d)')
    df.dropna(inplace=True)
    df['bottom'] = df['bottom'].astype('float64')
    df['top'] = df['top'].astype('float64')
    df['平均薪资'] = (df['bottom']+df['top'])/2 * 10
    df.head()
    
    mean = df.groupby('学历')['平均薪资'].mean().sort_values()
    x = mean.index.tolist()
    y = mean.values.tolist()
    c = (
        Bar()
        .add_xaxis(x)
        .add_yaxis(
            "学历",
            y
        )
        .set_global_opts(title_opts=opts.TitleOpts(title="不同学历的平均薪资"),datazoom_opts=opts.DataZoomOpts())
        .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    )
    c.render_notebook()
    
    color_js = """new echarts.graphic.LinearGradient(0, 1, 0, 0,
        [{offset: 0, color: '#63e6be'}, {offset: 1, color: '#0b7285'}], false)"""
    
    color_js1 = """new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
                                offset: 0,
                                color: '#ed1941'
                            }, {
                                offset: 1,
                                color: '#009ad6'
                            }], false)"""
    
    dq = df.groupby('城市')['职位'].count().to_frame('数量').sort_values(by='数量',ascending=False).reset_index()
    x_data = dq['城市'].values.tolist()[:20]
    y_data = dq['数量'].values.tolist()[:20]
    b1 = (
            Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK,bg_color=JsCode(color_js1),width='1000px',height='600px'))
            .add_xaxis(x_data)
            .add_yaxis('',
                       y_data ,
                       category_gap="50%",
                       label_opts=opts.LabelOpts(
                            font_size=12,
                            color='yellow',
                            font_weight='bold', 
                            font_family='monospace',
                            position='insideTop',  
                            formatter = '{b}\n{c}'  
                        ),
                      )
            .set_series_opts(
            源码、解答、教程可加Q裙:832157862免费领取
                itemstyle_opts={
                    "normal": {
                        "color": JsCode(color_js),
                        "barBorderRadius": [15, 15, 0, 0],
                        "shadowColor": "rgb(0, 160, 221)",
                    }
                }
            )
            .set_global_opts(
                title_opts=opts.TitleOpts(title='招 聘 数 量 前 20 的 城 市 区 域',
                                           title_textstyle_opts=opts.TextStyleOpts(color="yellow"),
                                           pos_top='7%',pos_left = 'center'
                                         ),
                legend_opts=opts.LegendOpts(is_show=False),
                xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=-15)),
                yaxis_opts=opts.AxisOpts(name="",
                                         name_location='middle',
                                         name_gap=40,
                                         name_textstyle_opts=opts.TextStyleOpts(font_size=16)),
                             datazoom_opts=[opts.DataZoomOpts(range_start=1,range_end=50)]
                            )
    
        )
    b1.render_notebook()
    
    boss = df['学历'].value_counts()
    x = boss.index.tolist()
    y = boss.values.tolist()
    data_pair = [list(z) for z in zip(x, y)]
    c = (
        Pie(init_opts=opts.InitOpts(width="1000px", height="600px", bg_color="#2c343c"))
        .add(
            series_name="学历需求占比",
            data_pair=data_pair,
            label_opts=opts.LabelOpts(is_show=False, position="center", color="rgba(255, 255, 255, 0.3)"),
        )
        .set_series_opts(
            tooltip_opts=opts.TooltipOpts(
                trigger="item", formatter="{a} <br/>{b}: {c} ({d}%)"
            ),
            label_opts=opts.LabelOpts(color="rgba(255, 255, 255, 0.3)"),
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(
                title="学历需求占比",
                pos_left="center",
                pos_top="20",
                title_textstyle_opts=opts.TextStyleOpts(color="#fff"),
            ),
            legend_opts=opts.LegendOpts(is_show=False),
        )
        .set_colors(["#D53A35", "#334B5C", "#61A0A8", "#D48265", "#749F83"])
    )
    c.render_notebook()
    
    boss = df['经验'].value_counts()
    x = boss.index.tolist()
    y = boss.values.tolist()
    data_pair = [list(z) for z in zip(x, y)]
    c = (
        Pie(init_opts=opts.InitOpts(width="1000px", height="600px", bg_color="#2c343c"))
        .add(
            series_name="经验需求占比",
            data_pair=data_pair,
            label_opts=opts.LabelOpts(is_show=False, position="center", color="rgba(255, 255, 255, 0.3)"),
        )
        .set_series_opts(
            tooltip_opts=opts.TooltipOpts(
                trigger="item", formatter="{a} <br/>{b}: {c} ({d}%)"
            ),
            label_opts=opts.LabelOpts(color="rgba(255, 255, 255, 0.3)"),
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(
                title="经验需求占比",
                pos_left="center",
                pos_top="20",
                title_textstyle_opts=opts.TextStyleOpts(color="#fff"),
            ),
            legend_opts=opts.LegendOpts(is_show=False),
        )
        .set_colors(["#D53A35", "#334B5C", "#61A0A8", "#D48265", "#749F83"])
    )
    c.render_notebook()
    
    boss = df['公司领域'].value_counts()
    x = boss.index.tolist()
    y = boss.values.tolist()
    data_pair = [list(z) for z in zip(x, y)]
    c = (
        Pie(init_opts=opts.InitOpts(width="1000px", height="600px", bg_color="#2c343c"))
        .add(
            series_name="公司领域占比",
            data_pair=data_pair,
            label_opts=opts.LabelOpts(is_show=False, position="center", color="rgba(255, 255, 255, 0.3)"),
        )
        .set_series_opts(
            tooltip_opts=opts.TooltipOpts(
                trigger="item", formatter="{a} <br/>{b}: {c} ({d}%)"
            ),
            label_opts=opts.LabelOpts(color="rgba(255, 255, 255, 0.3)"),
        )
        .set_global_opts(
            title_opts=opts.TitleOpts(
                title="公司领域占比",
                pos_left="center",
                pos_top="20",
                title_textstyle_opts=opts.TextStyleOpts(color="#fff"),
            ),
            legend_opts=opts.LegendOpts(is_show=False),
        )
        .set_colors(["#D53A35", "#334B5C", "#61A0A8", "#D48265", "#749F83"])
    )
    c.render_notebook()
    
    from pyecharts import options as opts
    from pyecharts.charts import Pie
    from pyecharts.faker import Faker
    boss = df['经验'].value_counts()
    x = boss.index.tolist()
    y = boss.values.tolist()
    data_pair = [list(z) for z in zip(x, y)]
    源码、解答、教程可加Q裙:832157862免费领取
    c = (
        Pie()
        .add("", data_pair)
        .set_colors(["blue", "green", "yellow", "red", "pink", "orange", "purple"])
        .set_global_opts(title_opts=opts.TitleOpts(title="经验要求占比"))
        .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}"))
    )
    c.render_notebook()
    
    
    from pyecharts import options as opts
    from pyecharts.charts import Pie
    from pyecharts.faker import Faker
    boss = df['经验'].value_counts()
    x = boss.index.tolist()
    y = boss.values.tolist()
    data_pair = [list(z) for z in zip(x, y)]
    
    c = (
        Pie()
        .add(
            "",
            data_pair,
            radius=["40%", "55%"],
            label_opts=opts.LabelOpts(
                position="outside",
                formatter="{a|{a}}{abg|}\n{hr|}\n {b|{b}: }{c}  {per|{d}%}  ",
                background_color="#eee",
                border_color="#aaa",
                border_width=1,
                border_radius=4,
                rich={
                    "a": {"color": "#999", "lineHeight": 22, "align": "center"},
                    "abg": {
                        "backgroundColor": "#e3e3e3",
                        "width": "100%",
                        "align": "right",
                        "height": 22,
                        "borderRadius": [4, 4, 0, 0],
                    },
                    "hr": {
                        "borderColor": "#aaa",
                        "width": "100%",
                        "borderWidth": 0.5,
                        "height": 0,
                    },
                    "b": {"fontSize": 16, "lineHeight": 33},
                    "per": {
                        "color": "#eee",
                        "backgroundColor": "#334455",
                        "padding": [2, 4],
                        "borderRadius": 2,
                    },
                },
            ),
        )
        .set_global_opts(title_opts=opts.TitleOpts(title="Pie-富文本示例"))
        
    )
    c.render_notebook()
    
    gsly = df['公司领域'].value_counts()[:10]
    x1 = gsly.index.tolist()
    y1 = gsly.values.tolist()
    c = (
        Bar()
        .add_xaxis(x1)
        .add_yaxis(
            "公司领域",
            y1
        )
        .set_global_opts(title_opts=opts.TitleOpts(title="公司领域"),datazoom_opts=opts.DataZoomOpts())
        .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    )
    c.render_notebook()
    
    
    gsgm = df['公司规模'].value_counts()[1:10]
    x2 = gsgm.index.tolist()
    y2 = gsgm.values.tolist()
    c = (
        Bar()
        .add_xaxis(x2)
        .add_yaxis(
            "公司规模",
            y2
        )
        .set_global_opts(title_opts=opts.TitleOpts(title="公司规模"),datazoom_opts=opts.DataZoomOpts())
        .set_series_opts(label_opts=opts.LabelOpts(is_show=False))
    )
    c.render_notebook()
    
    import stylecloud
    from PIL import Image
    welfares = df['福利'].dropna(how='all').values.tolist()
    welfares_list = []
    for welfare in welfares:
        welfares_list += welfare.split(',')
    pic_name = '福利词云.png'
    stylecloud.gen_stylecloud(
        text=' '.join(welfares_list),
        font_path='msyh.ttc',
        palette='cartocolors.qualitative.Bold_5',
        max_font_size=100,
        icon_name='fas fa-yen-sign',
        background_color='#212529',
        output_name=pic_name,
        源码、解答、教程可加Q裙:832157862免费领取
        )
    Image.open(pic_name)
    

    部分效果展示

    尾语

    好了,我的这篇文章写到这里就结束啦!

    有更多建议或问题可以评论区或私信我哦!一起加油努力叭(ง •_•)ง

    喜欢就关注一下博主,或点赞收藏评论一下我的文章叭!!!

    相关文章

      网友评论

          本文标题:Python采集招聘数据信息(+详情页)并实现可视化

          本文链接:https://www.haomeiwen.com/subject/fiwjvrtx.html