实战:爬取中国招聘网前1000条热门职位详细信息

中国招聘网:https://www.shixi.com/search/index
爬取每一个职位的详细信息:职位名、学历、薪资、工作地点、公司领域、公司规模、公司名、工作描述、时间

工作描述是较为特殊的需要用到正则表达式获取
时间也较为特殊,在跳转前的页面中才有,跳转后的页面除了时间其他详细信息都有
跳转前:
在这里插入图片描述

点击链接跳转后:

需要用到的库

import requests#用requests获取网页
from lxml import etree#用xpath解析
import pandas as pd#整理数据
import re#处理较为特殊的详细信息

import urllib3#忽略警告
urllib3.disable_warnings()
中国招聘网的链接因为证书问题,需要用到urllib3的disable_warnings()忽略警告

采用三个for循环分别负责不同的功能:获取链接、获取大部分详细信息(除时间)、获取时间信息

获取链接:
因为大多详细信息在跳转后的页面中,因此需要获得每个职位跳转的链接

观察如下链接:
视觉设计实习生:https://www.shixi.com/personals/jobshow/82245
综合岗实习生:https://www.shixi.com/personals/jobshow/82252

再观察它们的a标签:

<a href="/personals/jobshow/82245" target="_blank" 
class="job-name">视觉设计实习生</a>
<a href="/personals/jobshow/82252" target="_blank" 
class="job-name">综合岗实习生</a>

得到规律:
https://www.shixi.com/ + href属性便可以得到所有跳转后的链接

爬取1000条数据不可能在第一页就能有1000条,因此观察页数的链接
第一页:https://www.shixi.com/search/index?page=1
第二页:https://www.shixi.com/search/index?page=2
得到规律:https://www.shixi.com/search/index?page= + 页数得到不同页数的链接

第一个for循环代码如下:

urls = pd.DataFrame()
for i in range(1,101):# 包头不包尾
    url = 'https://www.shixi.com/search/index?page='+str(i)#得到页面的所有跳转链接
    print("正在解析第%d条:"%i+url)  # 方便报错后可查看出错的网页链接
    rq = requests.get(url, verify=False)
    dom = etree.HTML(rq.text, etree.HTMLParser())
    lin = dom.xpath('//*[@id="select-form"]/div[2]/div/div/div[1]/dl/dt/a/@href')
    link = ['https://www.shixi.com' + i for i in lin]
    d = pd.DataFrame({'详情链接':link})
    urls = pd.concat([urls, d])#pd.concat()使urls与d连接起来
urls.reset_index(inplace=True, drop=True)#重置索引
urls

接下来逐句解析每一条语句:
1.urls = pd.DataFrame我理解为创建一个空的表格赋值给urls

2.range(1,101)是包括1单不包括101的

3.通过for循环灵活的得到不同页数的链接

4.用print的格式化方便知道正在解析第几条

5.用get方法获取网页,因为链接有证书认证便用verify=False关闭了认证

6.用etree进行xpath的解析,我理解为解析为让xpath能看得懂的格式

7.dom.xpath()得到a标签的href属性,复制xpath的路径,随机进入一个岗位的详细页面中,复制想要的文字的xpath路径
在这里插入图片描述

8.[‘https://www.shixi.com’ + i for i in lin]通过for循环得到一个数组,装的是第几页的所有跳转后的链接

9.定义一个表格为d,放入标题为‘详情链接’,内容为link的数据

10.urls = pd.concat([urls, d])将d表格的内容和urls表格的内容进行合并,并赋给urls表格

11.通过reset_index()方法使得索引号从本来的无序变成有序的,爬取到的数据存在urls本是无序的,此方法的进行重新的排序并且覆盖掉之前的索引列
重置前:
在这里插入图片描述
重置后:
在这里插入图片描述

12.查看urls表格中的数据

第二个for循环:
获取大部分详细信息(除时间)

data = pd.DataFrame()
a = 0
for i in urls.loc[:,'详情链接']:
    a += 1
    print("正在解析第%d条:"%a+i)
    li = []# 要把列表清空
    rq = requests.get(i, verify=False)  # 发送请求
    delete = rq.text.replace('<br>', '').replace('\n', '').replace('\t', '').replace('\r', '')#删除掉文本中的\n、\t、\r和<br>
    dom = etree.HTML(rq.text, etree.HTMLParser())  # 解析网页
    job_name = dom.xpath('/html/body/div/div[3]/div[1]/div[1]/div[1]/h2/text()')  # 职位名
    education = dom.xpath('/html/body/div/div[3]/div[1]/div[1]/div[2]/span[1]/text()')  # 学历
    name = dom.xpath('/html/body/div/div[3]/div[2]/div/div[1]/h4/a/text()')#公司名
    pos = dom.xpath('/html/body/div/div[3]/div[1]/div[1]/div[1]/h2/span/text()')#工作地点
    # 用正则表达式得到工作描述+任职要求
    about = re.findall('<div class="work_b">([\s\S]*?)</div>',delete)
    # 把列表about变成str再加进新列表li,强制不会报错arrays must all be same length
    li.append(str(about).replace("[']",""))#删除字符串中的[']
    scope = dom.xpath('/html/body/div/div[3]/div[2]/div/div[1]/p[1]/span/text()')  # 领域
    area = dom.xpath('/html/body/div/div[3]/div[2]/div/div[1]/p[2]/span/text()')  # 规模
    pay = dom.xpath('/html/body/div/div[3]/div[1]/div[1]/div[2]/span[@class="money"]/text()')  # 薪资
    d = pd.DataFrame({'职位名': job_name,'学历':education,'薪资': pay,'工作地点': pos,'领域':scope,'规模':area,'公司名': name,'工作描述':li})
    data = pd.concat([data, d])
data.reset_index(inplace=True, drop=True)
data

逐句解析:
1.定义一个表格存于data中

2.a=0为了能方便知道正在解析第几条,在全局定义了a变量,每次循环+=1

3.urls.loc[:,‘详情链接’]是以切片的方式获取想要解析的范围,切片的冒号前无数据便是从0开始,冒号后也无数据就是解析得到的所有链接,逗号后是想要解析的“数据仓库”

4.用print的格式化方便知道正在解析第几条

5.复制xpath的路径,为了避免其的特殊性应该多打开几个岗位详细页面复制相同的信息进行xpath路径对比
例如工资的xpath有些是在span[3]有些是span[4],因此找到工资的特有属性class="money"使其适合于所有页面
在这里插入图片描述
在这里插入图片描述
6.同理获得所有想要的数据信息(职位名, 公司名, 学历, 工作地址, 工资,公司领域,公司规模)并将其放入DataFrame中

7.执行pd.concat([data, d]) 使得数据都保存至data中

8.执行data.reset_index(inplace=True, drop=True)重置索引列

9.工作描述的相关解析:

# 工作描述的特殊性
li = []
#删除不需要的文本信息
delete=rq.text.replace('<br>','').replace('\n','').replace('\t', '').replace('\r', '')
#通过正则表达式获得文本信息
about=re.findall('<div class="work_b">([\s\S]*?)</div>',delete)
#将得到的数组about由str()变为字符串再加到空数组li中
li.append(str(about))

问题1:“工作描述”的xpath解析获得的列表长度是不一的,有些是len(li)为3有些len(li)为4,因此在运行是便会报错arrays must all be same length
在这里插入图片描述

解决1:将xpath解析后得到的长度不一的列表整体通过str()方法强制变为字符串类型,再在循环中定义一个空列表li,将得到的字符串由li.append加入到列表中,此时列表的长度就为1与其他的信息一样,解决长度不一的报错。li = 0为局部变量,每次循环都要清空其中的数据,已达到和xpath解析的数据相同的过程
在这里插入图片描述
问题2:通过xpath地址无法获得“工作描述”的所有文本信息,并且许多xpath都不具有普遍性,无法通过xpath解析得到所有页面的“工作描述”
在这里插入图片描述
解决2:通过正则表达式解决了普遍性的问题,所有的文本的标签和属性都是一样的,因此匹配其中的文字信息即可,但仍然有无法解决的问题是:也匹配到相同class的其他不需要的文本信息
在这里插入图片描述
问题3:通过xpath地址获得的文本有许多其他不需要的信息,例如/n、/t、/r等等
在这里插入图片描述
解决3:通过.replace(‘/n’,’ ’)挨个将无用的文本删除
在这里插入图片描述

第三个for循环:
获得时间:

cv = pd.DataFrame()
for i in range(1,101):# 包头不包尾
    url = 'https://www.shixi.com/search/index?page='+str(i)#得到所有列表页面的链接
    print("正在解析第%d条:"%i+url)#方便报错后可查看出错的网页链接
    rq = requests.get(url, verify=False)
    dom = etree.HTML(rq.text, etree.HTMLParser())
    time = dom.xpath('//*[@id="select-form"]/div[2]/div/div/div[2]/div[1]/span[2]/text()')
    all_time = [i for i in time]
    t = pd.DataFrame({'时间':all_time})
    cv = pd.concat([cv, t])
cv.reset_index(inplace=True, drop=True)
data = pd.concat([cv,data],axis=1)#axis=1是在左右合并,=0是上下合并

逐句解析:
1.定义一个新的空表格cv

2.与第一个for循环很相似,获取所有列表页面的链接

3.用print的格式化方便知道正在解析第几条

4.用get方法获取页面以及用etree解析页面

5.获取时间的xpath地址,获取的是时间的文本信息因此尾部有text()

6.用for循环获得一个列表页面中的所有时间的信息

7.创建表格t赋值标题为时间内容为所有爬取到的时间

8.pd.concat()合并cv和t表格

9.cv.reset_index()重新整理索引号

10.pd.concat([cv,data],axis=1)多了一个属性axis,当axis=1时两个表格为左右合并,axis=0时为上下合并

问题:在没加axis=1时运行会报错,得出的时间结果很多为None,无法合并两个DataFrame
在这里插入图片描述
解决:进行很少数据量的爬取实验,发现导出的Excel表格是属于上下合并,上网搜索DataFrame的合并方式,发现有属性axis=1时为左右合并,axis=0时为上下合并,于是加上属性便解决问题
在这里插入图片描述

最后保存至Excel中:

#保存到excel中
data.to_excel('中国热门职位.xls',index=None)
# index=None删除第一列的索引列

1."中国热门职位.xls"为名字,默认保存至工作目录下

2.index=None为删除索引列

删除前:
在这里插入图片描述
删除后:
在这里插入图片描述
所有代码:

import requests
from lxml import etree
import pandas as pd
import re
#  忽略警告
import urllib3

#获得链接
urllib3.disable_warnings()
urls = pd.DataFrame()
for i in range(1,101):# 包头不包尾
    url = 'https://www.shixi.com/search/index?page='+str(i)#得到页面的所有跳转链接
    print("正在解析第%d条:"%i+url)  # 方便报错后可查看出错的网页链接
    rq = requests.get(url, verify=False)
    dom = etree.HTML(rq.text, etree.HTMLParser())
    lin = dom.xpath('//*[@id="select-form"]/div[2]/div/div/div[1]/dl/dt/a/@href')
    link = ['https://www.shixi.com' + i for i in lin]
    d = pd.DataFrame({'详情链接':link})
    urls = pd.concat([urls, d])#pd.concat()使urls与d连接起来
urls.reset_index(inplace=True, drop=True)#重置索引
urls

#获得除了时间
data = pd.DataFrame()  # 存储数据
a = 0
for i in urls.loc[:,'详情链接']:
    a += 1
    print("正在解析第%d条:"%a+i)
      # 要把列表清空
    li = []
    rq = requests.get(i, verify=False)  # 发送请求
    delete = rq.text.replace('<br>', '').replace('\n', '').replace('\t', '').replace('\r', '')#删除掉文本中的\n、\t、\r和<br>
    dom = etree.HTML(rq.text, etree.HTMLParser())  # 解析网页
    job_name = dom.xpath('/html/body/div/div[3]/div[1]/div[1]/div[1]/h2/text()')  # 职位名
    education = dom.xpath('/html/body/div/div[3]/div[1]/div[1]/div[2]/span[1]/text()')  # 学历
    name = dom.xpath('/html/body/div/div[3]/div[2]/div/div[1]/h4/a/text()')#公司名
    pos = dom.xpath('/html/body/div/div[3]/div[1]/div[1]/div[1]/h2/span/text()')#工作地点
    # 用正则表达式得到工作描述+任职要求
    about = re.findall('<div class="work_b">([\s\S]*?)</div>',delete)
    # 把列表about变成str再加进新列表li,强制不会报错arrays must all be same length
    li.append(str(about).replace("[']",""))#删除字符串中的[']
    scope = dom.xpath('/html/body/div/div[3]/div[2]/div/div[1]/p[1]/span/text()')  # 领域
    area = dom.xpath('/html/body/div/div[3]/div[2]/div/div[1]/p[2]/span/text()')  # 规模
    pay = dom.xpath('/html/body/div/div[3]/div[1]/div[1]/div[2]/span[@class="money"]/text()')  # 薪资
    d = pd.DataFrame({'职位名': job_name,'学历':education,'薪资': pay,'工作地点': pos,'领域':scope,'规模':area,'公司名': name,'工作描述':li})
    data = pd.concat([data, d])
data.reset_index(inplace=True, drop=True)
data

#获得时间
cv = pd.DataFrame()
for i in range(1,101):# 包头不包尾
    url = 'https://www.shixi.com/search/index?page='+str(i)#得到页面的所有跳转链接
    print("正在解析第%d条:"%i+url)  # 方便报错后可查看出错的网页链接
    rq = requests.get(url, verify=False)
    dom = etree.HTML(rq.text, etree.HTMLParser())
    time = dom.xpath('//*[@id="select-form"]/div[2]/div/div/div[2]/div[1]/span[2]/text()')
    all_time = [i for i in time]
    t = pd.DataFrame({'时间':all_time})
    cv = pd.concat([cv, t])
cv.reset_index(inplace=True, drop=True)
data = pd.concat([cv,data],axis=1)#axis=1是在左右合并,=0是上下合并

#保存到excel中
data.to_excel('中国热门职位.xls',index=None)
利用scrapy-redis框架实现分布式爬虫,首先需要理解分布式爬虫的工作原理和scrapy-redis框架的基本使用。分布式爬虫设计的核心在于将爬虫任务分散到多个节点上执行,以提高效率和吞吐量。Scrapy-redis通过Redis数据库共享URL请求队列和任务调度,支持master-slave架构,使得爬虫可以在多个工作节点上并发运行。 参考资源链接:[Python大数据驱动的招聘职位信息爬取与分析系统](https://wenku.youkuaiyun.com/doc/4au3j3vu7c) 在具体实现时,可以使用Python编程语言开发爬虫程序。首先,需要安装并配置scrapy框架和scrapy-redis扩展。然后,创建一个scrapy项目,定义初始爬虫规则,用于从目标招聘网站抓取职位信息。在分布式环境配置中,将scrapy-redis设置为调度器和去重中间件,并在Redis服务器上配置相应的队列和数据结构。 爬取到的职位信息往往包含大量噪声数据,如非相关的职位描述和元数据。因此,需要对抓取到的数据进行清洗和筛选,以获得高质量的大数据相关职位信息。数据清洗可以使用Pythonpandas库进行,该库提供了强大的数据处理功能。通过定义数据清洗规则,例如剔除含有特定关键字的职位,保留与大数据技术相关的职位信息,可以有效地提高数据集的质量和分析的价值。 接下来,根据需求对清洗后的数据集进行分析,这可能涉及数据集的统计描述、趋势分析或模式识别等。如果需要对数据进行进一步的分析,可以使用Python的numpy和scikit-learn等库来辅助完成。 综合以上步骤,你将能够构建一个完整的分布式爬虫系统,该系统能够从网络上爬取并分析与大数据相关的职位信息,为招聘数据分析提供有力支持。 考虑到你对《Python大数据驱动的招聘职位信息爬取与分析系统》资源包感兴趣,我推荐你深入学习其中的内容。该资源不仅涵盖了Python爬虫开发的基础知识,还详细介绍了如何使用scrapy-redis框架构建分布式爬虫,并对数据清洗和分析进行了深入探讨。通过这个资源包,你将能够全面掌握如何从招聘网爬取数据,并对这些数据进行深入的挖掘和分析,从而获得有价值的洞察。 参考资源链接:[Python大数据驱动的招聘职位信息爬取与分析系统](https://wenku.youkuaiyun.com/doc/4au3j3vu7c)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值