当前位置:   article > 正文

Python可视化分析项目高分课设_python可视化项目

python可视化项目

今天给大家分享一个基于python的django框架结合爬虫以及数据可视化和数据库的项目,该项目总体来说还是挺不错的,下面针对这个项目做具体介绍。

1:项目涉及技术:

项目后端语言:python

项目页面布局展现:前端(html,css,javascript)

项目数据可视化呈现:echars.js

项目数据操作:mysql数据库

项目数据获取方式:爬虫(selenium,Xpath)

2:项目功能:

爬取数据后启动项目会把数据都存放在数据库里(数据库有3个表,一个工作岗位信息表,一个用用户信息表,一个工作收藏表),然后进入项目的登陆注册页面,以及会对用户的账号密码经行校验和存储,校验成功后进入首页:

2.1:注册信息如果为空则自定义404报错页面

abc2664264dc431aa0a59ee7dcbb7f74.png

e9daedd376384b278ce01dfe8d7e5234.png

2.2: 注册登录成功进入首页:

ac730c933f84465fabcdba49e956b598.png

ae64f9ffa63f40df9d8fa27943a5ab35.png

左侧为导航状态栏,个人中心有修改个人信息和修改密码的子页面,数据统计有数据总览和岗位收藏的子页面,数据可视化有 薪资,公司信息,员工人数以及企业融资等信息的可视化页面。

中间是一个饼图,可视化的数据为用户的创建时间,饼图右侧是一个用户信息表的展示,接着再右侧是一个对爬取信息的统计(如数据条目总数,用户量,最高学历,最高工资,热门城市以及做多月薪等信息展示),下面是一个技术涉及的跑马灯效果,最后下面就是员工所有信息数据的展示。

a0b72dc912bf429a905cb2807783172b.png

 

2.3:然后是个人信息的展示:

a8a7e36b32b94edc908a90bc1dc38cfe.png

f881b5b1d85949a0a6e5f3eb07660f49.png

2.4:数据总览:用django内置的paginator分页系统对数据经行分页处理

7766a0b1e60a4c14b1d3f5c384b60a33.png  

67990fb544994b709ccd8808f88c03cc.png

bb8e6213823242239065d1d85c182ebf.png

2.5:数据可视化:在前端中使用echars.js对数据经行各种可视化分析,我们只需要把数据库的数据使用django模板语法在js的series字典的data属性经行信息渲染即可。

echars.js官网:Examples - Apache ECharts

eb193d6215704f12b69cdde03548b6dc.png

1958ba32b7354e6cab134ef76bc5f443.png

 

c915848bff43435781e5fe260c2bdd14.png

 

d7b26bcb978d49549fe08bf63cac3408.png

 

 f8ab4fe609ed422694aa3070b3a86b4a.png

8ff6f041f5134740ae88b9316c32a79b.png

 58d1b94ad8b945eaa70927a6c17576fd.png

 23c288ccc3c4446ba63b497fdcc3c907.png

533d9b5fac974b6587e34a699d6f0637.png

0f59c057a0a94627b86eb17f164b2b1f.png

 部分项目内部展示:

c5eae6a402e9463dbb62f1090f71b971.png

 3:项目实现技术流程分析:

3.1:数据爬取:

数据针对boss直聘网站所获取,获取的内容对象为title工作名字,address工作城市,type工作类型,educational学历,workExperience工作经验,workTag工作标签,salary工资,salaryMonth多薪,companyTag公司福利,hrWorkHR岗位,hrNameHR姓名,pratice是否实习,companyTitle公司名字,companyAvatar公司头像,companyNature公司性质,companyStatus公司融资,companyPeopl公司人数,detailUrl岗位详情链接,companyUrl公司详情链接,dist行政区。

我们先从官网拿来两条页面的数据,照片如下:

a1c3147f4f804b4c884150d1f61b478a.png

 

上面的数据和我们想要存放在数据库里的数据格式有点不一样,对此我们对个人数据样式需要做一些处理。

比如薪资信息,如15-30k我们在数据库要展示的类型为[15000,30000],处理过程为首先判断该职位是不是实习岗位,因为实习岗位是没有月薪的,实习的职位是多少多少元/天,我们先用Xpath路径解析来获取该薪资标签的text文本内容也就是15-30k·16薪,可以通过判断该文本字符串内容是否包含K来知道该职位是否实习岗位,包含k则为非实习岗位,然后python分隔符split(·)来把工资和多薪分开,然后用len()方法来获取其长度,如果为1则说明其没有多薪,我们设置为0薪,否则说明为多薪,至于对少薪,我们可以用python的切片来获取并将其多少薪赋值给一个salaryMonth的变量。

 

对于工资值的转换如何从15-30k转换为[15000,30000],代码首先从 salaries 列表中获取第一个元素,并在该元素中将 "K" 替换为空字符串。接着,代码使用 split('-') 方法将该元素按照 "-" 进行分割,得到一个列表。最后,代码使用 map() 函数将该列表中的每个元素都转换成整数,并乘以 1000,得到一个整数类型的列表。例如,如果 salaries[0] 的值为 "10K-20K",那么经过该代码处理后,salary 的值将为 [10000, 20000]。

 

另外对于address城市和dist行政区的赋值就是用xpath来获取去地址标签的文本如武汉市·洪山区·光谷,那我们是需要用ython的切片简单处理就好。

 

公司融资情况也需要做处理,因为我们浏览网站的数据不难发现有些有些公司的融资情况为无,有的显示已上市或者融资对象等等,例如:下面的融资情况为无,有的为有的为融资对象。

 

f26ee9af32064a9b96d0a86f1ca37adf.png

 31edde6cc2764604a2e3f1dd1e49b087.png

 

 

所以我们需要做些处理再放入到数据库,处理过程为:先用selenium库的find_element方法获取王者中的标签元素,遍历标签元素数量,提取公司的性质、融资状态以及公司规模等信息。具体而言,它首先判断网页中是否同时存在包含公司性质、融资状态和公司规模的标签,如果存在,就按顺序提取出它们的文本信息;否则,就认为公司的融资状态为“未融资”,然后提取公司规模信息,这里的公司人数也要做些处理。

 

公司人数也要做处理网站上显示的类型比如为20-99人,我们想要在数据库展示的是[20,99],则处理的过程和上面一样,使用 Selenium 库的 find_element 方法找到网页中符合条件的 HTML 元素,然后使用 split 和 replace 方法对元素的文本进行处理,最终将公司规模信息转化为一个包含两个整数的列表 companyPeople。如果在处理过程中出现异常,比如无法获取到元素或者元素的文本不符合预期,那么这段代码就会跳转到 except 语句块中,使用默认值 [0, 10000] 来代替 companyPeople。

 

公司福利也需要在传入数据库前经行处理因为我们发现有的公司并没有贴上福利内容比如:

082e0da6058847a8a7af2915c02121f1.png

 

这个时候只需要做简单的内容存在判断即可,如果不存在就把字符串“无”赋值即可,避免mysql不允许插入空值的问题。

 

数据爬取处理完毕之后给数据赋值变量后,将其放入到一个jobData的列表,调用os模块的writerow方法写入将其写入到csv里面,接着再对数据做最后的处理JobInfo.objects.create,将其

将其存入数据库里,到此爬取的数据已按照要求全部存入数据库。

 

3.2:登录注册:

注册内容就是纯粹的前端知识,建立一个form表单,把input输入框内容放在里面,建立一个属性为submit的button标签,在view.py视图写入后台逻辑代码,如果request.method == “GET”则键入url对应的地址(注册界面),如果请求方法为request.method == “POST”即提交表单,同时获取输入框提交的内容,然后用数据库User对象User.objects.create方法将数据写入到数据库的用户表里,使用md5 = hashlib.md5() .update(pwd.encode())对数据库的密码经行MD5加盐加密处理同时跳转到登录的url地址页面(检验注册是的账号以及密码就是简单的数据校验弹出提示或报错页面显示就不再说明了)

3.3:首页:

3.3.1:首页-时间&欢迎用户语:

time.localtime()获取当前时间,year = timeFormat.tm_year,month = timeFormat.tm_mon,day = timeFormat.tm_mday获取年月日,由于获取的月份是数字形式,而我们想要的是(June 1,2023)这种格式,所以在此我们创建一个列表放入1-12月的英文monthList=["January","February","March","April","May","June","July","August","September","October","November","December"]

,然后我们需要的月份便可以用monthlist[得到的数字-1]表示,同时欢迎语中的用户名便可使用使用django模板在前端html语法{{ username }}表示即可。

3.3.2:首页-用户创建时间饼状图:

在echars官网找到需要的数据展示图拿来源码在series列表的data字典里把用户时间字段属性值userTime写入即可,为了防止转义在后面加上 | safe,tooltip: { trigger: 'item'},legend: { top: '5%',left: 'center'},则用来实现数据布置图的鼠标悬停动态显示和顶部导航的.

3.3.3:首页-最新用户信息表展示:

前端table标签实现布局就不过多说明,主要说一下数据库中的用户数据的我获取展示,首先用户数据类User.objects.all()来获取数据库中用户的所有对象信息,赋值给Newuser对象里,然后用item.用户字段属性来获取用户字段的值,然后在首页前端页面写入规范的django模板循环语法{% for item in newUser %}即可遍历,记得放在tr标签里一起循环,且用户信息的数据展示规定显示5条且按照创建时间以此显示time.mktime(time.strptime(str(item.createTime),'%Y-%m-%d'))使用time模块中的strptime函数将时间字符串转换为struct_time类型的时间元组,然后再使用mktime函数将时间元组转换为时间戳。时间戳(Timestamp)是指某个特定时间点的标识,通常表示为从某个固定的起点(比如1970年1月1日00:00:00 UTC)开始到该时间点所经过的时间长度,单位可以是秒、毫秒、微秒等。时间戳可以用来表示事件发生的时间、计算事件之间的时间间隔等。在计算机系统中,时间戳通常以整数形式或浮点数形式存储。list(sorted(users,key=sort_fn,reverse=True))[:6]使用sort对时间戳经行排序且切片范围为前5个(包括第5个)

3.3.4:首页-项目技术需求涉及展示:

只需要在前端页面对应的div区域标签引入marquee文字滚动标签设置相关属性如方向,速度,字体大小等,即可改展现的文字内容“跑马灯效果”

3.3.5:首页-右侧数据(数据总量,用户数量,最高学历,最高工资,优势地点,最高多薪,岗位兴致)实现:

数据总量:获取数据库的用户对象,使用len()方法即可同理用户数量。

最高学历:创建一个educations = {"博士": 1, "硕士": 2, "本科": 3, "大专": 4, "高中": 5, "中专/中技": 6, "初中及以下":7,"学历不限": 8}字典,educations[job.educational]<educations[educationsTop]: educationsTop = job.educational对工作数据库的工作经行遍历,创建的educations 字典[工作学历]可以得到所创字典的value数值,用此来和每一个工作表里的工作条目的学历经行比较,找到最大的value数值也即对应所创字典最高的学历,最后就在前端使用django模板语法{{ 最高学历的变量 }}即可。

优势地点:if address.get(job.address,-1) == -1:address[job.address] = 1
else:address[job.address] += 1对job的对象的地址和经验进行计数,如果job对象的地址和经验在字典中不存在,则将其添加到字典中并赋值为1;如果已存在,则将其对应的值加1,这样便可得到如下形式{“地点a”:数值1,“地点b”:数值2.等等}然后调用内置的items()方法将其返回字典的所有键值对,最后addressStr=sorted(address.items(),key=lambda x:x[1],reverse=True)[:3]对其数值经行降序排列且切片到前3个地址并将其连接表示赋值给一个addressstr变量最后在前端规划写入django模板语法{{ addressstr }}即可,最高多薪以及岗位性质同理。

最高薪资:遍历工作表的每一个工资经行对比,找出最高的赋值即可。

3.3.6:首页的数据表格展示:

Jobs=JobInfo.objects.all(),对jobs经行遍历得到每一个job,在前端页面的tbale里经行数据渲染,但对于工资数据表里的是[xk,xk]我们这里要显示的是最高工资每月,所以job.salary = json.loads(i.salary)[1]用json的loads方法把字典里的字符串转换为python对象然后拿到后面(最高工资值)即可,是否实习也要经行个简单处理,因为我们数据库放的是0或者1来表示是否实习的,这里我们只需要做个if else语句即可,以及人数,我们数据库使用[a,b]来表示的,这里我们要展示为a人-b人, json.loads(i.companyPeople)把数据库的属性人数的值拿过来转换python对象,i.companyPeople = list(map(lambda x:str(x) + '人',然后再使用'-'.join(i.companyPeople)把列表里的的两个数用-号连接,便可得到需要的结果形式。

3.4:个人中心:

3.4.1:个人中心-个人信息:

学历,工作经验以及意向岗位选择下拉框的实现是在select标签里循环数据库的学历,工作经验以及岗位类型字段对呀的值,用for 循环来遍历 educations 列表中的每一个元素 e,并使用 if 和 else 语句来判断当前遍历到的元素是否等于 userInfo.educational,如果等于则输出一个选中状态的 option 标签,否则输出一个普通的 option 标签。其中 educations 和 userInfo.educational 都是从后端传递到前端的数据。这段代码的作用是生成一个下拉框,让用户可以选择自己的教育程度。其中educations列表为我们定义的educations 列表= ["博士","硕士","本科","大专","高中","中专/中技","学历不限"]

userInfo.educationa为数据库的学历字段对应的内容值,工作经验和意向岗位选取原理同上。

 

图片的选取是调用了前端的文件input type=“file”

 

然后接着便是提交form表单执行后端视图的post方法调用修改信息函数,该函数接受两个参数newInfo和FileInfo,其中newInfo是一个字典,包含用户的新个人信息,FileInfo是一个字典,包含用户上传的文件信息。该函数使用Django框架中的ORM(对象关系映射)方式来更新用户的个人信息。具体地说,它首先通过get方法从数据库中获取指定用户名的User对象,然后更新该对象的educational、workExpirence、address和work属性。如果FileInfo中的avatar属性不为None,则将其设置为该User对象的avatar属性。最后,使用save方法将更新后的User对象保存回数据库。

3.4.2:个人中心-修改密码:

原理同上.

3.5可视化图标-

3.5.1:薪资情况:

遍历所有非实习的工作,将其岗位类型添加到jobsType里,将其薪资信息中的第二项加入到 jobsType 中对应类型的列表中。形式为{Java[1,2,4,3]}这里列表的内容是java的各个工资合集

接着,代码创建了一个空字典 barData,并遍历 jobsType 中的每个类型,将其薪资列表按照一定区间进行分组,并统计各个区间的数量,将结果存储在 barData 中。最后,代码返回 salaryList、barData 和 barData 的键列表。此时barData形式为{java:[1,2,3,4]}此时列表的内容为不同薪资段的人数。

然后引入echars,在js代码的series: [ {% for k,v in barData.items %}
       { name: '{{ k }}', type: 'bar', data: {{ v }}, }, {% endfor %}]即可展现效果,其中的鼠标悬停的动态效果是tooltip字段。

输入框的选择筛选根据前端页面的option的选择将值传入后端,然后对数据库的工作岗位的每一个对象内容经行object。fillter(筛选条件)即可获取需要的数据然后用前面所说的echars展示即可。

实习生薪资平均值饼图数据展示:使用Django 的 ORM 模块从数据库中获取 JobInfo 对象的所有实例。然后,它创建一个空字典 jobsType 用于存储每种工作类型以及对应的月平均工资,并遍历所有工作信息,筛选出实习经验(pratice=1(实习))的工作信息,并将它们的月平均工资添加到 jobsType 中。

接着创建一个空列表 result,用于存储每种工作类型的月平均工资的总和,然后遍历 jobsType 中的每个键值对,用 自定义的addLis函数(求平均)函数将该工作类型的月平均工资求和。最后,将每种工作类型的名称和月平均工资总和添加到 result 中,并将 result 返回。此时result形式为[{工作类型:该类型薪资均值}]最后在前端的js代码的series将其写入即可。

至于多薪图标的展示,处理JobInfo的对象,筛选出薪资月份数量大于 0 的工作信息,并统计每种薪资月份的数量,返回一个列表和一个字典。其中,列表包含所有薪资月份的字符串,字典包含每种薪资月份及其对应数量的键值对。然后在引入的echars的series列表的data字段设置 {{  louDouData | safe}}即可。

后问部分篇幅略.......................................................................................................................

代码(一小小小部分)就当走个代码量吧,不然博客不好通过热门:

数据库创建:

  1. from django.db import models
  2. # Create your models here.
  3. class JobInfo(models.Model):
  4. id = models.AutoField('id',primary_key=True)
  5. title = models.CharField('工作名',max_length=255,default='')
  6. address = models.CharField('地址',max_length=255,default='')
  7. type = models.CharField('类型',max_length=255,default='')
  8. educational = models.CharField('学历',max_length=255,default='')
  9. workExperience = models.CharField('工作经验',max_length=255,default='')
  10. workTag = models.CharField('工作标签',max_length=2555,default='')
  11. salary = models.CharField('薪资',max_length=255,default='')
  12. salaryMonth = models.CharField('年终奖',max_length=255,default='')
  13. companyTags = models.CharField('公司标签',max_length=2555,default='')
  14. hrWork = models.CharField('人事职位',max_length=255,default='')
  15. hrName = models.CharField('人事名字',max_length=255,default='')
  16. pratice = models.BooleanField('是否为实习单位',max_length=255,default='')
  17. companyTitle = models.CharField('公司名称',max_length=255,default='')
  18. companyAvatar = models.CharField('公司头像',max_length=255,default='')
  19. companyNature = models.CharField('公司性质',max_length=255,default='')
  20. companyStatus = models.CharField('公司状态',max_length=255,default='')
  21. companyPeople = models.CharField('公司人数',max_length=255,default='')
  22. detailUrl = models.CharField('详情地址',max_length=2555,default='')
  23. companyUrl = models.CharField('公司详情地址',max_length=2555,default='')
  24. createTime = models.DateField('创建时间',auto_now_add=True)
  25. dist = models.CharField('行政区',max_length=255,default='')
  26. class Meta:
  27. db_table = "jobInfo"
  28. class User(models.Model):
  29. id = models.AutoField('id',primary_key=True)
  30. username = models.CharField('用户名',max_length=255,default='')
  31. password = models.CharField('密码',max_length=255,default='')
  32. educational = models.CharField('学历',max_length=255,default='')
  33. workExpirence = models.CharField('工作经验',max_length=255,default='')
  34. address = models.CharField('意向城市',max_length=255,default='')
  35. work = models.CharField('意向岗位',max_length=255,default='')
  36. avatar = models.FileField("用户头像",upload_to="avatar",default="avatar/default.png")
  37. createTime = models.DateField("创建时间",auto_now_add=True)
  38. class Meta:
  39. db_table = "user"
  40. class History(models.Model):
  41. id = models.AutoField('id',primary_key=True)
  42. job = models.ForeignKey(JobInfo,on_delete=models.CASCADE)
  43. user = models.ForeignKey(User,on_delete=models.CASCADE)
  44. count = models.IntegerField("点击次数",default=1)
  45. class Meta:
  46. db_table = "histroy"

爬虫代码:

  1. import json
  2. import time
  3. from selenium import webdriver
  4. from selenium.webdriver.chrome.service import Service
  5. from selenium.webdriver.common.by import By
  6. import csv
  7. import pandas as pd
  8. import os
  9. import django
  10. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'boss直聘数据可视化分析.settings')
  11. django.setup()
  12. # 但是还是需要在文件开头添加两行配置环境变量的配置语句,让程序知道该去哪儿寻找 models 中的文件。
  13. from myApp.models import *
  14. class spider(object):
  15. def __init__(self,type,page):
  16. self.type = type
  17. self.page = page
  18. self.spiderUrl = "https://www.zhipin.com/web/geek/job?query=%s&city=100010000&page=%s"
  19. def startBrower(self):
  20. option = webdriver.ChromeOptions()
  21. # option.add_experimental_option("debuggerAddress", "localhost:9222")
  22. option.add_experimental_option("excludeSwitches", ['enable-automation'])
  23. # s = Service("./chromedriver.exe")
  24. # browser = webdriver.Chrome(service=s, options=option)
  25. browser=webdriver.Chrome(executable_path='./chromedriver.exe',options=option)
  26. return browser
  27. def main(self,**info):
  28. if info['page'] < self.page:return
  29. brower = self.startBrower()
  30. print('页表页面URL:' + self.spiderUrl % (self.type,self.page))
  31. brower.get(self.spiderUrl % (self.type,self.page))
  32. time.sleep(15)
  33. # return
  34. job_list = brower.find_elements(by=By.XPATH, value="//ul[@class='job-list-box']/li")
  35. for index,job in enumerate(job_list):
  36. try:
  37. print("爬取的是第 %d 条" % (index + 1))
  38. jobData = []
  39. # title 工作名字
  40. title = job.find_element(by=By.XPATH,
  41. value=".//div[contains(@class,'job-title')]/span[@class='job-name']").text
  42. # address 地址
  43. addresses = job.find_element(by=By.XPATH,
  44. value=".//div[contains(@class,'job-title')]//span[@class='job-area']").text.split(
  45. '·')
  46. address = addresses[0]
  47. # dist 行政区
  48. if len(addresses) != 1:dist = addresses[1]
  49. else: dist = ''
  50. # type 工作类型
  51. type = self.type
  52. tag_list = job.find_elements(by=By.XPATH,
  53. value=".//div[contains(@class,'job-info')]/ul[@class='tag-list']/li")
  54. if len(tag_list) == 2:
  55. educational = job.find_element(by=By.XPATH,
  56. value=".//div[contains(@class,'job-info')]/ul[@class='tag-list']/li[2]").text
  57. workExperience = job.find_element(by=By.XPATH,
  58. value=".//div[contains(@class,'job-info')]/ul[@class='tag-list']/li[1]").text
  59. else:
  60. educational = job.find_element(by=By.XPATH,
  61. value=".//div[contains(@class,'job-info')]/ul[@class='tag-list']/li[3]").text
  62. workExperience = job.find_element(by=By.XPATH,
  63. value=".//div[contains(@class,'job-info')]/ul[@class='tag-list']/li[2]").text
  64. # hr
  65. hrWork = job.find_element(by=By.XPATH,
  66. value=".//div[contains(@class,'job-info')]/div[@class='info-public']/em").text
  67. hrName = job.find_element(by=By.XPATH,
  68. value=".//div[contains(@class,'job-info')]/div[@class='info-public']").text
  69. # workTag 工作标签
  70. workTag = job.find_elements(by=By.XPATH,
  71. value="./div[contains(@class,'job-card-footer')]/ul[@class='tag-list']/li")
  72. workTag = json.dumps(list(map(lambda x: x.text, workTag)))
  73. # salary 薪资
  74. salaries = job.find_element(by=By.XPATH,
  75. value=".//div[contains(@class,'job-info')]/span[@class='salary']").text
  76. # 是否为实习单位
  77. pratice = 0
  78. if salaries.find('K') != -1:
  79. salaries = salaries.split('·')
  80. if len(salaries) == 1:
  81. salary = list(map(lambda x: int(x) * 1000, salaries[0].replace('K', '').split('-')))
  82. salaryMonth = '0薪'
  83. else:
  84. # salaryMonth 年底多薪
  85. salary = list(map(lambda x: int(x) * 1000, salaries[0].replace('K', '').split('-')))
  86. salaryMonth = salaries[1]
  87. else:
  88. salary = list(map(lambda x: int(x), salaries.replace('元/天', '').split('-')))
  89. salaryMonth = '0薪'
  90. pratice = 1
  91. # companyTitle 公司名称
  92. companyTitle = job.find_element(by=By.XPATH, value=".//h3[@class='company-name']/a").text
  93. # companyAvatar 公司头像
  94. companyAvatar = job.find_element(by=By.XPATH,
  95. value=".//div[contains(@class,'job-card-right')]//img").get_attribute(
  96. "src")
  97. companyInfoList = job.find_elements(by=By.XPATH,
  98. value=".//div[contains(@class,'job-card-right')]//ul[@class='company-tag-list']/li")
  99. if len(companyInfoList) == 3:
  100. companyNature = job.find_element(by=By.XPATH,
  101. value=".//div[contains(@class,'job-card-right')]//ul[@class='company-tag-list']/li[1]").text
  102. companyStatus = job.find_element(by=By.XPATH,
  103. value=".//div[contains(@class,'job-card-right')]//ul[@class='company-tag-list']/li[2]").text
  104. try:
  105. companyPeople = list(map(lambda x: int(x), job.find_element(by=By.XPATH,
  106. value=".//div[contains(@class,'job-card-right')]//ul[@class='company-tag-list']/li[3]").text.replace(
  107. '人', '').split('-')))
  108. except:
  109. companyPeople = [0, 10000]
  110. else:
  111. companyNature = job.find_element(by=By.XPATH,
  112. value=".//div[contains(@class,'job-card-right')]//ul[@class='company-tag-list']/li[1]").text
  113. companyStatus = "未融资"
  114. try:
  115. companyPeople = list(map(lambda x: int(x), job.find_element(by=By.XPATH,
  116. value=".//div[contains(@class,'job-card-right')]//ul[@class='company-tag-list']/li[2]").text.replace(
  117. '人', '').split('-')))
  118. except:
  119. companyPeople = [0, 10000]
  120. # companyTag 公司标签
  121. companyTag = job.find_element(by=By.XPATH,
  122. value="./div[contains(@class,'job-card-footer')]/div[@class='info-desc']").text
  123. if companyTag:
  124. companyTag = json.dumps(companyTag.split(','))
  125. else:
  126. companyTag = '无'
  127. # 详情地址
  128. detailUrl = job.find_element(by=By.XPATH,
  129. value="./div[@class='job-card-body clearfix']/a").get_attribute('href')
  130. # 公司详情
  131. companyUrl = job.find_element(by=By.XPATH, value="//h3[@class='company-name']/a").get_attribute('href')
  132. jobData.append(title)
  133. jobData.append(address)
  134. jobData.append(type)
  135. jobData.append(educational)
  136. jobData.append(workExperience)
  137. jobData.append(workTag)
  138. jobData.append(salary)
  139. jobData.append(salaryMonth)
  140. jobData.append(companyTag)
  141. jobData.append(hrWork)
  142. jobData.append(hrName)
  143. jobData.append(pratice)
  144. jobData.append(companyTitle)
  145. jobData.append(companyAvatar)
  146. jobData.append(companyNature)
  147. jobData.append(companyStatus)
  148. jobData.append(companyPeople)
  149. jobData.append(detailUrl)
  150. jobData.append(companyUrl)
  151. jobData.append(dist)
  152. self.save_to_csv(jobData)
  153. except:
  154. pass
  155. self.page += 1
  156. self.main(page=info['page'])
  157. def save_to_csv(self,rowData):
  158. with open('./temp.csv', 'a', newline='', encoding='utf-8') as f:
  159. writer = csv.writer(f)
  160. writer.writerow(rowData)
  161. def clear_numTemp(self):
  162. with open('./numTemp.txt','w',encoding='utf-8') as f:
  163. f.write('')
  164. def init(self):
  165. if not os.path.exists('./temp.csv'):
  166. with open('./temp.csv','a',newline='',encoding='utf-8') as f:
  167. writer = csv.writer(f)
  168. writer.writerow(["title","address","type","educational","workExperience","workTag","salary","salaryMonth",
  169. "companyTags","hrWork","hrName","pratice","companyTitle","companyAvatar","companyNature",
  170. "companyStatus","companyPeople","detailUrl","companyUrl","dist"])
  171. def save_to_sql(self):
  172. data = self.clearData()
  173. for job in data:
  174. JobInfo.objects.create(
  175. title=job[0],
  176. address = job[1],
  177. type = job[2],
  178. educational = job[3],
  179. workExperience = job[4],
  180. workTag = job[5],
  181. salary = job[6],
  182. salaryMonth = job[7],
  183. companyTags = job[8],
  184. hrWork = job[9],
  185. hrName = job[10],
  186. pratice = job[11],
  187. companyTitle = job[12],
  188. companyAvatar = job[13],
  189. companyNature = job[14],
  190. companyStatus = job[15],
  191. companyPeople = job[16],
  192. detailUrl = job[17],
  193. companyUrl = job[18],
  194. dist=job[19]
  195. )
  196. print("导入数据库成功")
  197. os.remove("./temp.csv")
  198. def clearData(self):
  199. df = pd.read_csv('./temp.csv')
  200. df.dropna(inplace=True)
  201. df.drop_duplicates(inplace=True)
  202. df['salaryMonth'] = df['salaryMonth'].map(lambda x:x.replace('薪',''))
  203. print("总条数为%d" % df.shape[0])
  204. return df.values
  205. if __name__ == '__main__':
  206. spiderObj = spider("go",1);
  207. spiderObj.init()
  208. spiderObj.main(page=10)
  209. spiderObj.save_to_sql()

首页后台函数:

  1. from myApp.models import User,JobInfo
  2. from .publicData import *
  3. import time
  4. import json
  5. # 首页时间+欢迎语
  6. def getNowTime():
  7. timeFormat = time.localtime()
  8. year = timeFormat.tm_year
  9. month = timeFormat.tm_mon
  10. day = timeFormat.tm_mday
  11. monthList = ["January","February","March","April","May","June","July","August","September","October","November","December"]
  12. return year,monthList[month - 1],day
  13. # 首页右侧7指标
  14. def getTagData():
  15. jobs = getAllJobInfo()
  16. users = getAllUser()
  17. educationsTop = "学历不限"
  18. salaryTop = 0
  19. salaryMonthTop = 0
  20. address = {}
  21. pratice = {}
  22. for job in jobs:
  23. if educations[job.educational] < educations[educationsTop]:
  24. educationsTop = job.educational
  25. # 仅仅针对非实习岗位
  26. if not job.pratice:
  27. salary = json.loads(job.salary)[1]
  28. if salaryTop < salary:
  29. salaryTop = salary
  30. if int(job.salaryMonth) > salaryMonthTop:
  31. salaryMonthTop = int(job.salaryMonth)
  32. # 这段代码的作用是判断一个字典 address 中是否包含 key 为 job.address 的元素。
  33. # 如果不包含,则向字典中添加一个 key 为 job.addressvalue1 的元素。如果包含,则不进行任何操作。
  34. if address.get(job.address,-1) == -1:
  35. address[job.address] = 1
  36. else:
  37. address[job.address] += 1
  38. if pratice.get(job.pratice,-1) == -1:
  39. pratice[job.pratice] = 1
  40. else:
  41. pratice[job.pratice] += 1
  42. addressStr = sorted(address.items(),key=lambda x:x[1],reverse=True)[:3]
  43. addressTop = ""
  44. for i in addressStr:
  45. addressTop += i[0] + ","
  46. praticeMax = sorted(pratice.items(),key=lambda x:x[1],reverse=True)
  47. # a = "普通岗位" ? praticeMax[0][0] == False : "实习岗位"
  48. return len(jobs),len(users),educationsTop,salaryTop,salaryMonthTop,addressTop,praticeMax[0][0]
  49. def getUserCreateTime():
  50. users = getAllUser()
  51. data = {}
  52. for u in users:
  53. if data.get(str(u.createTime),-1) == -1:
  54. data[str(u.createTime)] = 1
  55. else:
  56. data[str(u.createTime)] += 1
  57. result = []
  58. for k,v in data.items():
  59. result.append({
  60. 'name':k,
  61. 'value':v
  62. })
  63. return result
  64. def getUserTop5():
  65. users = getAllUser()
  66. def sort_fn(item):
  67. return time.mktime(time.strptime(str(item.createTime),'%Y-%m-%d'))
  68. users = list(sorted(users,key=sort_fn,reverse=True))[:6]
  69. return users
  70. def getAllJobsPBar():
  71. jobs = getAllJobInfo()
  72. tempData = {}
  73. for job in jobs:
  74. if tempData.get(str(job.createTime),-1) == -1:
  75. tempData[str(job.createTime)] = 1
  76. else:
  77. tempData[str(job.createTime)] += 1
  78. def sort_fn(item):
  79. item = list(item)
  80. return time.mktime(time.strptime(str(item[0]), '%Y-%m-%d'))
  81. result = list(sorted(tempData.items(),key=sort_fn,reverse=False))
  82. def map_fn(item):
  83. item = list(item)
  84. item.append(round(item[1] / len(jobs),3))
  85. return item
  86. result = list(map(map_fn,result))
  87. return result
  88. def getTableData():
  89. jobs = getAllJobInfo()
  90. for i in jobs:
  91. i.workTag = '/'.join(json.loads(i.workTag))
  92. if i.companyTags != "无":
  93. i.companyTags = '/'.join(json.loads(i.companyTags))
  94. i.companyPeople = json.loads(i.companyPeople)
  95. i.companyPeople = list(map(lambda x:str(x) + '人',i.companyPeople))
  96. i.companyPeople = '-'.join(i.companyPeople)
  97. i.salary = json.loads(i.salary)[1]
  98. return jobs
  99. # jobs[0].workTags = '/'.join(json.loads(jobs[0].workTag))
  100. # def map_fn(item):
  101. # item.workTag = "/".join()
  102. # jobs = list(map(map_fn,jobs))

 

说明:由于代码量较多,详细介绍流程会占用不少时间和篇幅,项目对应的word文档我已经全部写好了,需要的话我会把项目文件包含word文档说明一起打包给你们的,另外如果那么跑不出来,我可以远程给你们操作,确保你们都能跑出来的。

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/371878
推荐阅读
相关标签
  

闽ICP备14008679号