爬虫:爬取分析拉勾网数据分析职位信息

本文是我第三篇爬虫实战的代码,主要针对拉勾这一类有反爬机制的网站构思爬取思路,并对爬取的数据进行可视化及分析

本来信心满满觉得可以写出这篇代码,但自己第一次完成的时候并不能成功爬取,于是我在各个网站上学习了各路大佬的思路,很有启发,下面的代码是我模仿其中最喜欢的爬虫代码风格写出的

第一部分是爬虫的代码

import requests
import pandas
import time
import random

#用于获取页面信息
def getWebResult(url,cookies,form,header):
    html = requests.post(url=url,cookies=cookies,data=form, headers=header)
    result = html.json()
    #找到html中result包含的招聘职位信息
    data = result['content']['positionResult']['result'] # 返回结果在preview中的具体返回值
    return data
#     if 'content' in result:
#         data = result['content']['positionResult']['result'] # 返回结果在preview中的具体返回值
#         return data
#     else:
#         print('not exist')
#     return None
###   在文末会提到以上注释的含义

#将招聘信息按照对应的参数,组装成字典
def getGoalData(data):
    for i in range(15):#每页默认15个职位
        info={
            'positionName': data[i]['positionName'],    #职位简称
            'companyShortName': data[i]['companyShortName'],    #平台简称
            'salary': data[i]['salary'],    #职位薪水
            'createTime': data[i]['createTime'],    #发布时间
            'companyId':data[i]['companyId'],   #公司ID
            'companyFullName':data[i]['companyFullName'],   #公司全称
            'companySize': data[i]['companySize'],  #公司规模
            'financeStage': data[i]['financeStage'],    #融资情况
            'industryField': data[i]['industryField'],  #所在行业
            'education': data[i]['education'],  #教育背景
            'district': data[i]['district'],    #公司所在区域
            'businessZones':data[i]['businessZones']    #区域详细地
        }
        data[i]=info
    return data

#保存data至csv文件
def saveData(data,stage):
    table = pandas.DataFrame(data)
    table.to_csv('lagou.csv', header=stage, index=False, mode='a+')

def main():
    # 拼装header信息
    header = {
        'Host': 'www.lagou.com',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36',
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'Accept-Encoding': 'gzip, deflate, br',
        'Referer': 'https://www.lagou.com/jobs/list_%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90?px=default&city=%E6%88%90%E9%83%BD',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'X-Requested-With': 'XMLHttpRequest',
        'X-Anit-Forge-Token': 'None',
        'X-Anit-Forge-Code': '0',
        'Content-Length': '55',
        'Connection': 'keep-alive',
        'Pragma': 'no-cache',
        'Cache-Control': 'no-cache, no-store, max-age=0'
        }
    cookies = {
        'Cookie':'user_trace_token=20190701195626-413b5187-9bf7-11e9-bb89-525400f775ce; LGUID=20190701195626-413b53d1-9bf7-11e9-bb89-525400f775ce; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2216bad64b2e0177-0b9dbc99c10c49-e343166-1327104-16bad64b2e16f2%22%2C%22%24device_id%22%3A%2216bad64b2e0177-0b9dbc99c10c49-e343166-1327104-16bad64b2e16f2%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_referrer_host%22%3A%22%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%7D%7D; _ga=GA1.2.801986302.1561982196; JSESSIONID=ABAAABAAADEAAFI4839E11CD94A977EEB2B1E95652FD697; WEBTJ-ID=20190810164200-16c7ab1117275-04bee1efa35a37-c343162-1327104-16c7ab111735a3; index_location_city=%E5%85%A8%E5%9B%BD; isCloseNotice=0; TG-TRACK-CODE=search_code; X_MIDDLE_TOKEN=a17a1fb36651540303bd945a47e31611; X_HTTP_TOKEN=c8d3763e5add9d9d9787255651a16cc9be556fcc48; LGRID=20190811205119-b72d08e6-bc36-11e9-8915-525400f775ce; SEARCH_ID=84e789e6c95a450bacac50045bccfaca'
    }


    # 职位关键字
    job='数据分析'

    # 职位所属地
    city = '成都'
    # 模拟请求的url
    url = 'https://www.lagou.com/jobs/positionAjax.json?px=default&city=' + city + '&needAddtionalResult=false'

    #用于定义开始爬取的起始页码
    startPage=1

    #拉勾网有个限制,单次只能连续爬取5页,所以使用一个以5页为轮循的小策略
    while startPage<26:
        for i in range(startPage, startPage+5):
            #拼装Form Data信息
            if i == 1:
                flag = 'true' #当是首次请求时,使用flag=true标志
                stage = True  #stage是用来标示csv是否创建表头的参数,仅在第一次保存数据时创建
            else:
                flag = 'false'
                stage = False
            num = i
            form = {'first': flag,  # 标示是否是首次请求标示,第二页以后则为false
                    'kd': job,
                    'pn': str(num)}
            print('------page %s-------' % i) #打印当面爬取的页码

            #调用函数,获取相应的招聘信息
            data = getWebResult(url,cookies,form, header)
            #调用函数,拼装招聘信息
            data_goal = getGoalData(data)
            #调用函数,保存info数据
            saveData(data_goal, stage)

        #以5页为单次,依次轮循
        startPage+=5

        #休眠一定时间
        time.sleep(20+random.randint(10,30))

if __name__ == '__main__':
    main()

这里解答一下问题,这个代码无法运行成功,始终会报'content'错误.
我并不能理解为什么,且发现网上其他作者的不同代码我运行都会报这个错,我搜索了相关解决方案,只找到如下:


作者如图

解决方法

我尝试了这个方法(即大概为上述代码的注解),但是报出另一个错误:我定义的(如图)字典键不存在值.我完全不能理解了...尝试许久还是没有解决,但这部分的代码和思路倒是十分熟练,只好告诉自己有缘再解决这个问题了...


下面是分析相关的代码

import pandas as pd  
import matplotlib.pyplot as plt  
import statsmodels.api as sm  
from wordcloud import WordCloud  
from scipy.misc import imread  
import jieba  
from pylab import mpl  

# 使matplotlib模块能显示中文  
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体  
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题  

# 读取数据  
df = pd.read_csv('lagou_jobs.csv', encoding = 'gbk')  

# 数据清洗,剔除实习岗位  
df.drop(df[df['职位名称'].str.contains('实习')].index, inplace=True)  
# print(df.describe())  

# 由于CSV文件内的数据是字符串形式,先用正则表达式将字符串转化为列表,再取区间的均值  
pattern = '\d+'  
df['工作年限'] = df['工作经验'].str.findall(pattern)  

avg_work_year = []  
for i in df['工作年限']:  
    # 如果工作经验为'不限'或'应届毕业生',那么匹配值为空,工作年限为0  
    if len(i) == 0:  
        avg_work_year.append(0)  
    # 如果匹配值为一个数值,那么返回该数值  
    elif len(i) == 1:  
        avg_work_year.append(int(''.join(i)))  
    # 如果匹配值为一个区间,那么取平均值  
    else:  
        num_list = [int(j) for j in i]  
        avg_year = sum(num_list)/2  
        avg_work_year.append(avg_year)  

df['经验'] = avg_work_year  

# 将字符串转化为列表,再取区间的前25%,比较贴近现实  
df['salary'] = df['工资'].str.findall(pattern)  

avg_salary = []  
for k in df['salary']:  
    int_list = [int(n) for n in k]  
    avg_wage = int_list[0]+(int_list[1]-int_list[0])/4  
    avg_salary.append(avg_wage)  

df['月工资'] = avg_salary  
# 将清洗后的数据保存,以便检查  
df.to_csv('draft.csv', index = False)  

# 描述统计  
print('数据分析师工资描述:\n{}'.format(df['月工资'].describe()))  

# 绘制频率直方图并保存  
plt.hist(df['月工资'],bins = 12)  
plt.xlabel('工资 (千元)')   
plt.ylabel('频数')   
plt.title("工资直方图")   
plt.savefig('histogram.jpg')  
plt.show()  

# 绘制饼图并保存  
count = df['区域'].value_counts()  
# 将龙华区和龙华新区的数据汇总  
count['龙华新区'] += count['龙华区']   
del count['龙华区']  
plt.pie(count, labels = count.keys(),labeldistance=1.4,autopct='%2.1f%%')  
plt.axis('equal')  # 使饼图为正圆形  
plt.legend(loc='upper left', bbox_to_anchor=(-0.1, 1))  
plt.savefig('pie_chart.jpg')  
plt.show()  

# 绘制词云,将职位福利中的字符串汇总  
text = ''  
for line in df['职位福利']:  
    text += line  
# 使用jieba模块将字符串分割为单词列表      
cut_text = ' '.join(jieba.cut(text))  
color_mask = imread('cloud.jpg')  #设置背景图  
cloud = WordCloud(  
        font_path = 'yahei.ttf',   
        background_color = 'white',  
        mask = color_mask,  
        max_words = 1000,  
        max_font_size = 100          
        )  

word_cloud = cloud.generate(cut_text)  
# 保存词云图片  
word_cloud.to_file('word_cloud.jpg')  
plt.imshow(word_cloud)  
plt.axis('off')  
plt.show()  

# 实证统计,将学历不限的职位要求认定为最低学历:大专  
df['学历要求'] = df['学历要求'].replace('不限','大专')  

# 学历分为大专\本科\硕士,将它们设定为虚拟变量  
dummy_edu = pd.get_dummies(df['学历要求'],prefix = '学历')  
# 构建回归数组  
df_with_dummy = pd.concat([df['月工资'],df['经验'],dummy_edu],axis = 1)  

# 建立多元回归模型  
y = df_with_dummy['月工资']  
X = df_with_dummy[['经验','学历_大专','学历_本科','学历_硕士']]  
X=sm.add_constant(X)   
model = sm.OLS(y,X)  
results = model.fit()  
print('回归方程的参数:\n{}\n'.format(results.params))  
print('回归结果:\n{}'.format(results.summary()))  

(因为爬取部分始终没能成功,所以分析部分的代码也就没能实施辽 hin难受)

总结

1.找到了自己爬虫的代码风格,也对这一类有反爬机制的网站爬取有了一系列心得体会;
2.对使用 python 进行数据分析有了实践和更多的思考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349