1. # -*- coding: utf-8 -*-
  2.  
  3. # 爬虫分析
  4. from bs4 import BeautifulSoup
  5. from lxml import etree
  6. from selenium import webdriver
  7. import time
  8. from pymongo import MongoClient
  9.  
  10. class WorkSpider:
  11. def __init__(self):
  12. self.client = MongoClient('mongodb://localhost:27017/')
  13. self.zfdb = self.client.zfdb
  14. #self.zfdb.authenticate("mongodbUser", "yourpassward")
  15.  
  16. # 要爬取的城市列表
  17. def getCity(self):
  18. return [
  19. "全国",
  20. "北京",
  21. "郑州",
  22. #"上海",
  23. #"深圳",
  24. #"广州",
  25. ]
  26.  
  27. # 要爬取的语言列表
  28. def getLanguage(self):
  29. return [
  30. "Java",
  31. "Python",
  32. # "C",
  33. # "机器学习",
  34. # "图像识别",
  35. # "自然语言处理",
  36. # "区块链",
  37. # "精准推荐",
  38. # "Node.js",
  39. # "Go",
  40. # "Hadoop",
  41. # "Php",
  42. # ".NET",
  43. # "Android",
  44. # "iOS",
  45. # "web前端",
  46. ]
  47.  
  48. # 经过观察发现,拉钩的 url 随语言和城市的变化如下
  49. def getUrl(self, language, city):
  50. url = "https://www.lagou.com/jobs/list_" + language + "?px=default&city=" + city
  51. return url
  52.  
  53. # 获取一个城市,列表中所有语言的 url 列表
  54. def getCityUrl(self, city):
  55. urlList = []
  56. for language in self.getLanguage():
  57. urlList.append(self.getUrl(language, city))
  58. return urlList
  59.  
  60. # 获取一门语言,不同城市的 url 列表
  61. def getLanguageUrl(self, language):
  62. urlList = []
  63. for city in self.getCity():
  64. urlList.append(self.getUrl(language, city))
  65. return urlList
  66.  
  67. def getOnePageData(self):
  68.  
  69. pass
  70.  
  71. # MongoDB 存储数据结构
  72. def getRentMsg(self, name, company, welfare, salaryMin, salaryMid, salaryMax, experience, education, companyType,
  73. companyLevel, companySize):
  74. return {
  75. "name": name, # 职位名称(python工程师)
  76. "company": company, # 公司名称(xxx有限公司)
  77. "welfare": welfare, # 福利(餐补、下午茶、带薪年假)
  78. "salaryMin": salaryMin, # 工资下限(9k)
  79. "salaryMid": salaryMid, # 工资下限(9k+15k)/2
  80. "salaryMax": salaryMax, # 工资上限(15k)
  81. "experience": experience, # 工作经验(经验3-5年)
  82. "education": education, # 教育程度(本科)
  83. "companyType": companyType, # 公司类型(移动互联网/信息安全)
  84. "companyLevel": companyLevel, # 公司级别(上市公司)
  85. "companySize": companySize, # 公司人数规模(150-500人)
  86. }
  87.  
  88. # 获取网页源码数据
  89. # language => 编程语言
  90. # city => 城市
  91. # collectionType => 值:True/False True => 数据库表以编程语言命名 False => 以城市命名
  92. def main(self, language, city, collectionType):
  93. print(" 当前爬取的语言为 => " + language + " 当前爬取的城市为 => " + city)
  94. #print(" 当前爬取的语言为 => " + language + " 当前爬取的城市为 => " + city)
  95. #print(" 当前爬取的语言为 => " + language + " 当前爬取的城市为 => " + city)
  96. url = self.getUrl(language, city)
  97. print(" 当前爬取的路径为 => " + url )
  98. chrome_options = webdriver.ChromeOptions()
  99. chrome_options.add_argument('--start-maximized') # 最大化运行(全屏窗口),不设置,取元素会报错
  100. chrome_options.add_argument('--disable-infobars') # 禁用浏览器正在被自动化程序控制的提示
  101. chrome_options.add_argument('--incognito') # 隐身模式(无痕模式)
  102. #chrome_options.add_argument('--headless') # 浏览器不提供可视化页面
  103. browser = webdriver.Chrome(executable_path = "chromedriver",options=chrome_options)
  104. #browser = webdriver.Chrome("chromedriver")
  105. browser.get(url)
  106. browser.implicitly_wait(10)
  107. for i in range(30):
  108. selector = etree.HTML(browser.page_source) # 获取源码
  109. soup = BeautifulSoup(browser.page_source, "html.parser")
  110. span = soup.find("div", attrs={"class": "pager_container"}).find("span", attrs={"action": "next"})
  111. print("span =>" + str(span)) # <span action="next" class="pager_next pager_next_disabled" hidefocus="hidefocus">下一页<strong class="pager_lgthen pager_lgthen_dis"></strong></span>
  112. classArr = span['class']
  113. print("classArr =>"+ str(classArr)) # 输出内容为 -> ['pager_next', 'pager_next_disabled']
  114. attr2 = list(classArr)[1]
  115. if attr2 == "pager_next_disabled":
  116. print("已经爬到最后一页,爬虫结束")
  117. break
  118. else:
  119. print("还有下一页,爬虫继续")
  120. #browser.find_element_by_xpath('//*[@id="order"]/li/div[4]/div[2]').click() # 点击下一页
  121. browser.find_element_by_xpath('//span[@class="pager_is_current"]/following-sibling::span').click() # 点击下一页
  122. time.sleep(5)
  123. print('第{}页抓取完毕'.format(i + 1))
  124. self.getItemData(selector, language, city, collectionType)
  125. browser.close()
  126.  
  127. # 解析一条 item 数据,并存进数据库
  128. def getItemData(self, selector, language, city, collectionType):
  129. items = selector.xpath('//*[@id="s_position_list"]/ul/li')
  130. for item in items:
  131. try:
  132. name = item.xpath('div[1]/div[1]/div[1]/a/h3/text()')[0]
  133. company = item.xpath('div[1]/div[2]/div[1]/a/text()')[0]
  134. welfare = item.xpath('div[2]/div[2]/text()')[0]
  135. salaryArray = item.xpath('div[1]/div[1]/div[2]/div/span/text()')[0].strip().split("-")
  136. salaryMin = salaryArray[0][:len(salaryArray[0]) - 1]
  137. salaryMax = salaryArray[1][:len(salaryArray[1]) - 1]
  138. salaryMid = (int(salaryMin) + int(salaryMax)) / 2
  139. educationArray = item.xpath('div[1]/div[1]/div[2]/div//text()')[3].strip().split("/")
  140. education = educationArray[0].strip()
  141. experience = educationArray[1].strip()
  142. conmpanyMsgArray = item.xpath('div[1]/div[2]/div[2]/text()')[0].strip().split("/")
  143. companyType = conmpanyMsgArray[0].strip()
  144. companyLevel = conmpanyMsgArray[1].strip()
  145. companySize = conmpanyMsgArray[2].strip()
  146.  
  147. data = self.getRentMsg(
  148. name,
  149. company,
  150. welfare,
  151. int(salaryMin),
  152. salaryMid,
  153. int(salaryMax),
  154. experience,
  155. education,
  156. companyType,
  157. companyLevel,
  158. companySize
  159. )
  160. if collectionType:
  161. self.zfdb["z_" + language].insert_one(data)
  162. else:
  163. self.zfdb["z_" + city].insert_one(data)
  164.  
  165. print(data)
  166. except:
  167. print("======= exception =======")
  168. continue
  169.  
  170. spider = WorkSpider()# 职业爬虫
  171. for language in spider.getLanguage():
  172. for city in spider.getCity():
  173. spider.main(language, city, True)
  174. time.sleep(5)

Spider.py

以上是爬取功能的全部代码:

参考github上的源码修改:

主要步骤如下:

1、组装url

2、selenium爬取数据

3、存入数据库mongo

4、去广告:

        browser.get(url)
        browser.implicitly_wait(10)
        try:
            browser.find_element_by_xpath('//div[@class="body-container showData"]/div/div[2]').click()  # 点击广告
        except:
            pass

---------------------------------------------------------------------------------------------------------------------------------------------------------

分析数据:

  1. # -*- coding: utf-8 -*-
  2. # 数据分析,数据可视化
  3. from os import path
  4. from wordcloud import WordCloud, ImageColorGenerator
  5. import jieba.analyse
  6. import matplotlib.pyplot as plt
  7. #from scipy.misc
  8. import imageio
  9. import os
  10. import time
  11. from pymongo import MongoClient
  12.  
  13. class Analycis:
  14. def __init__(self):
  15. self.client = MongoClient('mongodb://localhost:27017/')
  16. self.zfdb = self.client.zfdb
  17. #self.zfdb.authenticate("mongodbUser", "yourpassward")
  18.  
  19. def getCity(self):
  20. return [
  21. "全国",
  22. "北京",
  23. "郑州",
  24. #"上海",
  25. #"深圳",
  26. #"广州",
  27. ]
  28.  
  29. def getLanguage(self):
  30. return [
  31. "Java",
  32. "Python",
  33. # "C",
  34. # "机器学习",
  35. # "图像识别",
  36. # "自然语言",
  37. # "区块链",
  38. # "Go",
  39. # "Php",
  40. # ".NET",
  41. # "Android",
  42. # "iOS",
  43. # "web前端",
  44. # "精准推荐",
  45. # "Node.js",
  46. # "Hadoop",
  47.  
  48. ]
  49.  
  50. # 统计的数据量
  51. # 各语言平均工资
  52. # 各语言学历要求
  53. # 各语言工作年限要求
  54. #
  55.  
  56. # 福利词云
  57. # 公司级别排行(A轮、B轮)
  58. # 公司类型排行
  59.  
  60. # 获取各语言样本数量
  61. def getLanguageNum(self):
  62. analycisList = []
  63. for index, language in enumerate(self.getLanguage()):
  64. collection = self.zfdb["z_" + language]
  65. totalNum = collection.aggregate([{'$group': {'_id': '', 'total_num': {'$sum': 1}}}])
  66. totalNum2 = list(totalNum)[0]["total_num"]
  67. analycisList.append(totalNum2)
  68. return (self.getLanguage(), analycisList)
  69.  
  70. # 获取各语言的平均工资
  71. def getLanguageAvgSalary(self):
  72. analycisList = []
  73. for index, language in enumerate(self.getLanguage()):
  74. collection = self.zfdb["z_" + language]
  75. totalSalary = collection.aggregate([{'$group': {'_id': '', 'total_salary': {'$sum': '$salaryMid'}}}])
  76. totalNum = collection.aggregate([{'$group': {'_id': '', 'total_num': {'$sum': 1}}}])
  77. totalNum2 = list(totalNum)[0]["total_num"]
  78. totalSalary2 = list(totalSalary)[0]["total_salary"]
  79. analycisList.append(round(totalSalary2 / totalNum2, 2))
  80. return (self.getLanguage(), analycisList)
  81.  
  82. # 获取一门语言的学历要求(用于 pyecharts 的词云)
  83. def getEducation(self, language):
  84. results = self.zfdb["z_" + language].aggregate([{'$group': {'_id': '$education', 'weight': {'$sum': 1}}}])
  85. educationList = []
  86. weightList = []
  87. for result in results:
  88. educationList.append(result["_id"])
  89. weightList.append(result["weight"])
  90. # print(list(result))
  91. return (educationList, weightList)
  92.  
  93. # 获取一门语言的工作年限要求(用于 pyecharts 的词云)
  94. def getExperience(self, language):
  95. results = self.zfdb["z_" + language].aggregate([{'$group': {'_id': '$experience', 'weight': {'$sum': 1}}}])
  96. totalAvgPriceDirList = []
  97. for result in results:
  98. totalAvgPriceDirList.append(
  99. {"value": result["weight"], "name": result["_id"] + " " + str(result["weight"])})
  100. return totalAvgPriceDirList
  101.  
  102. # 获取 welfare 数据,用于构建福利词云
  103. def getWelfare(self):
  104. content = ''
  105. queryArgs = {}
  106. projectionFields = {'_id': False, 'welfare': True} # 用字典指定
  107. for language in self.getLanguage():
  108.  
  109. collection = self.zfdb["z_" + language]
  110. searchRes = collection.find(queryArgs, projection=projectionFields).limit(1000)
  111. for result in searchRes:
  112. print(result["welfare"])
  113. content += result["welfare"]
  114. return content
  115.  
  116. # 获取公司级别排行(用于条形图)
  117. def getAllCompanyLevel(self):
  118. levelList = []
  119. weightList = []
  120. newWeightList = []
  121. attrList = ["A轮", "B轮", "C轮", "D轮及以上", "不需要融资", "上市公司"]
  122. for language in self.getLanguage():
  123. collection = self.zfdb["z_" + language]
  124. # searchRes = collection.find(queryArgs, projection=projectionFields).limit(1000)
  125. results = collection.aggregate([{'$group': {'_id': '$companyLevel', 'weight': {'$sum': 1}}}])
  126. for result in results:
  127. levelList.append(result["_id"])
  128. weightList.append(result["weight"])
  129. for index, attr in enumerate(attrList):
  130. newWeight = 0
  131. for index2, level in enumerate(levelList):
  132. if attr == level:
  133. newWeight += weightList[index2]
  134. newWeightList.append(newWeight)
  135. return (attrList, newWeightList)
  136.  
  137. # ========================================================
  138.  
  139. # 展示饼图
  140. def showPie(self, title, attr, value):
  141. from pyecharts import Pie
  142. pie = Pie(title)
  143. # pie.add("aa", attr, value, is_label_show=True, title_pos='center')
  144. pie.add("",
  145. attr,
  146. value,
  147. radius=[40, 75],
  148. label_text_color=None,
  149. is_label_show=True,
  150. legend_orient="vertical",
  151. legend_pos="left", )
  152. pie.render()
  153.  
  154. # 展示矩形树图
  155. def showTreeMap(self, title, data):
  156. from pyecharts import TreeMap
  157. data = data
  158. treemap = TreeMap(title, width=1200, height=600)
  159. treemap.add("深圳", data, is_label_show=True, label_pos='inside', label_text_size=19)
  160. treemap.render()
  161.  
  162. # 展示条形图
  163. def showLine(self, title, attr, value):
  164. from pyecharts import Bar
  165. bar = Bar(title)
  166. bar.add("深圳", attr, value, is_convert=False, is_label_show=True, label_text_size=18, is_random=True,
  167. xaxis_interval=0,
  168. # xaxis_label_textsize=9,
  169. legend_text_size=18, label_text_color=["#000"])
  170. bar.render()
  171.  
  172. # 展示词云
  173. def showWorkCloud(self, content, image_filename, font_filename, out_filename):
  174. d = path.dirname(__name__)
  175. # content = open(path.join(d, filename), 'rb').read()
  176. # 基于TF-IDF算法的关键字抽取, topK返回频率最高的几项, 默认值为20, withWeight
  177. # 为是否返回关键字的权重
  178. tags = jieba.analyse.extract_tags(content, topK=100, withWeight=False)
  179. text = " ".join(tags)
  180. # 需要显示的背景图片
  181. img = imageio.imread(path.join(d, image_filename))
  182. # 指定中文字体, 不然会乱码的
  183. wc = WordCloud(font_path=font_filename,
  184. background_color='black',
  185. # 词云形状,
  186. mask=img,
  187. # 允许最大词汇
  188. max_words=500,
  189. # 最大号字体,如果不指定则为图像高度
  190. max_font_size=130,
  191. # 画布宽度和高度,如果设置了msak则不会生效
  192. # width=600,
  193. # height=400,
  194. margin=2,
  195. # 词语水平摆放的频率,默认为0.9.即竖直摆放的频率为0.1
  196. prefer_horizontal=0.9
  197. )
  198. wc.generate(text)
  199. img_color = ImageColorGenerator(img)
  200. plt.imshow(wc.recolor(color_func=img_color))
  201. wc.to_file("loutput.jpeg")
  202. plt.axis("off")
  203. plt.show()
  204. wc.to_file(path.join(d, out_filename))
  205.  
  206. # 展示 pyecharts 的词云
  207. def showPyechartsWordCloud(self, attr, value):
  208. from pyecharts import WordCloud
  209. wordcloud = WordCloud(width=1300, height=620)
  210. wordcloud.add("", attr, value, word_size_range=[20, 100])
  211. wordcloud.render()
  212.  
  213. analycis = Analycis()
  214.  
  215. # 计算样本数量
  216. (attr, value) = analycis.getLanguageNum()
  217. analycis.showLine("样本数量", attr, value)
  218. os.rename("render.html","sampleNum.html")
  219.  
  220. # 计算样本数量
  221. (attr, value) = analycis.getLanguageAvgSalary()
  222. analycis.showLine("各语言平均工资", attr, value)
  223. os.rename("render.html","languageAvgSalary.html")
  224.  
  225. # 语言学历要求
  226. for language in analycis.getLanguage():
  227. (attr, value) = analycis.getEducation(language)
  228. print(attr, value)
  229. analycis.showPie(" "+language + " 工作年限", attr, value)
  230. os.rename("render.html", "./languageEducation/" + language + "Education.html")
  231. #
  232.  
  233. # 语言工作年限要求要求
  234. for language in analycis.getLanguage():
  235. data = analycis.getExperience(language)
  236. print(data)
  237. analycis.showTreeMap(" "+language+"工作学历要求", data)
  238. os.rename("render.html", "./languageExperience/" + language + "Experience.html")
  239.  
  240. # 福利词云
  241. analycis.showWorkCloud(analycis.getWelfare(), "docker.jpeg", "kh.ttf", out_filename="loutput.jpeg")
  242.  
  243. # 公司级别(A轮、B轮) pyechart 词云
  244. (attr, value) = analycis.getAllCompanyLevel()
  245. print(attr, value)
  246. analycis.showLine("公司级别", attr, value)
  247. os.rename("render.html", "companyLevel.html")

分析

python爬取招聘网站数据的更多相关文章

  1. Python爬取招聘网站数据,给学习、求职一点参考

    1.项目背景 随着科技的飞速发展,数据呈现爆发式的增长,任何人都摆脱不了与数据打交道,社会对于“数据”方面的人才需求也在不断增大.因此了解当下企业究竟需要招聘什么样的人才?需要什么样的技能?不管是对于 ...

  2. python爬取某个网站的图片并保存到本地

    python爬取某个网站的图片并保存到本地 #coding:utf- import urllib import re import sys reload(sys) sys.setdefaultenco ...

  3. Python爬取招聘信息,并且存储到MySQL数据库中

    前面一篇文章主要讲述,如何通过Python爬取招聘信息,且爬取的日期为前一天的,同时将爬取的内容保存到数据库中:这篇文章主要讲述如何将python文件压缩成exe可执行文件,供后面的操作. 这系列文章 ...

  4. 利用Python爬取朋友圈数据,爬到你开始怀疑人生

    人生最难的事是自我认知,用Python爬取朋友圈数据,让我们重新审视自己,审视我们周围的圈子. 文:朱元禄(@数据分析-jacky) 哲学的两大问题:1.我是谁?2.我们从哪里来? 本文 jacky试 ...

  5. python 爬取网页简单数据---以及详细解释用法

    一.准备工作(找到所需网站,获取请求头,并用到请求头) 找到所需爬取的网站(这里举拉勾网的一些静态数据的获取)----------- https://www.lagou.com/zhaopin/Pyt ...

  6. python爬取股票最新数据并用excel绘制树状图

    大家好,最近大A的白马股们简直 跌妈不认,作为重仓了抱团白马股基金的养鸡少年,每日那是一个以泪洗面啊. 不过从金融界最近一个交易日的大盘云图来看,其实很多中小股还是红色滴,绿的都是白马股们. 以下截图 ...

  7. 如何使用python爬取网页动态数据

    我们在使用python爬取网页数据的时候,会遇到页面的数据是通过js脚本动态加载的情况,这时候我们就得模拟接口请求信息,根据接口返回结果来获取我们想要的数据. 以某电影网站为例:我们要获取到电影名称以 ...

  8. python爬取电影网站信息

    一.爬取前提1)本地安装了mysql数据库 5.6版本2)安装了Python 2.7 二.爬取内容 电影名称.电影简介.电影图片.电影下载链接 三.爬取逻辑1)进入电影网列表页, 针对列表的html内 ...

  9. 用Python爬取斗鱼网站的一个小案例

    思路解析: 1.我们需要明确爬取数据的目的:为了按热度查看主播的在线观看人数 2.浏览网页源代码,查看我们需要的数据的定位标签 3.在代码中发送一个http请求,获取到网页返回的html(需要注意的是 ...

随机推荐

  1. 侯捷C++学习(一)

    //c++学习//标准库非常重要//要规范自己的代码complex c1(2,1);complex c2;complex* pc = new complex(0,1);string s1(" ...

  2. 《新标准C++程序设计》4.5(C++学习笔记15)

    实例:长度可变的整型数组类 int main() { //要编写可变长整型数组类,使之能如下使用: CArray a; //开始里的数组是空的 ; i < ; ++i) a.push_back( ...

  3. ACM-最优配餐

    题目描述: 最优配餐  时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 栋栋最近开了一家餐饮连锁店,提供外卖服务.随着连锁店越来越多,怎么合理的给客户送餐成为了一个急需解决的问 ...

  4. 觉醒 闭包/this

    两条非常重要的知识点 首先上题 var a = '322' var preview = function() { var a = '123' console.log(a, this, this.a) ...

  5. 循环指令 LOOP

    循环程序: 如果需要重复执行若干次同样任务.用循环执行 循环指令: LOOP <跳转标号> 用累加器的低字做循环计数器 每次执行LOOP 指令的时候,累加器的低字减去1 若减去后 非零 , ...

  6. maven的概念模型及maven坐标

     1.概念模型 项目对象模型:一个maven工程有一个pom.xml文件,通过pom.xml文件定义项目的坐标.项目依赖.项目信息.插件目标等. 依赖管理系统:通过maven的依赖管理对项目所依赖的j ...

  7. centos7如何修改IP地址

    步骤1:使用vi编辑 /etc/sysconfig/network-scripts/目录下的ifcfg-ens160 配置文件 [root@model ~]# [root@model ~]# vi / ...

  8. ES6 之 Proxy

    概述 Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改. Proxy 可以理解在目标对象架设一个“拦截”层外界对该对象的访问都必须先通过这层拦截,因此提供了一种机制可以对外界的访问进行 ...

  9. unicode字符等价探究

    Demobaidu.com(\uff41)能跳转到baidu.combаidu.com(\u0430)不能跳转到baidu.com,被认为成一个其他域名 等价原因两个不同编码的Unicode字符之间可 ...

  10. java IO 流关系图谱

    学习io流最好明白其之间的 关联与转换关系 ,以下是笔者所划得 关系图谱,大框包含小框 ,小框是大框内的 请求参数,箭头是继承或实现. 清晰了其关联与包含关系后我们便很容易在现实中结合使用了 . 这是 ...