当前位置:   article > 正文

Python爬虫实战+数据分析+数据可视化(前程无忧招聘信息)_python爬取信息成表格并可视化分析

python爬取信息成表格并可视化分析

一、爬虫部分

爬虫说明:
1、本爬虫是以面向对象的方式进行代码架构的
2、本爬虫是通过将前程无忧网页转换成一定端来进行求职信息爬取的
3、本爬虫爬取的数据存入到MongoDB数据库中
4、爬虫代码中有详细注释

代码展示

    import time
    from pymongo import MongoClient
    import requests
    from lxml import html
    
    
    class JobSpider():
        def __init__(self):
            # 构造请求头信息
            self.headers = {
                "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1"
            }
            # 起始url路径
            self.start_url = 'https://msearch.51job.com/job_list.php?keyword=python&jobarea=000000&pageno=1'
            # 求职列表页url
            self.url_list = 'https://msearch.51job.com/job_list.php?keyword=python&jobarea=000000&pageno={}'
            # 初始化MongoDB数据库
            self.client = MongoClient()
            self.collection = self.client['test']['wuyou_job']
    
        # 构造所有列表页的url地址
        def get_url_list(self,total_num):
            total_num = int(total_num)
            page = total_num//50+1 if total_num%50!=0 else total_num//50
            return [self.url_list.format(i) for i in range(1,page+1)]
    
        # 请求并解析网页
        def parse_url(self,url):
            # 睡眠 防止因爬取速度过快而导致程序停止
            time.sleep(0.5)
            rest = requests.get(url,headers=self.headers)
            return rest.content.decode()
    
        # 获取列表页数据
        def get_content_list(self,str_html):
            str_html = html.etree.HTML(str_html)
            # 将求职信息进行分组
            job_list = str_html.xpath('//div[@id="pageContent"]/div[@class="list"]/a')
            # 遍历每一个求职信息获取详细url 再次请求获取详细求职信息
            for i in job_list:
                detail_url = i.xpath('./@href')[0]
                self.parse_detail(detail_url)
    
        # 解析详情页
        def parse_detail(self,detail_url):
            time.sleep(0.1)
            rest = requests.get(detail_url,headers = self.headers)
            str_html = html.etree.HTML(rest.content.decode())
            item = {}
            # 通过使用Python三目运算符的机制稳固爬虫程序 使爬虫在未爬取到信息的情况下不会报错并填充None
            item['职位'] = str_html.xpath('//p[@class="jname"]/text()')
            item['职位'] = item['职位'][0] if len(item['职位'])>0 else None
            item['公司名称'] = str_html.xpath('//div[@class="info"]/h3/text()')
            item['公司名称'] = item['公司名称'][0] if len(item['公司名称'])>0 else None
            item['公司地点'] = str_html.xpath('//div[@class="jbox"]/div[@class="m_bre"]/span[2]/text()')
            item['公司地点'] = item['公司地点'][0] if len(item['公司地点'])>0 else None
            item['公司性质'] = str_html.xpath('//div[@class="info"]/div[@class="m_bre"]/span[1]/text()')
            item['公司性质'] = item['公司性质'][0] if len(item['公司性质'])>0 else None
            item['薪资'] = str_html.xpath('//p[@class="sal"]/text()')
            item['薪资'] = item['薪资'][0] if len(item['薪资'])>0 else None
            item['学历要求'] = str_html.xpath('//div[@class="jbox"]/div[@class="m_bre"]/span[3]/text()')
            item['学历要求'] = item['学历要求'][0] if len(item['学历要求'])>0 else None
            item['工作经验'] = str_html.xpath('//div[@class="jbox"]/div[@class="m_bre"]/span[4]/text()')
            item['工作经验'] = item['工作经验'][0] if len(item['工作经验'])>0 else None
            item['公司规模'] = str_html.xpath('//div[@class="info"]/div[@class="m_bre"]/span[2]/text()')
            item['公司规模'] = item['公司规模'][0] if len(item['公司规模'])>0 else None
            item['公司类型'] = str_html.xpath('//div[@class="info"]/div[@class="m_bre"]/span[3]/text()')
            item['公司类型'] = item['公司类型'][0] if len(item['公司类型'])>0 else None
            item['公司福利'] = str_html.xpath('//div[@class="tbox"]/span/text()')
            item['公司福利'] = '-'.join(item['公司福利'])
            item['发布时间'] = str_html.xpath('//span[@class="date"]/text()')
            item['发布时间'] = item['发布时间'][0] if len(item['发布时间'])>0 else None
            print(item)
            self.save(item)
    
        # 保存爬取内容
        def save(self,item):
            self.collection.insert(item)
    
        # 主函数
        def run(self):
            # 先请求一次起始url获取总搜索条数
            rest = requests.get(self.start_url,headers = self.headers)
            str_html = html.etree.HTML(rest.content.decode())
            total_num = str_html.xpath('//p[@class="result"]/span/text()')[0]
            # 获取所有的列表页
            url_list = self.get_url_list(total_num)
            # 遍历列表页
            for i in url_list:
                str_html = self.parse_url(i)
                self.get_content_list(str_html)
    
    
    
    if __name__ == '__main__':
        job = JobSpider()
        job.run()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97

二、数据分析和数据可视化部分

数据分析和数据可视化说明:
1、本博客通过Flask框架来进行数据分析和数据可视化
2、项目的架构图为
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210117170031131.png?x-oss-
process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1ODIxNDIw,size_16,color_FFFFFF,t_70)

代码展示

  • 数据分析代码展示(analysis.py)
    import re
    import pandas as pd
    import numpy as np
    from pymongo import MongoClient
    import pymysql
    
    # 薪资处理函数 将薪资转换成以千为单位的数值 针对不同类型进行不同的处理
    def salary_process(df):
        # 处理元/每天的数据
        df['薪资'] = df['薪资'].apply(
            lambda x: str(round(float(re.findall('(.*)元', x)[0]) / 1000 * 30, 1)) if x.endswith('元/天') else x)
        # 处理千/月的数据
        df['薪资'] = df['薪资'].apply(lambda x: str(
            round((float(re.findall(r'(.*)千', x)[0].split('-')[0]) + float(re.findall(r'(.*)千', x)[0].split('-')[1])) / 2,
                  1)) if x.endswith('千/月') else x)
        # 处理万/月的数据
        df['薪资'] = df['薪资'].apply(lambda x: str(round(
            (float(re.findall(r'(.*)万', x)[0].split('-')[0]) + float(re.findall(r'(.*)万', x)[0].split('-')[1])) / 2 * 10,
            1)) if len(re.findall(r'万', x)) > 0 and len(re.findall(r'-', x)) > 0 else x)
        # 处理千以下/月的数据
        df['薪资'] = df['薪资'].apply(lambda x: re.findall('(.*)千以下', x)[0] if x.endswith('千以下/月') else x)
        # 将除以上结果的数据删除
        df['薪资'] = df['薪资'].apply(lambda x: x if len(re.findall('\d\.\d', x)) > 0 else np.nan)
        df['薪资'].dropna(how='any', inplace=True)
        # 将薪资类型转换成float
        df['薪资'] = df['薪资'].astype(np.float)
        df.reset_index(drop=True, inplace=True)
        return df
    
    
    # 工作经验与薪资的关系
    def experience_salary(df):
        # 按照薪资进行分组
        grouped = df.groupby('工作经验')['薪资'].mean().reset_index()
        # 数据只保留带有工作经验和在校生的部分
        grouped = grouped[(grouped['工作经验'].str.contains('经验'))|(grouped['工作经验'].str.contains('在校生'))]
        # 将单位转换成万并保留一位小数
        grouped['薪资'] = grouped['薪资'].apply(lambda x:round(x/10,1))
        # 将数据转换成列表嵌套列表的格式方便数据库批量导入
        data = [[i['工作经验'],i['薪资']] for i in grouped.to_dict(orient='records')]
        print(data)
        return data
    
    
    # 学历与薪资的关系
    def education_salary(df):
        grouped = df.groupby('学历要求').mean().reset_index()
        grouped['薪资'] = grouped['薪资'].apply(lambda x:round(x/10,1))
        # 将非学历字段删除
        grouped = grouped[grouped['学历要求'].str.contains('经验')==False]
        # 将数据转换成列表嵌套列表的格式方便数据库批量导入
        data = [[i['学历要求'],i['薪资']] for i in grouped.to_dict(orient='records')]
        return data
    
    
    # python城市需求地理位置分布图
    def city_need(df):
    	# 各城市的经纬度数据
        geoCoordMap = {
            '海门': [121.15, 31.89],
            '鄂尔多斯': [109.781327, 39.608266],
            '招远': [120.38, 37.35],
            '舟山': [122.207216, 29.985295],
            '齐齐哈尔': [123.97, 47.33],
            '盐城': [120.13, 33.38],
            '赤峰': [118.87, 42.28],
            '青岛': [120.33, 36.07],
            '乳山': [121.52, 36.89],
            '金昌': [102.188043, 38.520089],
            '泉州': [118.58, 24.93],
            '莱西': [120.53, 36.86],
            '日照': [119.46, 35.42],
            '胶南': [119.97, 35.88],
            '南通': [121.05, 32.08],
            '拉萨': [91.11, 29.97],
            '云浮': [112.02, 22.93],
            '梅州': [116.1, 24.55],
            '文登': [122.05, 37.2],
            '上海': [121.48, 31.22],
            '攀枝花': [101.718637, 26.582347],
            '威海': [122.1, 37.5],
            '承德': [117.93, 40.97],
            '厦门': [118.1, 24.46],
            '汕尾': [115.375279, 22.786211],
            '潮州': [116.63, 23.68],
            '丹东': [124.37, 40.13],
            '太仓': [121.1, 31.45],
            '曲靖': [103.79, 25.51],
            '烟台': [121.39, 37.52],
            '福州': [119.3, 26.08],
            '瓦房店': [121.979603, 39.627114],
            '即墨': [120.45, 36.38],
            '抚顺': [123.97, 41.97],
            '玉溪': [102.52, 24.35],
            '张家口': [114.87, 40.82],
            '阳泉': [113.57, 37.85],
            '莱州': [119.942327, 37.177017],
            '湖州': [120.1, 30.86],
            '汕头': [116.69, 23.39],
            '昆山': [120.95, 31.39],
            '宁波': [
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/696050
推荐阅读
相关标签
  

闽ICP备14008679号