近期的期末作业时爬51job并分析,我就分享一下我的代码
其实爬这个没有遇到反扒轻轻松松就爬下来了,应该也是数据量少的原因
但是这里呢我用了列表推导式,还别说,程序真的快了一些代码量也减少了,用了map这个函数发现也是超级好用,我大致说一下map,至于列表推导式的话一看就懂了。map这个函数允许接收一个可迭代对象和一个函数,当然这个函数可以是匿名函数,就是lambda,举个栗子吧,
f = lambda a,b,c:a+b+c
在这里a,b,c是函数的参数,此函数不需要return返回值,本身就是返回值,输入参数之后就会有一个返回值
map(lambda x:len(x) ,[1,2,3,4,5,6])
map的这个用法会把列表里的元素挨个计算长度,这里要说一下在python2中map的返回值是列表,但是在python3中他的返回值是一个对象,可以加上
list(map(lambda x: x+1, [1, 2, 3, 4, 5, 6]))
就会自动转化为列表方便使用,当然也可以转化为其他类型,。
在这篇文章里爬的数据比较少,只有职位地点薪资,(原谅我误解了老师的意思。。)
然后说一下我这的思路:
from bs4 import BeautifulSoup
import requests
import csv
titles = []
# 首先打开需要存储的文件,不要忘记"newline=''"这个参数要不然结果可能就是行与行之间就会多了一个空行,
f = open('E:/51JobData/job_country.csv', 'w', encoding='gbk', newline='')
f_csv = csv.writer(f)
# 确定第一行的属性
f_csv.writerow(['职位', '工作地点', '薪资'])
for i in range(1, 201):# 最大值是需要抓取的页数
try:
url = 'https://search.51job.com/list/010000%252C020000%252C030200%252C040000%252C180200,000000,0000,00,9,99,%25E5%25A4%25A7%25E6%2595%25B0%25E6%258D%25AE,2,{}.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99°reefrom=99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare='.format(str(i))
response = requests.get(url) # 获得对于每一页的url的返回值
response.encoding = 'gbk'# 由于51job网站的编码方式是gbk这里要换一下编码,不能再用utf-8了
soup = BeautifulSoup(response.text)# 用beautiful函数封装html返回bs对象
lists2 = soup.find_all('p', class_="t1") # 匹配包含职位的标签
salary = soup.select('#resultList > div > span.t4')[1:] # 匹配找到span.t4返回结果列表
work_place = soup.select('#resultList > div > span.t3')[1:]
work_places = list(map(lambda x: x.text, work_place)) # 遍历工作地点列表,获得每个标签的text
salary_list = list(map(lambda x: x.text, salary)) # 便利薪资列表,获得每个薪资标签的text
new_titles2 = [list_title.span.a['title'] for list_title in lists2] # 用列表推导式,找到每个标签下span中的title
for j in range(len(new_titles2)):# 由于这些的列表长度都是一样大的,所以遍历其中一个,把其他的同索引的一起拿出,并且同时写入文件
f_csv.writerow([new_titles2[j], work_places[j], salary_list[j]])
print('正在抓取第{}页'.format(str(i)))
except Exception as e:
print(e)
f.close()
print('抓取完毕!')
对其中的地点这一列进行清洗,源代码如下:
import pandas as pd
class Clear_For_Data():
df = pd.read_csv('E:/51JobData/job_country.csv', engine='python', encoding='gbk', iterator=False, header=0)
df_list = list(df.dropna()['工作地点']) # 统计工作地点的数量
def city_count(self):
workplace = list(map(lambda x: x.split('-')[0], self.df_list))# 分割一下原来的字符串 只提取城市,不提取具体位置 返回列表
sets = set(workplace) # 将列表放入集合里 (去重)
sets.remove('异地招聘') # 将异地招聘这种非城市的地点信息去掉
count_dit = {item: workplace.count(item) for item in sets} # 根据集合里不重复项挨个统计每个item在workplace里的重复次数,返回字典
return count_dit
根据拿到的地点的字典,来画一个饼图:
from pyecharts import Pie
import data_clear
data_obj = data_clear.Clear_For_Data() # 实例化对象
city_dit = data_obj.city_count() # 调用清洗函数
attr = list(city_dit.keys())# 把字典的键作为一个数组
v1 = list(city_dit.values())# 把字典的值作为一个数组
pie = Pie('饼图示例') # 通过饼图展示
pie.use_theme('dark') # 背景黑色
pie.add('城市', attr, v1, is_label_show=True)
pie.render('pie.html')
结果: