欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

使用Python爬取前程無憂上南京地區Python職位以及對應工資

系統 1950 0

獲取原始數據

最近在學習Python,做了一個爬蟲程序練練手,前程無憂這個網站頁面布局還是挺簡單的,適合我這種新手。使用requests+bs4爬取
不多說了,先來看看頁面布局吧。

使用Python爬取前程無憂上南京地區Python職位以及對應工資_第1張圖片
這是前程無憂上的職位列表,看上去還是很清楚的

然后再來看看頁面布局,使用Google瀏覽器打開前程無憂網頁,然后按下F12

使用Python爬取前程無憂上南京地區Python職位以及對應工資_第2張圖片
每一個class為el的div就代表一個招聘信息

然后再來看看div里面是怎么布局的,我們需要獲取第二列公司名稱以及第四列的薪資,其他的暫時不管。
使用Python爬取前程無憂上南京地區Python職位以及對應工資_第3張圖片
公司名稱在el這個div下面的class為t2的span標簽下面。

使用Python爬取前程無憂上南京地區Python職位以及對應工資_第4張圖片
薪資在t4的span標簽下面。
這樣獲取的邏輯就很簡單了。

  • 首先使用BeautifulSoup解析request獲取的html
  • 找到所有class=el的div標簽的集合
  • 在每個el標簽下找到t2和t4標簽,將它們的內容讀取保存在字典中
  • 比如:‘南京萬瑞建設工程有限公司’:‘12-20萬/年’

以上是爬取一頁的數據,我們當然不能只能爬取一頁這么簡單了,往下一頁爬取有兩種方法:
第一種方法就是獲取到下一頁的url,然后通過遞歸調用,不斷地爬取
下一頁的標簽是這樣的:
使用Python爬取前程無憂上南京地區Python職位以及對應工資_第5張圖片
下一頁在class等于bk的li標簽下的a標簽里面,首先要獲取下一頁的標簽next_page,然后通過

            
              next_url = next_page['href']

            
          

就可以獲取到url,然后重復上述爬取一頁的步驟,就可以不斷的往下爬取了。

第二種方法我們來研究一下url
https://search.51job.com/list/070200,000000,0000,00,9,99,Python,2,1.html
這是第一頁的url,注意最后的Python,2,1
https://search.51job.com/list/070200,000000,0000,00,9,99,Python,2,2.html
這是第二頁,區別就是2,1變成了2,2
后面第三頁,第四頁就不看了,都是一樣,只有數字的變化,這樣就可以采用for循環了。

            
              urlpri = 'https://search.51job.com/list/070200,000000,0000,00,9,99,Python,2,{page}.html'
for i in range(1,page+1) :#從1開始,并且page要加1,不然爬取不到最后一頁
	url = urlpri.format(**{'page':i})

            
          

下面來看這部分代碼:

            
              def salary_python(page):
    """
    獲取前程無憂上前page頁的Python職位對應的公司名稱以及薪水
    :param page: 頁數
    :return:返回公司名稱與薪水對應的字典
    """
    urlpri = 'https://search.51job.com/list/070200,000000,0000,00,9,99,Python,2,{page}.html'
    info = {}
    for i in range(1,page+1):
        url = urlpri.format(**{'page':i})
        res = requests.get(url)
        if res.status_code == 200:
            soup = BeautifulSoup(res.content, 'lxml')
            jobList = soup.find_all('div', class_='el')
            for job in jobList:
                companyName = ''
                salary = ''
                companyTag = job.find('span', class_='t2')
                if companyTag:
                    companyTag1 = companyTag.find('a')
                    if companyTag1:
                        companyName = companyTag1.string
                salaryTag = job.find('span', class_='t4')
                if salaryTag:
                    salary = salaryTag.string
                if companyName and salary: #有些職位沒有寫薪資,遇到這樣的我們就跳過,這地方需要過濾一下
                    info[companyName] = salary
    return info

            
          

使用Python爬取前程無憂上南京地區Python職位以及對應工資_第6張圖片
看一下運行結果,是可以獲取到對應的公司名稱以及開出的薪資的,我的pycharm不知道出了啥問題,debug的時候想點開看一下,結果一點開debug就卡死,有知道原因的大神可以來解答一下。

數據簡單處理

上面我們獲取到的是原始數據,只有這個數據是看不出什么的,所以我們簡單處理一下,這里用到Python的pandas模塊,需要先安裝一下

            
              pip install pandas

            
          

主要是對工資進行處理,研究一下發現工資的寫法主要包括下面幾種

  • xx(-xx)萬/月
  • xx(-xx)萬/年
  • xx(-xx)千/月
  • xx(-xx)百/天
    或者沒有萬,百,千這種單位,直接是數字加上時間(月,年,天)
    剩下一些少見的單位,像什么萬/天、百/月,就不考慮了。

我們單獨寫一個方法來處理工資的這種表述,統一化成 以月為單位 的形式
比如12萬/年,將其轉化為10000
對于工資在某一范圍的,就取個中間值吧
比如0.6–1.2萬/月,轉化為9000

下面來看代碼:

            
              def handle_salary(s):
    """
    將str類型的薪水表述,轉化為flaot類型,并全部轉化為 元/月為單位
    :param s: 字符串類型數據
    :return: float類型薪水
    """
    if r'萬' in s and r'月' in s:
        matchwMouth1 = re.match(r'(\d+\.*\d*)\-(\d+\.*\d*)', s, re.I)
        matchwMouth2 = re.match(r'(\d+\.*\d*)', s, re.I)
        if matchwMouth1:
            sMin = float(matchwMouth1.group(1))
            sMax = float(matchwMouth1.group(2))
            salary = (sMax+sMin)/2.0
            return round(salary*10000, 2)
        elif matchwMouth2:
            salary = float(matchwMouth2.group(1))
            return round(salary*10000, 2)
        else:
            return s
    elif r'萬' in s and r'年' in s:
        matchwYear1 = re.match(r'(\d+\.*\d*)\-(\d+\.*\d*)', s, re.I)
        matchwYear2 = re.match(r'(\d+\.*\d*)', s, re.I)
        if matchwYear1:
            sMin = float(matchwYear1.group(1))
            sMax = float(matchwYear1.group(2))
            salary = (sMax + sMin) / (2.0*12)
            return round(salary*10000, 2)
        elif matchwYear2:
            salary = float(matchwYear2.group(1))/12.0
            return round(salary*10000, 2)
        else:
            return s
    elif r'千' in s and r'月' in s:
        matchqMouth1 = re.match(r'(\d+\.*\d*)\-(\d+\.*\d*)', s, re.I)
        matchqMouth2 = re.match(r'(\d+\.*\d*)', s, re.I)
        if matchqMouth1:
            sMin = float(matchqMouth1.group(1))
            sMax = float(matchqMouth1.group(2))
            salary = (sMax + sMin) / 2.0
            return round(salary*1000, 2)
        elif matchqMouth2:
            salary = float(matchqMouth2.group(1))
            return round(salary*1000, 2)
        else:
            return s
    elif r'百' in s and r'天' in s:
        matchbDay1 = re.match(r'(\d+\.*\d*)\-(\d+\.*\d*)', s, re.I)
        matchbDay2 = re.match(r'(\d+\.*\d*)', s, re.I)
        if matchbDay1:
            sMin = float(matchbDay1.group(1))
            sMax = float(matchbDay1.group(2))
            salary = (sMax + sMin) / 2.0
            return round(salary*3000, 2)
        elif matchbDay2:
            salary = float(matchbDay2.group(1))
            return round(salary*3000, 2)
        else:
            return s
    elif r'天' in s:
        matchbDay1 = re.match(r'(\d+\.*\d*)\-(\d+\.*\d*)', s, re.I)
        matchbDay2 = re.match(r'(\d+\.*\d*)', s, re.I)
        if matchbDay1:
            sMin = float(matchbDay1.group(1))
            sMax = float(matchbDay1.group(2))
            salary = (sMax + sMin) / 2.0
            return round(salary*30, 2)
        elif matchbDay2:
            salary = float(matchbDay2.group(1))
            return round(salary*30, 2)
        else:
            return s
    elif r'月' in s:
           matchMouth1 = re.match(r'(\d+\.*\d*)\-(\d+\.*\d*)', s, re.I)
           matchMouth2 = re.match(r'(\d+\.*\d*)', s, re.I)
           if matchMouth1:
               sMin = float(matchMouth1.group(1))
               sMax = float(matchMouth1.group(2))
               salary = (sMax + sMin) / 2.0
               return round(salary, 2)
           elif matchMouth2:
               salary = float(matchMouth2.group(1))
               return round(salary, 2)
           else:
               return s
    elif r'年' in s:
        matchYear1 = re.match(r'(\d+\.*\d*)\-(\d+\.*\d*)', s, re.I)
        matchYear2 = re.match(r'(\d+\.*\d*)', s, re.I)
        if matchYear1:
            sMin = float(matchYear1.group(1))
            sMax = float(matchYear1.group(2))
            salary = (sMax + sMin) / (2.0 * 12)
            return round(salary, 2)
        elif matchYear2:
            salary = float(matchYear2.group(1)) / 12.0
            return round(salary, 2)
        else:
            return s
    else:
        return s  #工資的表示形式如果不在上述幾種形式范圍內,就返回它的原有值,這個到后面還要在處理

            
          

使用Python爬取前程無憂上南京地區Python職位以及對應工資_第7張圖片
調試一下,輸出都是對的。

接下來用一個for循環,把全部數據處理一下。
奉上代碼:

            
              def cleanData(dict):
    """
    清理獲取的數據,薪水全部轉化為float,單位為 元/月
    :param dict: 獲取的原始數據
    :return: 返回處理過的數據
    """
    nameList = list(dict.keys())
    salary = list(dict.values())
    salaryList = []
    for item in salary:
        salaryItem = handle_salary(item)
        salaryList.append(salaryItem)

    dataDict = {}
    for i in range(len(nameList)):
        dataDict[nameList[i]] = salaryList[i]

    dataDictNew = {}
    for key,value in dataDict.items():
        if isinstance(value,float):
            dataDictNew[key] = value
    data = {'name': list(dataDictNew.keys()), 'salary': list(dataDictNew.values())}
    df = pd.DataFrame(data)
    return df

            
          

這里有幾點要說明

            
                  dataDict = {}
    for i in range(len(nameList)):
        dataDict[nameList[i]] = salaryList[i]

            
          

對數據的處理其實到這兒就已經結束了

            
               dataDictNew = {}
    for key,value in dataDict.items():
        if isinstance(value,float):
            dataDictNew[key] = value

            
          

這部分代碼是為了過濾掉上面說的handle_salary這個方法沒能處理掉的數據,經過處理過的工資,數據類型應該都是float,如果不是float,就將這條數據刪除。

            
                  data = {'name': list(dataDictNew.keys()), 'salary': list(dataDictNew.values())}
    df = pd.DataFrame(data)
    return df

            
          

這是將數據保存為pandas的dataframe形式,關于這種數據結構,可以參考這篇博客
https://www.cnblogs.com/IvyWong/p/9203981.html

保存數據

經過處理過的數據,將它保存在一個csv文件里,方便以后查看,pandas模塊有直接處理csv文件的方法,非常方便。

            
              def saveDataCsv(df):
    """
    保存數據到csv文件中
    :param df: dataframe類型數據
    :return:
    """
    filename = 'python_51job_salary.csv'
    try:
        df.to_csv(filename, encoding='gbk')
    except UnicodeEncodeError:
        print("編碼錯誤, 該數據無法寫到文件中, 直接忽略該數據")

            
          

使用Python爬取前程無憂上南京地區Python職位以及對應工資_第8張圖片

簡單分析

dataframe有個describe()方法,可以簡單分析一下數據,我們來看一下

            
              print(dfSalary.describe())  #dfsalary是處理過的數據,保存為dataframe格式

            
          

輸出:

            
                           salary
count    146.000000       #樣本數量
mean   13519.748836     #工資平均值
std     7021.955639         #工資標準差
min     3750.000000        #最小值
25%     9000.000000		#從小到大排列,第25%的那個數
50%    12500.000000      #中位數
75%    15750.000000      #同25%
max    45000.000000       #最大值

            
          

還可以利用pandas模塊畫一個折線圖

            
              dfSalary.plot()
plt.show()  #繪制折現圖表

            
          

使用Python爬取前程無憂上南京地區Python職位以及對應工資_第9張圖片
工資看上去一萬到兩萬的比較多。
下面這個方法用于統計工資高于某個值所占的比例:

            
              def over(df, num):
    """
    計算高于num的工資所占比例
    :param df: 原始數據,dataframe類型
    :param num: 高于工資
    :return: 比例
    """
    salaryList = df.salary.tolist()
    overList = [x for x in salaryList if x>num]
    over = len(overList)*1.0/len(salaryList)
    return over

            
          
            
              print(over(dfSalary,10000))    #工資高于10000所占比例  輸出:0.7123287671232876

            
          

各位可以看下自己大概在啥水平哈。

新手一枚,代碼還有許多不合理之處,歡迎各位大神提出意見,共同進步!!
附上github源碼:
https://github.com/cchhgithub/pythonLearning/blob/master/pachong/51job.py


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 高清在线不卡 | 香港三级日本三级韩国a | 成人亚洲国产综合精品91 | 中国一级黄色片 | 国产换爱交换乱理伦片 | 欧美在线免费 | 亚洲天堂ww | 狠狠插天天干 | 97av在线| av色偷偷| 欧美激情精品久久久久 | 日本高清视频在线三级 | 麻豆传媒地址 | 久久成人一区二区 | 在线国产视频 | 成人一级| av一二三区| 黄色激情小视频 | 精品人成 | 精品一区二区在线观看视频 | 国产免费一级淫片 | 国产成人免费高清激情明星 | 啊啊啊好紧好爽 | 国产91精品黄网在线观看 | 亚洲视频在线看 | 免费观看呢日本天堂视频 | 99久久精品国产自免费 | 久久久91 | 日本成人一区二区三区 | 开心久久网 | 国产三级一区二区三区 | 国产欧美一区二区成人影院 | 亚洲人网站 | 性欧美一区 | 国产福利不卡视频在免费 | 成人激情综合网 | 亚洲涩涩| 欧美成人全部费免网站 | 亚洲欧美日韩精品高清 | 亚洲精品天堂 | 91看片淫黄大片在看 |