Python爬蟲爬取智聯招聘(進階版)

前言

文的文字及圖片來源於網絡,僅供學習、交流使用,不具備任何商業用途,版權歸原做者全部,若有問題請及時聯繫咱們以做處理。html

做者: C與Python實戰python

PS:若有須要Python學習資料的小夥伴能夠加點擊下方連接自行獲取git

http://note.youdao.com/noteshare?id=3054cce4add8a909e784ad934f956cefgithub

上一篇文章中《Python爬蟲抓取智聯招聘(基礎版)》咱們已經抓取了智聯招聘一些信息,可是那些對於找工做來講仍是不夠的,今天咱們繼續深刻的抓取智聯招聘信息並分析,本文使用到的第三方庫不少,涉及到的內容也很繁雜,請耐心閱讀。正則表達式

  • 運行平臺: Windows 算法

  • Python版本: Python3.6 數據庫

  • IDE: Sublime Text 編程

  • 其餘工具: Chrome瀏覽器瀏覽器

0、寫在前面的話

在基礎版中,構造url時使用了urllib庫的urlencode函數:網絡

 url = 'https://sou.zhaopin.com/jobs/searchresult.ashx?' + urlencode(paras)
    try:
        # 獲取網頁內容,返回html數據
        response = requests.get(url, headers=headers)
    ...

 

其實用reuqests庫能夠完成此工做,本例將該部分改成:

 url = 'https://sou.zhaopin.com/jobs/searchresult.ashx?'
    try:
        # 獲取網頁內容,返回html數據
        response = requests.get(url, params=paras, headers=headers)
    ...

 

一、找到職位連接

爲了獲得更加詳細的職位信息,咱們要找到職位連接,在新的頁面中尋找數據。上篇文章中咱們沒有解析職位連接,那再來找一下吧:

在這裏插入圖片描述

修改一下正則表達式:

# 正則表達式進行解析
    pattern = re.compile('<td class="zwmc".*?href="(.*?)" target="_blank">(.*?)</a>.*?' # 匹配職位詳情地址和職位名稱
        '<td class="gsmc">.*? target="_blank">(.*?)</a>.*?'                             # 匹配公司名稱
        '<td class="zwyx">(.*?)</td>', re.S)                                            # 匹配月薪      
# 匹配全部符合條件的內容
    items = re.findall(pattern, html)   

 

二、求工資平均值

工資有兩種形式xxxx-yyyy或者面議,此處取第一種形式的平均值做爲分析標準,雖有誤差可是也差很少,這是求職中最重要的一項指標。

for item in items:
    salary_avarage = 0
    temp = item[3]
    if temp != '面議':
        idx = temp.find('-')
        # 求平均工資
        salary_avarage = (int(temp[0:idx]) + int(temp[idx+1:]))//2

 

三、解析職位詳細信息

3.1 網頁解析

第一步已經將職位地址找到,在瀏覽器打開以後咱們要找到以下幾項數據:

在這裏插入圖片描述

在開發者工具中查找這幾項數據,以下圖所示:

在這裏插入圖片描述 HTML結構以下所示:

# 數據HTML結構
<body>
|------<div class="terminalpage clearfix">
==>|------<div class="terminalpage-left">
==>==>|------<ul class="terminal-ul clearfix">
==>==>==>|------<li><span>工做經驗:</span><strong>3-5年</strong>
==>==>==>|------<li><span>最低學歷:</span><strong>本科</strong>
==>==>|------<div class="terminalpage-main clearfix">
==>==>==>|------<div class="tab-cont-box">
==>==>==>==>|------<div class="tab-inner-cont">
==>==>==>==>==>|------<p>工做職責:</p>
==>==>==>==>==>|------<p>********</p>
==>==>==>==>==>|------<p>********</p>    # 工做職責詳情
==>|------<div class="terminalpage-right">    
==>==>|------<div class="company-box">
==>==>==>|------<ul class="terminal-ul clearfix terminal-company mt20">
==>==>==>==>|------<li><span>公司規模:</span><strong>100-499人</strong>

 

3.2 代碼實現

爲了學習一下BeautifulSoup庫的使用,咱們再也不使用正則表達式解析,而是BeautifulSoup庫解析HTML標籤來得到咱們想要獲得的內容。

解析庫的安裝:pip install beautifulsoup4

下面介紹一下本例中使用到的功能:

  • 庫的引入:from bs4 import BeautifulSoup

  • 數據引入:soup = BeautifulSoup(html, 'html.parser') ,其中html是咱們要解析的html源碼,html.parser指定HTML的解析器爲Python標準庫。

  • 查找標籤:find(name,attrs,recursive,text,**kwargs),find返回的匹配結果的第一個元素

  • 查找全部標籤:find_all(name,attrs,recursive,text,**kwargs)能夠根據標籤名,屬性,內容查找文檔,返回找到的全部元素

  • 獲取內容:get_text()就能夠獲取文本內容

  • 獲取子標籤:soup.p這種方式就能夠獲取到soup下的第一個p標籤

'''
python學習交流羣:821460695更多學習資料能夠加羣獲取
'''
def get_job_detail(html):
    requirement = ''
    # 使用BeautifulSoup進行數據篩選
    soup = BeautifulSoup(html, 'html.parser')
    # 找到<ul class="terminal-ul clearfix">標籤
    for ul in soup.find_all('ul', class_='terminal-ul clearfix'):
        # 該標籤共有8個子標籤,分別爲:
        # 職位月薪|工做地點|發佈日期|工做性質|工做經驗|最低學歷|招聘人數|職位類別
        lis = ul.find_all('strong')
        # 工做經驗
        years = lis[4].get_text()
        # 最低學歷
        education = lis[5].get_text()
    # 篩選任職要求
    for terminalpage in soup.find_all('div', class_='terminalpage-main clearfix'):
        for box in terminalpage.find_all('div', class_='tab-cont-box'):
            cont = box.find_all('div', class_='tab-inner-cont')[0]
            ps = cont.find_all('p')
            # "當即申請"按鈕也是個p標籤,將其排除
            for i in range(len(ps) - 1):
                requirement += ps[i].get_text().replace("\n", "").strip()   # 去掉換行符和空格
# 篩選公司規模,該標籤內有四個或五個<li>標籤,可是第一個就是公司規模
    scale = soup.find(class_='terminal-ul clearfix terminal-company mt20').find_all('li')[0].strong.get_text()
​
    return {'years': years, 'education': education, 'requirement': requirement, 'scale': scale}

 

本次咱們將職位描述寫入txt文件,其他信息寫入csv文件。

csv文件採用逐行寫入的方式這樣也能夠省點內存,修改write_csv_rows函數:

def write_csv_rows(path, headers, rows):
    '''
    寫入行
    '''
    with open(path, 'a', encoding='gb18030', newline='') as f:
        f_csv = csv.DictWriter(f, headers)
        # 若是寫入數據爲字典,則寫入一行,不然寫入多行
        if type(rows) == type({}):
            f_csv.writerow(rows)
        else:
            f_csv.writerows(rows)

 

添加寫txt文件函數:

def write_txt_file(path, txt):
    '''
    寫入txt文本
    '''
    with open(path, 'a', encoding='gb18030', newline='') as f:
        f.write(txt)

 

咱們最重要對職位描述的內容進行詞頻統計,一些標點符號等會影響統計,使用正則表達式將其剔除:

# 對數據進行清洗,將標點符號等對詞頻統計形成影響的因素剔除
pattern = re.compile(r'[一-龥]+')
filterdata = re.findall(pattern, job_detail.get('requirement'))
write_txt_file(txt_filename, ''.join(filterdata))

 

至此,職位詳細信息的獲取及保存的工做已經完成,來看一下此時的main函數:

 1 def main(city, keyword, region, pages):
 2     '''
 3     主函數
 4     '''
 5     csv_filename = 'zl_' + city + '_' + keyword + '.csv'
 6     txt_filename = 'zl_' + city + '_' + keyword + '.txt'
 7     headers = ['job', 'years', 'education', 'salary', 'company', 'scale', 'job_url']
 8     write_csv_headers(csv_filename, headers)
 9     for i in range(pages):
10         '''
11         獲取該頁中全部職位信息,寫入csv文件
12         '''
13         job_dict = {}
14         html = get_one_page(city, keyword, region, i)
15         items = parse_one_page(html)
16         for item in items:
17             html = get_detail_page(item.get('job_url'))
18             job_detail = get_job_detail(html)
19 
20             job_dict['job'] = item.get('job')
21             job_dict['years'] = job_detail.get('years')
22             job_dict['education'] = job_detail.get('education')
23             job_dict['salary'] = item.get('salary')
24             job_dict['company'] = item.get('company')
25             job_dict['scale'] = job_detail.get('scale')
26             job_dict['job_url'] = item.get('job_url')
27 
28             # 對數據進行清洗,將標點符號等對詞頻統計形成影響的因素剔除
29             pattern = re.compile(r'[一-龥]+')
30             filterdata = re.findall(pattern, job_detail.get('requirement'))
31             write_txt_file(txt_filename, ''.join(filterdata))
32             write_csv_rows(csv_filename, headers, job_dict)

 

四、數據分析

本節內容爲此版本的重點。

4.1 工資統計

咱們對各個階段工資的佔比進行統計,分析該行業的薪資分佈水平。前面咱們已經把數據保存到csv文件裏了,接下來要讀取salary列:

def read_csv_column(path, column):
    '''
    讀取一列
    '''
    with open(path, 'r', encoding='gb18030', newline='') as f:
        reader = csv.reader(f)
        return [row[column] for row in reader]

# main函數裏添加
print(read_csv_column(csv_filename, 3))

#下面爲打印結果
['salary', '7000', '5000', '25000', '12500', '25000', '20000', '32500', '20000', '15000', '9000', '5000', '5000', '12500', '24000', '15000', '18000', '25000', '20000', '0', '20000', '12500', '17500', '17500', '20000', '11500', '25000', '12500', '17500', '25000', '22500', '22500', '25000', '17500', '7000', '25000', '3000', '22500', '15000', '25000', '20000', '22500', '15000', '15000', '25000', '17500', '22500', '10500', '20000', '17500', '22500', '17500', '25000', '20000', '11500', '11250', '12500', '14000', '12500', '17500', '15000']

 

從結果能夠看出,除了第一項,其餘的都爲平均工資,可是此時的工資爲字符串,爲了方便統計,咱們將其轉換成整形:

salaries = []
sal = read_csv_column(csv_filename, 3)
    # 撇除第一項,並轉換成整形,生成新的列表
    for i in range(len(sal) - 1):
        # 工資爲'0'的表示招聘上寫的是'面議',不作統計
        if not sal[i] == '0':
            salaries.append(int(sal[i + 1]))
    print(salaries)

# 下面爲打印結果
[7000, 5000, 25000, 12500, 25000, 20000, 32500, 20000, 15000, 9000, 5000, 5000, 12500, 24000, 15000, 18000, 25000, 20000, 0, 20000, 12500, 20000, 11500, 17500, 25000, 12500, 17500, 25000, 25000, 22500, 22500, 17500, 17500, 7000, 25000, 3000, 22500, 15000, 25000, 20000, 22500, 15000, 22500, 10500, 20000, 15000, 17500, 17500, 25000, 17500, 22500, 25000, 12500, 20000, 11250, 11500, 14000, 12500, 15000, 17500]

 

咱們用直方圖進行展現:

plt.hist(salaries, bins=10 ,)
plt.show()

 

生成效果圖以下:

在這裏插入圖片描述

從圖中能夠看出工資分佈的狀況,這樣在你找工做時能夠作一個參考。

4.2 職位描述詞頻統計

對職位描述詞頻統計的意義是能夠了解該職位對技能的基本要求,若是正在找工做,能夠估計一下本身的要求是否符合該職位;若是想要一年後換工做,那麼也能夠提早作好準備,迎接新的挑戰。

詞頻統計用到了 jieba、numpy、pandas、scipy庫。若是電腦上沒有這兩個庫,執行安裝指令:

  • pip install jieba

  • pip install pandas

  • pip install numpy

  • pip install scipy

4.2.1 讀取txt文件

前面已經將職位描述保存到txt文件裏了,如今咱們將其讀出:

1 def read_txt_file(path):
2     '''
3     讀取txt文本
4     '''
5     with open(path, 'r', encoding='gb18030', newline='') as f:
6         return f.read()

 

簡單測試一下:

 1 import jieba
 2 import pandas as pd
 3 '''
 4 python學習交流羣:821460695更多學習資料能夠加羣獲取
 5 '''
 6 content = read_txt_file(txt_filename)
 7 segment = jieba.lcut(content)
 8 words_df=pd.DataFrame({'segment':segment})
 9 print(words_df)
10 
11 # 輸出結果以下:
12       segment
13 0        崗位職責
14 1          參與
15 2          公司
16 3        軟件產品
17 4          後臺
18 5          研發
19 620 7          維護
21 8          工做
22 9          參與
23 10        建築物
24 11         聯網
25 12       數據分析
26 13         算法
27 1428 15         設計
29 1630 17         開發
31 1832 19         獨立
33 20         完成
34 21         業務
35 22         算法
36 23         模塊
37 ...            ...

 

從結果能夠看出:「崗位職責」、「參與」、「公司」、軟件產品「、」的「、」和「等單詞並無實際意義,因此咱們要將他們從表中刪除。

4.2.2 stop word

下面引入一個概念:stop word, 在網站裏面存在大量的經常使用詞好比:「在」、「裏面」、「也」、「的」、「它」、「爲」這些詞都是中止詞。這些詞由於使用頻率太高,幾乎每一個網頁上都存在,因此搜索引擎開發人員都將這一類詞語所有忽略掉。若是咱們的網站上存在大量這樣的詞語,那麼至關於浪費了不少資源。

在百度搜索stpowords.txt進行下載,放到py文件同級目錄。接下來測試一下:

content = read_txt_file(txt_filename)
segment = jieba.lcut(content)
words_df=pd.DataFrame({'segment':segment})

stopwords=pd.read_csv("stopwords.txt",index_col=False,quoting=3,sep=" ",names=['stopword'],encoding='utf-8')
words_df=words_df[~words_df.segment.isin(stopwords.stopword)]

print(words_df)

# 如下爲輸出結果
0        崗位職責
1          參與
2          公司
3        軟件產品
4          後臺
5          研發
7          維護
8          工做
9          參與
10        建築物
11         聯網
12       數據分析
13         算法
15         設計
17         開發
19         獨立
21         業務
22         算法
23         模塊
24         開發
28         產品
29         目標
31         改進
32         創新
33         任職
35         熟練
38         開發
39         經驗
40         優先
41         熟悉
...       ...

 

從結果看出,那些經常使用的stop word好比:「的」、「和」、「可」等已經被剔除了,可是還有一些詞如「崗位職責」、「參與」等也沒有實際意義,若是對詞頻統計不產生影響,那麼就無所謂,在後面統計時再決定是否對其剔除。

4.2.3 詞頻統計

重頭戲來了,詞頻統計使用numpy:

import numpy

words_stat = words_df.groupby(by=['segment'])['segment'].agg({"計數":numpy.size})
    words_stat = words_stat.reset_index().sort_values(by=["計數"],ascending=False)
    print(words_stat)

# 如下是爬取所有「北京市海淀區Python工程師」職位的運行結果:
    segment   計數
362      開發  505
590      熟悉  409
701      經驗  281
325      工做  209
820      負責  171
741      能力  169
793      設計  161
82       優先  160
409      技術  157
621      相關  145
322    崗位職責  127
683      系統  126
64       產品  124
904      項目  123
671      算法  107
78       任職  107
532      框架  107
591      熟練  104

 

能夠看出,某些詞語仍是影響了統計結果,我將如下stop word加入stopword.txt中:

開發、熟悉、熟練、精通、經驗、工做、負責、能力、有限、相關、崗位職責、任職、語言、平臺、參與、優先、技術、學習、產品、公司、熟練掌握、以上學歷

最後運行結果以下:

775      設計  136
667      系統  109
884      項目  105
578      熟練   95
520      框架   92
656      算法   90
143      分析   90
80       優化   77
471     數據庫   75
693      維護   66
235      團隊   65
72       代碼   61
478      文檔   60
879      需求   58
766     計算機   56
698      編程   56
616      研發   49
540      溝通   49
527      模塊   49
379      性能   46
695      編寫   45
475    數據結構   44

 

這樣基本上就是對技能的一些要求了,你也能夠根據本身的需求再去修改stopword.txt已達到更加完美的效果。

4.2.4 詞頻可視化:詞雲

詞頻統計雖然出來了,能夠看出排名,可是不完美,接下來咱們將它可視化。使用到wordcloud庫,詳細介紹見 github ,使用pip install wordcloud進行安裝。

from scipy.misc import imread
from wordcloud import WordCloud, ImageColorGenerator
'''
python學習交流羣:821460695更多學習資料能夠加羣獲取
'''
    # 設置詞雲屬性
    color_mask = imread('background.jfif')
    wordcloud = WordCloud(font_path="simhei.ttf",   # 設置字體能夠顯示中文
                    background_color="white",       # 背景顏色
                    max_words=100,                  # 詞雲顯示的最大詞數
                    mask=color_mask,                # 設置背景圖片
                    max_font_size=100,              # 字體最大值
                    random_state=42,
                    width=1000, height=860, margin=2,# 設置圖片默認的大小,可是若是使用背景圖片的話,                                                   # 那麼保存的圖片大小將會按照其大小保存,margin爲詞語邊緣距離
                    )
​
​
    # 生成詞雲, 能夠用generate輸入所有文本,也能夠咱們計算好詞頻後使用generate_from_frequencies函數
    word_frequence = {x[0]:x[1]for x in words_stat.head(100).values}
    word_frequence_dict = {}
    for key in word_frequence:
        word_frequence_dict[key] = word_frequence[key]
​
    wordcloud.generate_from_frequencies(word_frequence_dict)
    # 從背景圖片生成顏色值  
    image_colors = ImageColorGenerator(color_mask) 
    # 從新上色
    wordcloud.recolor(color_func=image_colors)
    # 保存圖片
    wordcloud.to_file('output.png')
    plt.imshow(wordcloud)
    plt.axis("off")
    plt.show()

 

運行效果圖以下(左圖爲原圖,右圖爲生成的圖片):

在這裏插入圖片描述

至此,詞頻統計及其可視化完成。

相關文章
相關標籤/搜索