1. 程式人生 > >【python爬蟲實戰】使用Selenium webdriver採集山東招考資料

【python爬蟲實戰】使用Selenium webdriver採集山東招考資料

[toc] # 1、目標 - 目標:按地區、高校 採集2020年擬在山東招生的所有專業資訊 - 採集地址:http://xkkm.sdzk.cn/zy-manager-web/gxxx/selectAllDq# # 2、Selenium webdriver說明 ## 2.1 為什麼使用webdriver Selenium Webdriver是通過各種瀏覽器的驅動(web driver)來驅動瀏覽器的,相遇對於使用requests庫直接對網頁進行解析,效率較低,本次使用webdriver庫主要原因是requests庫無法解析該網站 ## 2.2 webdriver支援瀏覽器 - Google Chrome - Microsoft Internet Explorer 7,8,9,10,11 for Windows Vista,Windows 7,Windows 8,Windows 8.1. - Microsoft Edge - Firefox - Safari - Opera ## 2.3 配置與使用說明 webdriver是通過各瀏覽器的驅動程式 來操作瀏覽器的,所以,要有各瀏覽器的驅動程式,瀏覽器驅動要與本地瀏覽器版本對應,常用瀏覽器驅動下載地址如下: 瀏覽器 | 對應驅動下載地址 ---|--- chrom(chromedriver.exe) | http://npm.taobao.org/mirrors/chromedriver/ firefox(geckodriver.exe) | https://github.com/mozilla/geckodriver/releases Edge | https://developer.microsoft.com/en-us/micrsosft-edage/tools/webdriver Safari | https://webkit.org/blog/6900/webdriver-support-in-safari-10/ 本文使用谷歌的chrome瀏覽器, chrome + webdriver的具體配置和操作說明見 https://www.cnblogs.com/cbowen/p/13217857.html # 3、採集 ## 3.1 分析網站 - 進入網頁發現各省份地址相同、各高校地址相同,因此想按規律構造每個省份和每個學校的url,並用requests進行解析就無法實現了。 ![](https://img2020.cnblogs.com/blog/1845117/202007/1845117-20200702212612169-705511333.png) - 於是想到webdriver,來模擬人工操作,獲取當前頁面,再通過xpath定位到要獲取的資料單元。 先用chrome控制檯獲取目標資料單元的xpath ![](https://img2020.cnblogs.com/blog/1845117/202007/1845117-20200702212718203-1955614648.png) 通過手動調整xpath,很容易發現省份xpath的規律為 ``` for province_id in rang(1, 33) province_xpath = '//*[@id="div1"]/div/div[%s]/a' % province_id ``` ![](https://img2020.cnblogs.com/blog/1845117/202007/1845117-20200702212737408-357460455.png) 再用同樣方法獲取高校的xpat,這裡就不貼截圖了,直接上結果 ``` # sch_id為每個省份的高校id # schid_xpath,province_xpath,schcode_xpath,school_xpath,subpage_xpath,schhome_xpath分別對應欄位序號、地區、學校程式碼、學校名稱、選考科目要求、學校主頁 schid_xpath = '//*[@id="div4"]/table/tbody/tr[%s]/td[1]/a' % school_id province_xpath = '//*[@id="div4"]/table/tbody/tr[%s]/td[2]/a' % school_id schcode_xpath = '//*[@id="div4"]/table/tbody/tr[%s]/td[3]/a' % school_id school_xpath = '//*[@id="div4"]/table/tbody/tr[%s]/td[4]/a' % school_id subpage_xpath = '//*[@id="div4"]/table/tbody/tr[%s]/td[5]/a' % school_id schhome_xpath = '//*[@id="div4"]/table/tbody/tr[%s]/td[6]/a' % school_id ``` 再用同樣方法獲取專業資訊的xpat,直接上結果 ```py # major_id為每個高校專業序號,從1到最後一個專業序號 # i從1到4分別對應欄位“序號”、“層次”、“專業名稱”、“選考科目要求” for i in range(1, 5): major_xpath = '//*[@id="ccc"]/div/table/tbody/tr[%s]/td[%s]' % (major_id, i) ``` ## 3.2 遍歷省份 - 遍歷省份很簡單,一共32個省份,直接用rang(1,33),省去用try來判斷。 - 在函式外啟動瀏覽器,並傳入WebDriver類wd,所有省份遍歷完成後關閉瀏覽器 - 後面要將資料寫入mysql,所有傳入了完成資料庫連線的connect物件conn,並在全部資料寫入後關閉conn連線。 ``` def traverse_province(wd, conn): """ 迴圈進入省份 :return: """ for province_id in range(1, 33): province_xpath = '//*[@id="div1"]/div/div[%s]/a' % province_id wd.find_element_by_xpath(province_xpath).click() # 點選進入省份 time.sleep(1) traverse_school(wd, conn) # 遍歷省份內的高校 wd.quit() conn.close() ``` ## 3.3 遍歷高校 - 用while True迴圈來遍歷當前頁所有的高校,用try-except來判斷是否成功捕捉高校資訊,失敗則終端while True迴圈。 - 獲取高校基本資訊放列表school_info中,傳入下層函式用於冗餘儲存高校+專業 完整資料。 - 進入高校的子頁面後,需要重新定位當前操作頁面,wd.window_handles獲取當前瀏覽器所有子頁面控制代碼,wd.switch_to.window切換至指定頁面。 - 最內層函式traverse_major()會獲取專業資料,並將本層獲取的高校資料和專業資料寫入mysql。 - 在一個高校的全部專業資料寫入完成後,提交一次。 ``` def traverse_school(wd, conn): """ 遍歷高校資訊 :return: """ school_id = 1 while True: school_info = [] try: # 獲取高校資訊 for i in [1, 2, 3, 4, 6]: school_xpath = '//*[@id="div4"]/table/tbody/tr[%s]/td[%s]' % (school_id, i) text = wd.find_element_by_xpath(school_xpath).text school_info.append(text) # 進入高校子頁 wd.find_element_by_xpath('//*[@id="div4"]/table/tbody/tr[%s]/td[5]/a' % school_id).click() wd.switch_to.window(wd.window_handles[-1]) # 切換到最後一個頁面 traverse_major(school_info, wd, conn) # 遍歷專業 wd.close() # 關閉當前頁 wd.switch_to.window(wd.window_handles[-1]) # 重新定位一次頁面 school_id += 1 except: break conn.commit() # 每個高校份提交一次 ``` ## 3.4 採集專業資料 - 將專業資訊結合上層函式傳入的高校資訊冗餘儲存。 - 每個高校啟動一次遊標。 - 本函式內僅使操作遊標進行資料寫入,資料庫的連線在下面函式中,資料庫關閉在最外層函式中。 ``` def traverse_major(school_info, wd, conn): """ 遍歷專業資訊,最後結合高校資訊一併輸出 :param school_info: 上層函式傳遞進來的高校資訊 :return: """ major_id = 1 cursor = conn.cursor() while True: major_info = [] try: for i in range(1, 5): major_xpath = '//*[@id="ccc"]/div/table/tbody/tr[%s]/td[%s]' % (major_id, i) text = wd.find_element_by_xpath(major_xpath).text major_info.append(text) print(school_info + major_info) # 寫入mysql insert_sql = ''' insert into sdzk_data (school_id,province,school_code,school_name,school_home,major_id,cc,major_name,subject_ask) values('%s','%s','%s','%s','%s','%s','%s','%s','%s') ''' % (school_info[0], school_info[1], school_info[2], school_info[3], school_info[4], major_info[0], major_info[1], major_info[2], major_info[3]) cursor.execute(insert_sql) major_id += 1 except: break cursor.close() # 每個高校都重新開啟一次遊標 ``` ## 3.5 寫入mysql - 該函式僅用於建立mysql連線,並建立表。 - 判斷表是否存在,存在則先刪除再建立。 - 函式返回connect類,用於其他函式使用。 - 關閉連線在最外層函式中,直到所有省份資料採集結束後才關閉連線。 ``` def connect_mysql(config): """ 連線資料庫,並建立表,如果表已存在則先刪除 :param config: mysql資料庫資訊 :return: 返回連線成功的connect物件 """ create_sql = ''' CREATE table if NOT EXISTS sdzk_data (school_id int(3),province varchar(20), school_code varchar(5), school_name varchar(50), school_home varchar(100), major_id int(3), cc varchar(5), major_name varchar(100), subject_ask varchar(50)) ''' # 判斷表是否存在,存在則刪除,然後建立 conn = pymysql.connect(**config) cursor = conn.cursor() cursor.execute('''show TABLEs like "sdzk_data"''') if cursor.fetchall(): cursor.execute('''drop table sdzk_data''') cursor.execute(create_sql) cursor.close() return conn ``` # 4、原始碼 原始碼地址:https://github.com/18686622933/s