python如何爬取網站數據并進行數據可視化
前言
爬取拉勾網關于python職位相關的數據信息,并將爬取的數據已csv各式存入文件,然后對csv文件相關字段的數據進行清洗,并對數據可視化展示,包括柱狀圖展示、直方圖展示、詞云展示等并根據可視化的數據做進一步的分析,其余分析和展示讀者可自行發(fā)揮和擴展包括各種分析和不同的存儲方式等。。。。。
一、爬取和分析相關依賴包
- Python版本: Python3.6
- requests: 下載網頁
- math: 向上取整
- time: 暫停進程
- pandas:數據分析并保存為csv文件
- matplotlib:繪圖
- pyecharts:繪圖
- statsmodels:統計建模
- wordcloud、scipy、jieba:生成中文詞云
- pylab:設置畫圖能顯示中文
在以上安裝或使用過程中可能讀者會遇到安裝或導入失敗等問題自行百度,選擇依賴包的合適版本
二、分析網頁結構
通過Chrome搜索'python工程師',然后右鍵點擊檢查或者F12,,使用檢查功能查看網頁源代碼,當我們點擊下一頁觀察瀏覽器的搜索欄的url并沒有改變,這是因為拉勾網做了反爬蟲機制, 職位信息并不在源代碼里,而是保存在JSON的文件里,因此我們直接下載JSON,并使用字典方法直接讀取數據.即可拿到我們想要的python職位相關的信息,
待爬取的python工程師職位信息如下:
為了能爬到我們想要的數據,我們要用程序來模擬瀏覽器來查看網頁,所以我們在爬取的過程中會加上頭信息,頭信息也是我們通過分析網頁獲取到的,通過網頁分析我們知道該請求的頭信息,以及請求的信息和請求的方式是POST請求,這樣我們就可以該url請求拿到我們想的數據做進一步處理
爬取網頁信息代碼如下:
import requests url = ' https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false' def get_json(url, num): """ 從指定的url中通過requests請求攜帶請求頭和請求體獲取網頁中的信息, :return: """ url1 = 'https://www.lagou.com/jobs/list_python%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88?labelWords=&fromSearch=true&suginput=' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36', 'Host': 'www.lagou.com', 'Referer': 'https://www.lagou.com/jobs/list_%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90?labelWords=&fromSearch=true&suginput=', 'X-Anit-Forge-Code': '0', 'X-Anit-Forge-Token': 'None', 'X-Requested-With': 'XMLHttpRequest' } data = { 'first': 'true', 'pn': num, 'kd': 'python工程師'} s = requests.Session() print('建立session:', s, '\n\n') s.get(url=url1, headers=headers, timeout=3) cookie = s.cookies print('獲取cookie:', cookie, '\n\n') res = requests.post(url, headers=headers, data=data, cookies=cookie, timeout=3) res.raise_for_status() res.encoding = 'utf-8' page_data = res.json() print('請求響應結果:', page_data, '\n\n') return page_data print(get_json(url, 1))
通過搜索我們知道每頁顯示15個職位,最多顯示30頁,通過分析網頁源代碼知道,可以通過JSON里讀取總職位數,通過總的職位數和每頁能顯示的職位數.我們可以計算出總共有多少頁,然后使用循環(huán)按頁爬取, 最后將職位信息匯總, 寫入到CSV格式的文件中.
程序運行結果如圖:
爬取所有python相關職位信息如下:
三、數據清洗后入庫
數據清洗其實會占用很大一部分工作,我們在這里只做一些簡單的數據分析后入庫。在拉勾網輸入python相關的職位會有18988個。你可以根據工作中需求選擇要入庫的字段,并對一些字段做進一步的篩選,比如我們可以去除職位名稱中為實習生的崗位,過濾指定的字段區(qū)域在我們指定區(qū)域的職位,取字段薪資的平均值,以最低值和差值的四分之一為平均值等等根據需求自由發(fā)揮
import pandas as pd import matplotlib.pyplot as plt import statsmodels.api as sm from wordcloud import WordCloud from scipy.misc import imread from imageio 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('Python_development_engineer.csv', encoding='utf-8') # 進行數據清洗,過濾掉實習崗位 # df.drop(df[df['職位名稱'].str.contains('實習')].index, inplace=True) # print(df.describe()) # 由于csv文件中的字符是字符串形式,先用正則表達式將字符串轉化為列表,在去區(qū)間的均值 pattern = '\d+' # print(df['工作經驗'], '\n\n\n') # print(df['工作經驗'].str.findall(pattern)) df['工作年限'] = df['工作經驗'].str.findall(pattern) print(type(df['工作年限']), '\n\n\n') avg_work_year = [] count = 0 for i in df['工作年限']: # print('每個職位對應的工作年限',i) # 如果工作經驗為'不限'或'應屆畢業(yè)生',那么匹配值為空,工作年限為0 if len(i) == 0: avg_work_year.append(0) # print('nihao') count += 1 # 如果匹配值為一個數值,那么返回該數值 elif len(i) == 1: # print('hello world') avg_work_year.append(int(''.join(i))) count += 1 # 如果匹配為一個區(qū)間則取平均值 else: num_list = [int(j) for j in i] avg_year = sum(num_list) / 2 avg_work_year.append(avg_year) count += 1 print(count) df['avg_work_year'] = avg_work_year # 將字符串轉化為列表,薪資取最低值加上區(qū)間值得25%,比較貼近現實 df['salary'] = df['薪資'].str.findall(pattern) # avg_salary_list = [] for k in df['salary']: int_list = [int(n) for n in k] avg_salary = int_list[0] + (int_list[1] - int_list[0]) / 4 avg_salary_list.append(avg_salary) df['月薪'] = avg_salary_list # df.to_csv('python.csv', index=False)
四、數據可視化展示
下面是對數據的可視化展示,僅以部分視圖進行一些可視化的展示,如果讀者想對其他字段做一些展示以及想使用不同的視圖類型進行展示,請自行發(fā)揮,注:以下代碼中引入的模塊見最后的完整代碼
1、繪制python薪資的頻率直方圖并保存
如果我們想看看關于互聯網行業(yè)python工程師相關的崗位大家普遍薪資的一個分部區(qū)間在哪個范圍,占據了多達的比例我們就可以借助matplotlib庫,來將我們保存在csv文件中的數據進行可視化的展示,然我們能夠更直觀的看到數據的一個分部趨勢
# 繪制python薪資的頻率直方圖并保存 plt.hist(df['月薪'],bins=8,facecolor='#ff6700',edgecolor='blue') # bins是默認的條形數目 plt.xlabel('薪資(單位/千元)') plt.ylabel('頻數/頻率') plt.title('python薪資直方圖') plt.savefig('python薪資分布.jpg') plt.show()
運行結果如下:
2、繪制python相關職位的地理位置餅狀圖
通過地理python職位地理位置的分部我們可以大致了解IT行業(yè)主要集中分部在哪些城市,這樣也更利于我們選擇地域進行選擇性就業(yè),可以獲得更多的面試機會等,參數可自行調試,或根據需要添加。
# 繪制餅狀圖并保存 city = df['城市'].value_counts() print(type(city)) # print(len(city)) label = city.keys() print(label) city_list = [] count = 0 n = 1 distance = [] for i in city: city_list.append(i) print('列表長度', len(city_list)) count += 1 if count > 5: n += 0.1 distance.append(n) else: distance.append(0) plt.pie(city_list, labels=label, labeldistance=1.2, autopct='%2.1f%%', pctdistance=0.6, shadow=True, explode=distance) plt.axis('equal') # 使餅圖為正圓形 plt.legend(loc='upper left', bbox_to_anchor=(-0.1, 1)) plt.savefig('python地理位置分布圖.jpg') plt.show()
運行結果如下:
3、繪制基于pyechart的城市分布柱狀圖
pycharts是python中調用百度基于js開發(fā)的echarts接口,也可以對數據進行各種可視化操作,更多數據可視化圖形展示,可參考echarts官網:https://www.echartsjs.com/,echarts官網提供了各種實例供我們參考,如折線圖、柱狀圖、餅圖、路徑圖、樹圖等等,基于pyecharts的文檔可參考以下官網:https://pyecharts.org/#/,更多用法也可自行百度網絡資源
city = df['城市'].value_counts() print(type(city)) print(city) # print(len(city)) keys = city.index # 等價于keys = city.keys() values = city.values from pyecharts import Bar bar = Bar("python職位的城市分布圖") bar.add("城市", keys, values) bar.print_echarts_options() # 該行只為了打印配置項,方便調試時使用 bar.render(path='a.html')
運行結果如下:
4、繪制python福利相關的詞云
詞云圖又叫文字云,是對文本數據中出現頻率較高的關鍵詞予以視覺上的突出,形成"關鍵詞的渲染"就類似云一樣的彩色圖片,從而過濾掉大量的文本信息,,使人一眼就可以領略文本數據的主要表達意思。利用jieba分詞和詞云生成WorldCloud(可自定義背景),下面就是對python相關職位的福利做了一個詞云的展示,可以更直觀的看到大多數公司的福利待遇集中在哪些地方
# 繪制福利待遇的詞云 text = '' for line in df['公司福利']: if len(eval(line)) == 0: continue else: for word in eval(line): # print(word) text += word cut_word = ','.join(jieba.cut(text)) word_background = imread('公主.jpg') cloud = WordCloud( font_path=r'C:\Windows\Fonts\simfang.ttf', background_color='black', mask=word_background, max_words=500, max_font_size=100, width=400, height=800 ) word_cloud = cloud.generate(cut_word) word_cloud.to_file('福利待遇詞云.png') plt.imshow(word_cloud) plt.axis('off') plt.show()
運行結果如下:
五、爬蟲及可視化完整代碼
完整代碼在下面,代碼均測試可正常運行,感興趣的小伙伴可去嘗試和了解其中的使用方法,如運行或者模塊安裝等失敗可以在評論區(qū)進行留言,讓我們一同解決吧
如果你覺得對你有幫助可以點個贊哦,原創(chuàng)內容轉載需說明出處?。。?/p>
1、爬蟲完整代碼
為了防止我們頻繁請求一個網站被限制ip,我們在爬取每一頁后選擇睡一段時間,當然你也可以使用代理等其他方式自行實現
import requests import math import time import pandas as pd def get_json(url, num): """ 從指定的url中通過requests請求攜帶請求頭和請求體獲取網頁中的信息, :return: """ url1 = 'https://www.lagou.com/jobs/list_python%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88?labelWords=&fromSearch=true&suginput=' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36', 'Host': 'www.lagou.com', 'Referer': 'https://www.lagou.com/jobs/list_%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90?labelWords=&fromSearch=true&suginput=', 'X-Anit-Forge-Code': '0', 'X-Anit-Forge-Token': 'None', 'X-Requested-With': 'XMLHttpRequest' } data = { 'first': 'true', 'pn': num, 'kd': 'python工程師'} s = requests.Session() print('建立session:', s, '\n\n') s.get(url=url1, headers=headers, timeout=3) cookie = s.cookies print('獲取cookie:', cookie, '\n\n') res = requests.post(url, headers=headers, data=data, cookies=cookie, timeout=3) res.raise_for_status() res.encoding = 'utf-8' page_data = res.json() print('請求響應結果:', page_data, '\n\n') return page_data def get_page_num(count): """ 計算要抓取的頁數,通過在拉勾網輸入關鍵字信息,可以發(fā)現最多顯示30頁信息,每頁最多顯示15個職位信息 :return: """ page_num = math.ceil(count / 15) if page_num > 30: return 30 else: return page_num def get_page_info(jobs_list): """ 獲取職位 :param jobs_list: :return: """ page_info_list = [] for i in jobs_list: # 循環(huán)每一頁所有職位信息 job_info = [] job_info.append(i['companyFullName']) job_info.append(i['companyShortName']) job_info.append(i['companySize']) job_info.append(i['financeStage']) job_info.append(i['district']) job_info.append(i['positionName']) job_info.append(i['workYear']) job_info.append(i['education']) job_info.append(i['salary']) job_info.append(i['positionAdvantage']) job_info.append(i['industryField']) job_info.append(i['firstType']) job_info.append(i['companyLabelList']) job_info.append(i['secondType']) job_info.append(i['city']) page_info_list.append(job_info) return page_info_list def main(): url = ' https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false' first_page = get_json(url, 1) total_page_count = first_page['content']['positionResult']['totalCount'] num = get_page_num(total_page_count) total_info = [] time.sleep(10) print("python開發(fā)相關職位總數:{},總頁數為:{}".format(total_page_count, num)) for num in range(1, num + 1): # 獲取每一頁的職位相關的信息 page_data = get_json(url, num) # 獲取響應json jobs_list = page_data['content']['positionResult']['result'] # 獲取每頁的所有python相關的職位信息 page_info = get_page_info(jobs_list) print("每一頁python相關的職位信息:%s" % page_info, '\n\n') total_info += page_info print('已經爬取到第{}頁,職位總數為{}'.format(num, len(total_info))) time.sleep(20) # 將總數據轉化為data frame再輸出,然后在寫入到csv各式的文件中 df = pd.DataFrame(data=total_info, columns=['公司全名', '公司簡稱', '公司規(guī)模', '融資階段', '區(qū)域', '職位名稱', '工作經驗', '學歷要求', '薪資', '職位福利', '經營范圍', '職位類型', '公司福利', '第二職位類型', '城市']) # df.to_csv('Python_development_engineer.csv', index=False) print('python相關職位信息已保存') if __name__ == '__main__': main()
2、可視化完整代碼
數據可視化涉及到matplotlib、jieba、wordcloud、pyecharts、pylab、scipy等等模塊的使用,讀者可以自行了解各個模塊的使用方法,和其中涉及的各種參數
import pandas as pd import matplotlib.pyplot as plt import statsmodels.api as sm from wordcloud import WordCloud from scipy.misc import imread # from imageio 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('Python_development_engineer.csv', encoding='utf-8') # 進行數據清洗,過濾掉實習崗位 # df.drop(df[df['職位名稱'].str.contains('實習')].index, inplace=True) # print(df.describe()) # 由于csv文件中的字符是字符串形式,先用正則表達式將字符串轉化為列表,在去區(qū)間的均值 pattern = '\d+' # print(df['工作經驗'], '\n\n\n') # print(df['工作經驗'].str.findall(pattern)) df['工作年限'] = df['工作經驗'].str.findall(pattern) print(type(df['工作年限']), '\n\n\n') avg_work_year = [] count = 0 for i in df['工作年限']: # print('每個職位對應的工作年限',i) # 如果工作經驗為'不限'或'應屆畢業(yè)生',那么匹配值為空,工作年限為0 if len(i) == 0: avg_work_year.append(0) # print('nihao') count += 1 # 如果匹配值為一個數值,那么返回該數值 elif len(i) == 1: # print('hello world') avg_work_year.append(int(''.join(i))) count += 1 # 如果匹配為一個區(qū)間則取平均值 else: num_list = [int(j) for j in i] avg_year = sum(num_list) / 2 avg_work_year.append(avg_year) count += 1 print(count) df['avg_work_year'] = avg_work_year # 將字符串轉化為列表,薪資取最低值加上區(qū)間值得25%,比較貼近現實 df['salary'] = df['薪資'].str.findall(pattern) # avg_salary_list = [] for k in df['salary']: int_list = [int(n) for n in k] avg_salary = int_list[0] + (int_list[1] - int_list[0]) / 4 avg_salary_list.append(avg_salary) df['月薪'] = avg_salary_list # df.to_csv('python.csv', index=False) """1、繪制python薪資的頻率直方圖并保存""" plt.hist(df['月薪'], bins=8, facecolor='#ff6700', edgecolor='blue') # bins是默認的條形數目 plt.xlabel('薪資(單位/千元)') plt.ylabel('頻數/頻率') plt.title('python薪資直方圖') plt.savefig('python薪資分布.jpg') plt.show() """2、繪制餅狀圖并保存""" city = df['城市'].value_counts() print(type(city)) # print(len(city)) label = city.keys() print(label) city_list = [] count = 0 n = 1 distance = [] for i in city: city_list.append(i) print('列表長度', len(city_list)) count += 1 if count > 5: n += 0.1 distance.append(n) else: distance.append(0) plt.pie(city_list, labels=label, labeldistance=1.2, autopct='%2.1f%%', pctdistance=0.6, shadow=True, explode=distance) plt.axis('equal') # 使餅圖為正圓形 plt.legend(loc='upper left', bbox_to_anchor=(-0.1, 1)) plt.savefig('python地理位置分布圖.jpg') plt.show() """3、繪制福利待遇的詞云""" text = '' for line in df['公司福利']: if len(eval(line)) == 0: continue else: for word in eval(line): # print(word) text += word cut_word = ','.join(jieba.cut(text)) word_background = imread('公主.jpg') cloud = WordCloud( font_path=r'C:\Windows\Fonts\simfang.ttf', background_color='black', mask=word_background, max_words=500, max_font_size=100, width=400, height=800 ) word_cloud = cloud.generate(cut_word) word_cloud.to_file('福利待遇詞云.png') plt.imshow(word_cloud) plt.axis('off') plt.show() """4、基于pyechart的柱狀圖""" city = df['城市'].value_counts() print(type(city)) print(city) # print(len(city)) keys = city.index # 等價于keys = city.keys() values = city.values from pyecharts import Bar bar = Bar("python職位的城市分布圖") bar.add("城市", keys, values) bar.print_echarts_options() # 該行只為了打印配置項,方便調試時使用 bar.render(path='a.html')
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
基于Django的樂觀鎖與悲觀鎖解決訂單并發(fā)問題詳解
這篇文章主要介紹了基于Django的樂觀鎖與悲觀鎖解決訂單并發(fā)問題詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-07-07selenium?drag_and_drop不生效的解決辦法
本文主要介紹了selenium?drag_and_drop不生效的解決辦法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-03-03