700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 拉钩网招聘信息爬虫项目

拉钩网招聘信息爬虫项目

时间:2022-11-04 10:35:39

相关推荐

拉钩网招聘信息爬虫项目

需求分析

知己知彼,方可百战不殆。在学习技术的时候我们往往面临太多选择而不知所措,可能是各个方面都有

涉猎,对某个领域没有深入研究,看似什么都会,真要让你做个什么东西的时候就显得捉肘见襟。如果

我们能从招聘职位所需的技能开始学习,便可练就一身硬功夫,为实战应用中打下良好的基础。

通过python抓取拉钩网的招聘详情,并筛选其中的技能关键词,存储到 excel 中。

职位需求页面分析

通过观察可以发现,拉勾网的职位页面详情是由 /jobs/

PositionId.html 组成。

而 PositionId 可以通过分析 Json 的 XHR 获得。而红框里的职位描述内容是我们要抓取的数据。

知道了数据的源头,接下来就按照常规步骤包装 Headers ,提交 FormData 来获取反馈数据。

PositionId 数据采集

注意:

拉勾网反爬虫做的比较严,请求头多添加几个参数才能不被网站识别。

我们找到真正的请求网址,发现返回的是一个 JSON 串,解析这个 JSON 串即可,而且注意是 POST

传值,通过改变 Form Data 中 pn 的值来控制翻页。

XHR : XMLHttpRequest 对象用于和服务器交换数据。

点击页面中的页数,比如第 2 页,我们可以在右边看到一个 POST 请求,这个请求里面包含了真实的

URL( 浏览器上的 URL 并没有职位数据,查看源代码就可以发现这一点)、 POST 请求的请求头

Headers 、 POST 请求提交的表单 Form Data (这里面包含了页面信息 pn 、搜索的职位信息 kd )

真实的URL获取

请求头信息

我们需要构造的请求头Headers信息,如果这里没有构造好的话,容易被网站识别为爬虫,从而拒绝访问请求。

表单信息

发送POST请求时需要包含的表单信息 Form Data 。

返回的JSON数据

发现需要的职位信息在 content –> positionResult –> result 下,其中包含了工作地点、公司名、职位等信息。 我们只需要保存这个数据就可以了。

至此我们分析完毕网页,下面可以开始爬取过程了。

项目代码

配置文件 config.py 文件

"""Date: --14 10:36User: yzEmail: 1147570523@Desc:"""from fake_useragent import UserAgentimport requestsHost=''Accept='application/json, text/javascript, */*; q=0.01'Connection='keep-alive'Origin=''Referer='/jobs/list_python'ua=UserAgent(verify_ssl=False)url = 'http://172.25.254.39:9999/get_proxy/'proxies = requests.get(url).textpages = 20# 存储信息的csv文件位置csv_filename = 'lagou.csv'# 多线程开启的线程数;ThreadCount = 100

核心代码文件 run.py

数据存储:

csv 格式

开启线程池,批量爬取职位信息,并存储于 csv 文件;

修改文件run.py : 封装页面爬取和页面解析的任务;

"""Date: --14 10:10User: yzEmail: 1147570523@Desc:"""import requestsimport loggingimport pandas as pdimport timeimport pprintfrom config import *from concurrent.futures import ThreadPoolExecutorlogging.basicConfig(level=logging.DEBUG,format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',datefmt='%a, %d %b %Y %H:%M:%S',filename='lagou.log',filemode='w')def getPositionIDPage(url_start, url_parse, page=1, kd='python'):headers = {'User-Agent': ua.random,'Host': Host,'Origin': Origin,'Referer': Referer,'Connection': Connection,'Accept': Accept,'proxies': proxies}# 构造表单data = {'first': True,'pn': str(page),'kd': kd}try:# requests库的session对象能够帮我们跨请求保持某些参数,# 也会在同一个session实例发出的所有请求之间保持cookies。# 创建一个session对象session = requests.Session()# 用session对象发出get请求,设置cookiessession.get(url_start, headers=headers, timeout=3) # 请求首页获取cookiescookie = session.cookies # 为此次获取的cookies# 用session对象发出另外一个post请求,获取cookies , 返回响应信息response = session.post(url=url_parse,headers=headers,data=data,)time.sleep(1)# 响应状态码为4xx客户端错误,或者5xx服务器错误响应,来抛出异常:response.raise_for_status()response.encoding = response.apparent_encoding# print(cookie)except Exception as e:logging.error("页面" + url_parse + "爬取失败:", e)else:logging.info("页面" + url_parse + "爬取成功" + str(response.status_code))return response.json()def analyse_PositionID(html):"""根据获取的页面解析每一个招聘页面详情都有一个所属的ID索引:param html::return:"""# tag = 'positionId'positions = html['content']['positionResult']['result']df = pd.DataFrame(positions)return dfdef task(page):# 拉勾网页面url_start = '/jobs/list_python'url_parse = '/jobs/positionAjax.json?needAddtionalResult=false'html = getPositionIDPage(url_start, url_parse,page=page)# pprint.pprint(content)df = analyse_PositionID(html)# 解析页面, 返回DataFrame格式的数据;return dfdef save_as_csv():"""将获取的页面解析后的信息通过多线程的方式以csv格式存储到文件:return:"""# 开启线程池with ThreadPoolExecutor(ThreadCount) as pool:# map方法中,可迭代对象传入函数是从前到后逐个提取元素, 并将结果依次存储到results中;results = pool.map(task, range(1, pages + 1))# 拼接获取的所有信息, axis=0代表往跨行(down),而axis=1代表跨列(across)total_df = pd.concat(results, axis=0)"""sep: 输出文件的字段分隔符, 默认为逗号;header: 是否写出列名;index: 是否写入行名称(索引);"""total_df.to_csv(csv_filename, sep=',', header=True, index=False)logging.info("文件%s存储成功" % (csv_filename))return total_dfif __name__ == '__main__':save_as_csv()

PositionId 页面解析

获取所需的岗位ID,每一个招聘页面详情都有一个所属的ID索引。将我们爬取下来的信息提取出我们想要的信息。

核心代码:

"""Date: --14 11:52User: yzEmail: 1147570523@Desc:"""import pandas as pdfrom config import *import matplotlib.pyplot as pltimport matplotlib # 配置中文字体和修改字体大小plt.rcParams['font.sans-serif'] = ['SimHei']plt.rcParams['font.family'] = 'sans-serif'matplotlib.rcParams['font.size'] = 12# 用来正常显示负号plt.rcParams['axes.unicode_minus'] = Falsedf = pd.read_csv(csv_filename, encoding='utf-8')def show_second_type():# 获取职位类别分类并分组统计secondType_Series = df['secondType'].value_counts()# 设置图形的大小;plt.figure(figsize=(10, 5))# 绘制条形图;secondType_Series.plot.bar()# 展示图形plt.show()def show_job_nature():jobNature_Series = df['jobNature'].value_counts()print(jobNature_Series)plt.figure(figsize=(10, 5))# 饼状图jobNature_Series.plot.pie()plt.show()def show_company():companyShortName_Series = df['companyShortName'].value_counts()companyShortName_Series_gt5 =companyShortName_Series[companyShortName_Series > 2] # 选取招聘Python相关职位个数大于等于5的公司plt.figure(figsize=(10, 5))companyShortName_Series_gt5.plot.bar()plt.show()if __name__ == '__main__':show_second_type()show_job_nature()show_company()

职位类别统计

公司统计

统计每个公司出现的个数,然后选取招聘Python相关职位个数大于等于2的公司。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。