寫在前面
不同的語言,有它們各自擅長的應用場景,選擇一門適合自己的語言需要勇氣與毅力。
而當你下定決心要在甄選的語言上一條道走到黑的時候,孰不知,選擇才剛剛開始。
一門編程語言往往有許多分支,每一個分支都需要掌握不同的技能,我們時常會感到困惑:怎么才能較為准確的分配技能點?
需求決定選擇,從招聘方的角度來觀察,看看我們未來的金主需要現在的你我掌握什么技能,或許能夠從繁多的技術分支中受到啟發:
這次練習的題目是通過Python抓取拉勾網的招聘詳情頁,並篩選其中的技能關鍵詞,存儲到excel中。
一、獲取職位需求數據
通過觀察可以發現,拉勾網的職位頁面詳情是由http://www.lagou.com/jobs/+*****(PositionId).html組成,而PositionId可以通過分析Json的XHR獲得。而紅框里的職位描述內容是我們要抓取的數據。
知道了數據的源頭,接下來就按照常規步驟包裝Headers,提交FormData來獲取反饋數據。
獲取PositionId列表所在頁面:
1 # 獲取職位的查詢頁面(參數分別為網址,當前頁面數,關鍵詞) 2 def get_page(url, pn, keyword): 3 headers = { 4 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ' 5 'Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3', 6 'Host': 'www.lagou.com', 7 'Connection': 'keep-alive', 8 'Origin': 'http://www.lagou.com' 9 } 10 if pn == 1: 11 boo = 'true' 12 else: 13 boo = 'false' 14 # 通過頁面分析,發現瀏覽器提交的FormData包括以下參數 15 data = parse.urlencode([ 16 ('first', boo), 17 ('pn', pn), 18 ('kd', keyword) 19 ]) 20 req = request.Request(url, headers=headers) 21 page = request.urlopen(req, data=data.encode('utf-8')).read() 22 page = page.decode('utf-8') 23 return page
通過Json獲取PositionId:
1 # 獲取所需的崗位id,每一個招聘頁面詳情都有一個所屬的id索引 2 def read_id(page): 3 tag = 'positionId' 4 page_json = json.loads(page) 5 page_json = page_json['content']['result'] 6 company_list = [] 7 for i in range(15): 8 company_list.append(page_json[i].get(tag)) 9 return company_list
合成目標url:
1 # 獲取職位頁面,由PositionId和BaseUrl組合成目標地址 2 def get_content(company_id): 3 fin_url = r'http://www.lagou.com/jobs/%s.html' % company_id 4 headers = { 5 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ' 6 'Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3', 7 'Host': 'www.lagou.com', 8 'Connection': 'keep-alive', 9 'Origin': 'http://www.lagou.com' 10 } 11 req = request.Request(fin_url, headers=headers) 12 page = request.urlopen(req).read() 13 content = page.decode('utf-8') 14 return content
二、對數據進行處理
獲取數據之后,需要對數據進行清洗,通過BeautifulSoup抓取的職位內容包含Html標簽,需要讓數據脫去這層“外衣”。
1 # 獲取職位需求(通過re來去除html標記),可以將職位詳情單獨存儲 2 def get_result(content): 3 soup = Bs(content, 'lxml') 4 job_description = soup.select('dd[class="job_bt"]') 5 job_description = str(job_description[0]) 6 rule = re.compile(r'<[^>]+>') 7 result = rule.sub('', job_description) 8 return result
現在得到的數據就是職位描述信息,我們要從職位信息當中篩選我們所關注的任職要求關鍵詞。
我們將這些關鍵詞篩選出來,存儲到List當中。經過對整個500+職位進行爬去,我們得到了職位技能關鍵詞的總表。
1 # 過濾關鍵詞:目前篩選的方式只是選取英文關鍵詞 2 def search_skill(result): 3 rule = re.compile(r'[a-zA-z]+') 4 skill_list = rule.findall(result) 5 return skill_list
對關鍵詞按照500+職位需求出現的頻次進行排序,選取頻次排序Top80的關鍵詞,去除無效的關鍵詞。
1 # 對出現的關鍵詞計數,並排序,選取Top80的關鍵詞作為數據的樣本 2 def count_skill(skill_list): 3 for i in range(len(skill_list)): 4 skill_list[i] = skill_list[i].lower() 5 count_dict = Counter(skill_list).most_common(80) 6 return count_dict
三、對數據進行存儲和可視化處理
1 # 對結果進行存儲並生成Area圖 2 def save_excel(count_dict, file_name): 3 book = xlsxwriter.Workbook(r'C:\Users\Administrator\Desktop\%s.xls' % file_name) 4 tmp = book.add_worksheet() 5 row_num = len(count_dict) 6 for i in range(1, row_num): 7 if i == 1: 8 tag_pos = 'A%s' % i 9 tmp.write_row(tag_pos, ['關鍵詞', '頻次']) 10 else: 11 con_pos = 'A%s' % i 12 k_v = list(count_dict[i-2]) 13 tmp.write_row(con_pos, k_v) 14 chart1 = book.add_chart({'type': 'area'}) 15 chart1.add_series({ 16 'name': '=Sheet1!$B$1', 17 'categories': '=Sheet1!$A$2:$A$80', 18 'values': '=Sheet1!$B$2:$B$80' 19 }) 20 chart1.set_title({'name': '關鍵詞排名'}) 21 chart1.set_x_axis({'name': '關鍵詞'}) 22 chart1.set_y_axis({'name': '頻次(/次)'}) 23 tmp.insert_chart('C2', chart1, {'x_offset': 25, 'y_offset': 10})
這就是抓取之后的數據可視化展示。
附上源碼
1 #! -*-coding:utf-8 -*- 2 ''' 3 Function:計算拉勾網編程語言的關鍵詞排名 4 Author:蘭茲 5 ''' 6 7 8 from urllib import request, parse 9 from bs4 import BeautifulSoup as Bs 10 from collections import Counter 11 import lxml 12 import json 13 import datetime 14 import xlsxwriter 15 import re 16 17 starttime = datetime.datetime.now() 18 19 url = r'http://www.lagou.com/jobs/positionAjax.json?city=%E5%8C%97%E4%BA%AC' 20 21 keyword = input('請輸入您所需要查找的關鍵詞 : ') 22 23 24 # 獲取職位的查詢頁面(參數分別為網址,當前頁面數,關鍵詞) 25 def get_page(url, pn, keyword): 26 headers = { 27 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ' 28 'Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3', 29 'Host': 'www.lagou.com', 30 'Connection': 'keep-alive', 31 'Origin': 'http://www.lagou.com' 32 } 33 if pn == 1: 34 boo = 'true' 35 else: 36 boo = 'false' 37 # 通過頁面分析,發現瀏覽器提交的FormData包括以下參數 38 data = parse.urlencode([ 39 ('first', boo), 40 ('pn', pn), 41 ('kd', keyword) 42 ]) 43 req = request.Request(url, headers=headers) 44 page = request.urlopen(req, data=data.encode('utf-8')).read() 45 page = page.decode('utf-8') 46 return page 47 48 49 # 獲取所需的崗位id,每一個招聘頁面詳情都有一個所屬的id索引 50 def read_id(page): 51 tag = 'positionId' 52 page_json = json.loads(page) 53 page_json = page_json['content']['result'] 54 company_list = [] 55 for i in range(15): 56 company_list.append(page_json[i].get(tag)) 57 return company_list 58 59 60 # 獲取當前招聘關鍵詞的最大頁數,大於30的將會被覆蓋,所以最多只能抓取30頁的招聘信息 61 def read_max_page(page): 62 page_json = json.loads(page) 63 max_page_num = page_json['content']['totalPageCount'] 64 if max_page_num > 30: 65 max_page_num = 30 66 return max_page_num 67 68 69 # 獲取職位頁面,由ositionId和BaseUrl組合成目標地址 70 def get_content(company_id): 71 fin_url = r'http://www.lagou.com/jobs/%s.html' % company_id 72 headers = { 73 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ' 74 'Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3', 75 'Host': 'www.lagou.com', 76 'Connection': 'keep-alive', 77 'Origin': 'http://www.lagou.com' 78 } 79 req = request.Request(fin_url, headers=headers) 80 page = request.urlopen(req).read() 81 content = page.decode('utf-8') 82 return content 83 84 85 # 獲取職位需求(通過re來去除html標記),可以將職位詳情單獨存儲 86 def get_result(content): 87 soup = Bs(content, 'lxml') 88 job_description = soup.select('dd[class="job_bt"]') 89 job_description = str(job_description[0]) 90 rule = re.compile(r'<[^>]+>') 91 result = rule.sub('', job_description) 92 return result 93 94 95 # 過濾關鍵詞:目前篩選的方式只是選取英文關鍵詞 96 def search_skill(result): 97 rule = re.compile(r'[a-zA-z]+') 98 skill_list = rule.findall(result) 99 return skill_list 100 101 102 # 對出現的關鍵詞計數,並排序,選取Top80的關鍵詞作為數據的樣本 103 def count_skill(skill_list): 104 for i in range(len(skill_list)): 105 skill_list[i] = skill_list[i].lower() 106 count_dict = Counter(skill_list).most_common(80) 107 return count_dict 108 109 110 # 對結果進行存儲並生成Area圖 111 def save_excel(count_dict, file_name): 112 book = xlsxwriter.Workbook(r'C:\Users\Administrator\Desktop\%s.xls' % file_name) 113 tmp = book.add_worksheet() 114 row_num = len(count_dict) 115 for i in range(1, row_num): 116 if i == 1: 117 tag_pos = 'A%s' % i 118 tmp.write_row(tag_pos, ['關鍵詞', '頻次']) 119 else: 120 con_pos = 'A%s' % i 121 k_v = list(count_dict[i-2]) 122 tmp.write_row(con_pos, k_v) 123 chart1 = book.add_chart({'type': 'area'}) 124 chart1.add_series({ 125 'name': '=Sheet1!$B$1', 126 'categories': '=Sheet1!$A$2:$A$80', 127 'values': '=Sheet1!$B$2:$B$80' 128 }) 129 chart1.set_title({'name': '關鍵詞排名'}) 130 chart1.set_x_axis({'name': '關鍵詞'}) 131 chart1.set_y_axis({'name': '頻次(/次)'}) 132 tmp.insert_chart('C2', chart1, {'x_offset': 25, 'y_offset': 10}) 133 134 ###################################################################################### 135 136 if __name__ == '__main__': 137 max_pn = read_max_page(get_page(url, 1, keyword)) # 獲取招聘頁數 138 fin_skill_list = [] # 關鍵詞總表 139 for pn in range(1, max_pn): 140 print('***********************正在抓取第%s頁信息***********************' % pn) 141 page = get_page(url, pn, keyword) 142 company_list = read_id(page) 143 for company_id in company_list: 144 content = get_content(company_id) 145 result = get_result(content) 146 skill_list = search_skill(result) 147 fin_skill_list.extend(skill_list) 148 print('***********************開始統計關鍵詞出現頻率***********************') 149 count_dict = count_skill(fin_skill_list) 150 print(count_dict) 151 file_name = input(r'請輸入要保存的文件名:') 152 save_excel(count_dict, file_name) 153 print('***********************正在保存到桌面***********************') 154 endtime = datetime.datetime.now() 155 time = (endtime - starttime).seconds 156 print('總共用時:%s s' % time)
30*15頁的內容抓取需要花費2分多鍾,相對來說還是有些慢,可以加入並行模塊抓取數據。
至此,拉勾網職位需求關鍵詞的抓取就完成了。
這個爬蟲的目的就是為了抓取與編程語言相關的技能需求,大家可以通過排名靠前的關鍵詞獲知主流的框架或結構,避免遺漏。也可以通過長尾關鍵詞來擴展自己的知識面。
還有其他功能,大家可以自行開發,這里只做拋磚引玉之用,歡迎交流,轉載請注明出處~ (^ _ ^)/~~