利用python爬蟲(案例7)--X訊招聘的小職位們

學習筆記


爬取X訊招聘的小職位們

寫個小案例,我們想爬取X訊招聘網站裏處於1級頁面的職位名稱和處於2級頁面的工作職責工作要求。由於這個X訊招聘網站是動態加載的,所以需要抓取我們與網站進行交互時產生的數據包。


爬取步驟

①確定X訊招聘的URL地址(https://careers.tencent.com/search.html)

②在1級頁面中抓包,並獲取1級頁面中的json地址

③在2級頁面中抓包,獲取2級頁面中的json地址

④爬取數據,並將數據存放在mysql數據庫中


1級頁面抓包


我們打開X訊招聘網站後,右鍵打開審查元素–>點擊Network–>點擊XHR(我們要的數據包主要在這裏)–>刷新網頁,獲取多個數據包–>點開preview, 依次判斷哪個數據包中有我們要的數據–>確定我們想要數據包

經過這麼一堆步驟後,我找到了想要的數據包。
參數RecruitPostName所對應的值,就是我們要爬取的職位名稱:

我們點開Headers,查看數據包的頭部信息,獲取JSON文件的URL地址(Request URL),以及查詢參數:

JSON文件的URL地址:

https://careers.tencent.com/tencentcareer/api/post/Query?timestamp=1587432663964&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword=&pageIndex=1&pageSize=10&language=zh-cn&area=cn

查詢參數:

timestamp:1587432663964
countryId:
cityId:
bgIds:
productId:
categoryId:
parentCategoryId:
attrId:
keyword:
pageIndex:1
pageSize:10
language:zh-cn
area:cn

我們看到,pageIndex表示的可能表示的是第幾頁;pageSize表示的可能是一頁中有多少職位信息;而timestamp應該是時間戳,我們知道每次發請求時,時間戳肯定都不一樣,如果服務端需要時間戳這個查詢參數,那麼就需要我們在python中自己生成,如果不需要,就可以把這個查詢參數從URL中剔除,或者隨便寫一個整數(比如1)。


2級頁面抓包


按照和上面類似的步驟,我們在2級頁面中,抓到了想要的數據包。
而參數Requirement和Responsibility所對應的值,就是我們要爬取的工作要求與工作職責:

點開Headers,獲取JSON文件的URL地址(Request URL),以及查詢參數:

JSON文件的URL地址:

https://careers.tencent.com/tencentcareer/api/post/ByPostId?timestamp=1587434334600&postId=1188745462794948608&language=zh-cn

查詢參數:

timestamp:1587434334600
postId:1188745462794948608
language:zh-cn

我們看到, 有個查詢參數叫postId,這個參數我們應該是需要的,關鍵是,我們如何獲取這個查詢參數值,或者找到這個查詢參數的規律呢?

不像之前遇到pageIndex查詢參數,我們一看就知道是表示頁數的,但是這個postId參數貌似沒啥規律可循啊…陷入僵局.JPG

這可咋整?

不要驚慌!這個值不可能憑空出現。此時,我們可以把之前獲取的新信息擼一遍,看一看有沒有這個查詢參數的線索。什麼新信息?哪來的新信息?有鴨,就是在1級頁面中抓取到的JSON文件

這時,我們可以回到1級頁面,看一看在1級頁面中抓取到的JSON文件裏,裏是否有關於這個查詢參數的線索:

{
Id: 0,
PostId: "1188745462794948608",
RecruitPostId: 54633,
RecruitPostName: "21557-音視頻流媒體傳輸算法工程師(深圳)",
CountryName: "中國",
LocationName: "深圳",
BGName: "CSIG",
ProductName: "騰訊雲",
CategoryName: "技術",
Responsibility: "負責實時音視頻通話、直播、視頻會議等場景的流媒體網絡傳輸算法的預研和開發,包括但不限於: 1.	負責流媒體傳輸中網絡狀態的實時檢測及算法選型和集成; 2.	負責損傷網絡下的網絡擁塞算法的研究和調優落地; 3.	負責受限網絡下多路流媒體的分佈式中轉算法設計和實現; 4.	負責流媒體傳輸中音視頻QOE/QOS的實現與調優。",
LastUpdateTime: "2020年04月21日",
PostURL: "http://careers.tencent.com/jobdesc.html?postId=1188745462794948608",
SourceID: 1,
IsCollect: false,
IsValid: true
},

有了!PostId: "1188745462794948608"和我們的postId查詢參數值一毛一樣!

所以,我們拿到1級頁面的JSON文件時,除了要獲取每一個職位的RecruitPostName,還需要獲取每一個職位的PostId


開始敲代碼吧


首先我們創建一個mysql數據表用於存儲數據:

CREATE TABLE tencent_career(id int NOT NULL AUTO_INCREMENT,
recruitpostname varchar(50) NOT NULL,
requirement varchar(500) NOT NULL,
responsibility varchar(500) NOT NULL,
PRIMARY KEY (id));

敲python代碼:

# -*- coding: utf-8 -*-

import requests
import json
import time
import random
import pymysql

class CareerSpider:
    
    def __init__(self):
        self.headers = self.headers = {'Accept':'application/json, text/javascript, */*; q=0.01',
                        'User-Agent':'Mozilla/5.0'}
        self.url01 = 'https://careers.tencent.com/tencentcareer/api/post/Query?countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword=&pageIndex={}&pageSize=10&language=zh-cn&area=cn'
        self.url02 = 'https://careers.tencent.com/tencentcareer/api/post/ByPostId?postId={}&language=zh-cn'
        self.db = pymysql.connect(host = '127.0.0.1',
                     port = 3306,
                     user = 'root',
                     password = '19970928',
                     database = 'datacup',
                     charset = 'utf8')
        self.cur = self.db.cursor()
    
    
    #請求函數
    def get_page(self, url):
        res = requests.get(url, headers=self.headers)
        #res.encoding = 'utf-8'
        #將得到的JSON類型的字符串,轉換成python數據類型
        print('status_code:', res.status_code)
        #print('url:', res.url)
        return json.loads(res.text)
    
    def get_data(self, json_dict):
        job_data = []
        job_list = json_dict['Data']['Posts']
        
        for item in job_list:
            recruitpostname = item['RecruitPostName']
            print(recruitpostname)
            postId = item['PostId']
            url02 = self.url02.format(postId)
            responsibility, requirement = self.get_data_two(url02)
            job_data.append([recruitpostname, requirement, responsibility])
        self.write_data(job_data)
            

    def get_data_two(self, url):
        json_dict = self.get_page(url)
        
        responsibility = json_dict['Data']['Responsibility']
        requirement = json_dict['Data']['Requirement']
        return (responsibility, requirement)
    
    def write_data(self, data_list):
        sql = 'insert into tencent_career(recruitpostname, requirement, responsibility) \
             values(%s, %s, %s);'
        try:
            
            self.cur.executemany(sql, data_list)
            self.db.commit()
        except Exception as e:
            self.db.rollback()
            print('錯誤信息:', e)
    
    def main(self):
        for index in range(1, 3):
            url01 = self.url01.format(index)
            one_json_dict = self.get_page(url01)
            self.get_data(one_json_dict)
            
            time.sleep(random.uniform(0.5,  1.5))
        self.cur.close()
        self.db.close()
            


if __name__ == '__main__':
    start = time.time()
    spider = CareerSpider()
    spider.main()
    end = time.time()
    print('執行時間:%.2f' % (end-start))  


控制檯部分輸出(共20條):

status_code: 200
32032-PC客戶端高級工程師(深圳)
status_code: 200
15573-天天愛消除動畫設計師(上海)
status_code: 200
執行時間:8.40

查詢mysql數據庫


我們先檢驗一下數據是否導入到tencent_career表裏:

SELECT * FROM tencent_career;

語句執行記錄:

11:33:17	SELECT * FROM tencent_career LIMIT 0, 1000	20 row(s) returned	0.000 sec / 0.000 sec

查詢的部分結果:

# id, recruitpostname, requirement, responsibility
'1', '35595-信息流內容策略高級產品經理', '1)三年及以上信息流內容推薦策略相關工作經驗;\n2)有數據分析、信息流推薦產品經驗者優先考慮;\n3)具有強推進能力,並有強烈的責任心和自驅力。 ', '1)對騰訊信息流產品大盤內容現狀進行分析,尋找在內容建設方向和推薦策略方向的優化空間; \n2)問題驅動進行內容和推薦全鏈路的分析、優化,包括內容建設、內容理解、用戶畫像等環節; \n3)分析挖掘不同用戶場景和不同用戶羣體的內容需求,建立可行的產品和內容策略並推動落地;\n4)負責跟蹤內容策略的數據效果並持續分析,爲大盤各核心指標的正向增長,提供內容側支持;\n5)定期對競品的內容策略進行測評,輸出有價值的內容策略優化方案和建議,並負責推動落地。\n'
'2', '30361-SLAM算法工程師', '1. 熟悉單目、雙目或深度的SLAM算法; \n2. 有較強的工程開發能力,能獨立完成算法移植和優化; \n3. 在SLAM或者計算機視覺方向發過高質量論文的優先; \n4. 熟悉Android/IOS 開發的優先。\n5. 具備良好的敬業精神和團隊合作精神,善於分析和解決問題,富有想象力和學習能力。', '1. 負責移動端增強現實引擎開發和優化 \n2. 負責SLAM前沿技術研發及相關產品實現 '

很好!20條職位信息都導入數據庫了。


這時,我想查看工作要求裏有"碩士"兩個字的職位信息:

SELECT * FROM tencent_career WHERE requirement REGEXP '碩士';

查詢的部分結果:

# id, recruitpostname, requirement, responsibility
'3', 'TEG16-高級祕書(深圳)', '碩士,英語能力強,有一定的海外工作經驗更佳;\n有3-7年大型企業相關助理工作經驗本科也可以考慮;\n有大型項目或活動組織經驗,溝通協調能力強;\n踏實、穩重,靈活,有服務意識及全局觀。', '爲GM提供高效專業的助理支持服務,協助高管進行各項日常工作管理,安排和落實高管參與的內外部各項會議、活動、差旅行程等;\n跟進領導交付的各項任務,保證事務的順利落實;\n在業務側協助高管推進業務或項目,配合協調與維護內外部公共關係;\n協助安排和組織高管團隊的各項會議、活動等;\n負責組織活動和文化落地,活躍部門組織氛圍;及系統級節慶、拓展活動組織;\n擔任部門內各項行政人事工作接口人,包括行政、人事、資產、費用、合同、文檔、資料管理等;\n部門財務預算制定管理工作;協助制定並實施部門的管理規章制度及各項流程;\n組織和維護所在祕書團隊的日常事務運作及大型項目活動。'
'11', 'WXG10-企業微信音視頻引擎開發(成都)', '音視頻相關專業碩士及以上學歷;\n熟悉c\\c++,熟悉網絡,精通信號處理相關知識,瞭解深度學習相關技能;\n有5年以上音視頻引擎優化的相關工作經驗;', '負責企業微信音頻或視頻功能的引擎研發工作;\n音頻方向主要爲負責語音編解碼性能優化,降噪rnn算法優化,語音fec優化,會議室回聲處理,語音網絡策略算法優化等算法工作;\n視頻方向主要爲負責H265的視頻會議算法優化,超分辨率算法優化,高清會議室視頻算法優化等工作;'

很好,查到了,貌似一個職位是高級祕書,一個職位是引擎開發。



後記:在寫這個案例的過程中,出現過兩次小意外。

第一個小意外:我一開始把由瀏覽器向服務端發送的請求頭信息,都寫在python程序裏了,結果導致由python程序訪問服務端出現404錯誤,後來我在python代碼中刪除了一些請求頭信息,只留下了User-Agent和Accept,程序就正常訪問了。

第二個小意外:最開始在創建mysql數據表時,我將requirement和responsibility字段設置爲varchar(200)結果報出錯誤信息"Data too long for column 'requirement' at row 8", 並且由於設置了回滾rollback,所以,報錯之前的職位信息全部都沒有存入數據庫,只有報錯後的職位信息存入了數據庫。後來,我設置varchar(500)就沒有出現該問題了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章