使用selenium爬取智联招聘
我是一名在校大學生,這是第一次寫博客,希望記錄一下自己的學習過程,然后如果哪里做的不好打擾或者影響到您,可以聯系我修改、刪除。
哇,……弄了好久才明白咋回事。我想開頭空兩格寫,然后發現空兩格之后他就不會自動換行了,找了半天才發現原來不空兩格就好了…………賊丟人(還是得多讀書啊……)。言歸正傳,寫這個博客,我主要是想記錄一下自己的學習過程,同時如果有哪位兄弟姐妹看到了我踩的坑可以吸取教訓的話,我也會非常的欣慰!!
一.主要目的:
最近在學習python網絡爬蟲,然后學到了selenium模塊,然后就想主要用這個模塊來爬去一下智聯招聘網站。
二.前期準備:
這里我用的是windows7系統,使用的是anaconda中的環境(我平時比較懶,然后感覺anaconda包比較多,而且可視化界面也是非常舒服)
我希望模擬的是火狐瀏覽器,然后需要下載一個驅動:GeckoDriver(下載地址:https://github.com/mozilla/geckodriver/releases),然后這里的話如果希望用著方便可以直接把下載好的驅動直接放到Python的Scripts目錄下,另外還可以有另一種方法,也是我這里用到的,定義一個driver_path變量。這里我是看的崔慶才大神所著的《Python3網絡開發實戰教程》。程序中我用到的模塊:
三.思路分析:
1.在看了網站主頁之后我決定從城市開始爬,從主頁獲取每個城市的頁面鏈接,這個不難,直接使用selenium中的source_page獲取(這里獲取的直接是右鍵檢查元素中的內容,不需要再打開源代碼找了),因為我對xpath比較熟悉,所以習慣用xpath提取,另外這樣速度好像也會更快些。我這里是定義了一個類,然后類里面有好多函數。
self.url = 'https://www.zhaopin.com/'self.wait = WebDriverWait(self.browser, 5)def run(self):self.browser.get(self.url)time.sleep(65)#讓我登陸一下self.browser.close()#因為登陸以后會有新的頁面跳出self.browser.switch_to.window(self.browser.window_handles[0])source = self.browser.page_source#因為網速原因有時候彈出框出的慢# 因為會有彈出框# know_btn = self.wait.until(EC.element_to_be_clickable((By.XPATH, '/html/body/div[5]/div/div/button'))) # 按鈕必須這樣真TMD坑# know_btn.click()time.sleep(1)#感覺可刪,不過影響不大htmlElement = etree.HTML(source)# 獲取后面每個城市的網頁鏈接city_links_all = htmlElement.xpath('//div[@id="footer"]//li//a/@href')# 獲取城市名city_names_all = htmlElement.xpath('//div[@id="footer"]//li//a/text()')2.進到某個誠實頁面之后會出現一些職位分類,按照大方向分為:
到這里之后可以發現內部這些大方向內部還有具體的小方向:
所以我希望可以為每個城市建立一個文件夾,在城市文件夾內部,按照每個城市的招聘信息中每個大方向分別創建自己的文件夾,最后在大方向文件夾內部每一個小方向是一個CSV文件。因為我只需要每個省會城市的信息(主要是都爬時間太長……),所以多加了一步。
對了上面這個圖里面小方向好像是在JS中,然后他也不是按鈕也沒法用click()點擊,這點我很困惑,最終也沒解決!!
我用的方法是,這一頁上面有一個輸入框可以查詢具體方向的招聘信息,我通過控制瀏覽器然后模擬輸入,點擊按鈕進行查詢的方式進入到招聘信息頁面
city_links = []city_names = ['北京', '上海', '天津', '重慶', '哈爾濱', '銀川', '鄭州', '濟南', '太原', '合肥', '長春', '沈陽', '呼和浩特', '石家莊', '烏魯木齊','蘭州', '西寧', '西安', '張家界', '武漢', '南京', '成都', '貴陽', '昆明', '南寧', '西藏', '杭州', '南昌', '廣州', '福州', '海口']for i in range(len(city_names)):city_links.append("")print(len(city_links))for i in range(len(city_names_all)):for index, city_name in enumerate(city_names):if city_names_all[i] == city_name:city_links[index] = city_links_all[i]print(city_names,city_links)print("一共要爬"+str(len(city_names))+"個城市")for i in range(len(city_names)):print('正在獲取'+ city_names[i]+'的信息,該城市鏈接為'+city_links[i])time.sleep(1)#爬每一個城市前停一下city_directory = city_names[i]#城市名即為目錄名if not os.path.exists(city_directory):os.mkdir(city_directory)#創建每個城市的目錄try:self.request_city(city_links[i],city_names[i])print(city_names[i] + '所有崗位已經爬取完畢')print('=' * 40)except Exception as e:print(e)print("城市頁面加載出問題")# time.sleep(1)#認為可刪print('='*40)self.browser.close()self.browser.switch_to.window(self.browser.window_handles[0]) # 這里爬完一整個城市,然后要關掉窗口def request_city(self,url,city):first_second_positions = {}url = "https:"+urlself.browser.execute_script("window.open()")self.browser.switch_to.window(self.browser.window_handles[1])#把當前控制頁面切換到新一頁try:self.browser.get(url)city_source = self.browser.page_sourcehtmlElement = etree.HTML(city_source)category_first_positions = htmlElement.xpath('//*[@id="root"]/div[3]/div/div[1]/ol/li/div[1]/text()')#大方向,比如IT,金融for index,category_first_position in enumerate(category_first_positions):category_second_positions = htmlElement.xpath('//*[@id="root"]/div[3]/div/div[1]/ol/li['+str(index+1)+']/div[2]/div/div/a//text()')######################################還是有問題#//*[@id="root"]/div[3]/div[2]/div[1]/ol/li[1]/div[2]/div/div//text()first_second_positions[category_first_position] = category_second_positionsprint(first_second_positions)# category_second_positions = htmlElement.xpath('//*[@id="root"]/div[3]/div/div[1]/ol/li[1]/div[2]/div/div[2]//text()')#小方向,比如JAVA,PYTHON# print(category_first_positions)# print(category_second_positions)# # print(category_first_positions,category_second_positions)# time.sleep(1)for key,value in first_second_positions.items():if not os.path.exists(city+'/'+key):key = re.sub(r'/', '', key)if not os.path.exists(city+'/'+key):os.mkdir(city+'/'+key)for i in value:#這里的i就是每一個小方向,例如互聯網IT下的pythonroad = city+'/'+key+'/'+iif not os.path.exists(road+".csv"):# second_url = 'https://sou.zhaopin.com/?jl=601&kw='+i+'&kt=3'print('現在正在爬取'+city+"市"+key+"行業,"+i+'崗位')input = self.browser.find_element_by_xpath("/html/body/div[1]/div[1]/div/div[2]/div/div/div[2]/div/div/input")js = 'document.querySelector(".zp-search__input").value="";'self.browser.execute_script(js)#NB#input.clear() ########忘了后果很嚴重,TMD這里這個失效了,上網找了個大神的方法input.send_keys(i)button = self.browser.find_element_by_xpath('//*[@id="root"]/div[1]/div/div[2]/div/div/div[2]/div/div/a')button.click()try:self.parse_second_position(road)print(city + "市" + key + "行業," + i + '崗位,爬取完成')except Exception as e:print(e)print(city + "市" + key + "行業," + i + "崗位頁面加載出問題,城市頁面沒問題")print('='*30)# time.sleep(1)去掉或許可以提速self.browser.close()self.browser.switch_to.window(self.browser.window_handles[1])#time.sleep(1)# time.sleep(1)#self.browser.close()#某市某行業下的小方向爬完之后,關閉網頁# print(city+"市"+category_first_position+"行業,"+category_second_position+'崗位已爬取成功')# self.browser.close()#關閉該城市爬完的崗位# self.browser.switch_to.window(self.browser.window_handles[0])# time.sleep(1)繼續提速except Exception as e:print(city+"城市頁面出問題")#查看該城市所有的招聘信息# bt = self.browser.find_element_by_class_name('jobs-hot__button--more')# bt.click()# time.sleep(3)# self.browser.close()# self.browser.switch_to.window(self.browser.window_handles[2])# print(self.browser.current_url)# time.sleep(10)# self.browser.quit()這個代碼是我改了好多遍的,但是為了提醒自己,我修改的時候只是給我覺得不合適的代碼變成了注釋。然后一開始沒有加異常處理(主要原因是自己不太會,但是這個程序總是被錯誤中斷,我就加了個異常處理)這里創建文件夾之前先判斷是否存在,也是為了一次沒爬完下次接著爬…………
3.然后就到了某個城市某個大方向下某個小方向中的每一條具體招聘信息的頁面,我用的方法是,這一頁上面有一個輸入框可以查詢具體方向的招聘信息,我通過控制瀏覽器然后模擬輸入,點擊按鈕進行查詢的方式進入到招聘信息頁面
def parse_second_position(self,road):try:#i = 1#記錄當前在爬的頁數second_position_informations = []#self.browser.execute_script("window.open()")#self.browser.switch_to.window(self.browser.window_handles[2])self.browser.switch_to.window(self.browser.window_handles[2])# self.browser.get(url)# print(self.browser.current_url)second_position_page_source = self.browser.page_sourcehtmlElement = etree.HTML(second_position_page_source)element_judges = self.wait.until(EC.presence_of_all_elements_located((By.XPATH, '//*[@id="listItemPile"]/div[3]/div/div')))#這里是判斷某地區的某行業中的某個小方向是否有招聘信息# print(element_judges)# print(element_judges[0].text)judge = re.sub(r"[\s]","",element_judges[0].text)#這里是要去掉找不到那個中間的換行# print(judge)#判斷是否有信息if judge != "很抱歉,您搜索的職位找不到!換個條件試試吧":#print("現在在爬"+road+"第"+str(i)+"頁")element_as = self.wait.until(EC.presence_of_all_elements_located((By.XPATH, '//*[@id="listContent"]/div/div/a'))) # 這里得到的是元素a,列表。這里是為了防止網速慢,未加載出來###########!!!!!!!這里面收到的錯誤類型不知道算什么.用TimeError,收不到這個錯誤類型 #for element_a in element_as:# print(element_a.get_attribute('href'))#具體職位的詳情頁面URLlink = element_a.get_attribute('href')try:second_position_informations.append(self.parse_detail_position(link))print("收到請求數據")except Exception as e:print(e, "詳情函數出問題")print()print()self.browser.close()self.browser.switch_to.window(self.browser.window_handles[2])####這個翻頁我整不成,不弄了,單獨調試沒有一點問題 # next_btn = self.wait.until(EC.presence_of_all_elements_located( # (By.XPATH, '//*[@id="pagination_content"]/div/button[2]'))) # # print() # #這里是判斷是否有翻頁 # print("判斷是否有下一頁") # print(type(next_btn)) # if len(htmlElement.xpath('//*[@id="pagination_content"]/div/button[2]/@disabled'))!=0: # break # else: # next_btn[0].click() # i = i+1 # print("已點擊翻頁按鈕") #個人一些見解:如果try內部有函數,函數內發生異常(即使內部函數中也有try except依舊會出現觸發外部的try except)如果是try except嵌套try except那么如果內層出現的錯誤符合內層的except則不會觸發外部的except#此處應該拉到前面,這樣如果IF成立,也會建立文件''' !!!!!!!!!!!!!!!!!!!!!!!!!!!此處有修改 '''with open(road + '.csv', 'a', encoding='utf-8', errors='ignore') as fp:print("開始寫入數據")fieldnames = ['職位名稱', '工資', '城市', '工作經驗', '教育背景', '人數需求', '職位亮點', '職位描述', '工作地點']writer = csv.DictWriter(fp, lineterminator='\n', fieldnames=fieldnames)writer.writeheader()for row in second_position_informations:try:writer.writerow(row)except UnicodeEncodeError as e:print(e)print("數據寫入完成")print()except Exception as e:print("大概率是second職位頁面未加載出來頁面")print(e)這個頁面上有的小方向中的招聘信息是有分頁的,然后我看了一下這個‘下一頁’按鈕如果有disabled屬性則證明已經到了最后一頁,我想用這個進行判斷,單獨在一個文件中試我確實成功了,但是整個代碼一運行,這里總是出問題,最后我就放棄了…………如果有大神可以指導的話真的很感謝。然后我這個寫入CSV文件的時候我也是采取了只要爬到數據就寫入,也就是說如果我這個程序爬一個小方向中的具體招聘信息時出現異常,那么下一次我再重新爬的時候,他會檢測到已經有該CSV文件了,就不會再解決有出現異常的那個數據(因為能力有限,確實只能做到這了)
4.進入到招聘信息的詳情頁面,我把這些數據存成字典形式
def parse_detail_position(self,url):#print(url)print('爬取中…………')position_information = {}self.browser.execute_script("window.open()")self.browser.switch_to.window(self.browser.window_handles[3])try:self.browser.get(url)#因為這里有可能請求不到頁面# source = self.browser.page_source# htmlElement = etree.HTML(source)# print(htmlElement)print("等待加載")self.wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="root"]/div[3]/div/div/h3')))# page_htmlElement = page_htmlElement.xpath('//*[@id="root"]')[0]#因為返回的是列表!!!!!!# print(len(page_htmlElement))print("加載完畢")source = self.browser.page_sourcehtmlElement = etree.HTML(source)if len(htmlElement.xpath('//*[@id="root"]/div[3]/div/div/h3/text()'))!=0:position_name = htmlElement.xpath('//*[@id="root"]/div[3]/div/div/h3/text()')[0]else:position_name = '無'# print(position_name)position_information['職位名稱'] = position_nameif len(htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/span/text()'))!=0:salary = htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/span/text()')[0]else:salary="無"position_information['工資'] = salaryif len(htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[1]//text()'))!=0:position_city = htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[1]//text()')[0]else:posirion_city = "無"position_information['城市'] = position_cityif len(htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[2]//text()'))!=0:work_years = htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[2]//text()')[0]else:work_years = "無"position_information['工作經驗'] = work_yearsif len(htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[3]//text()'))!=0:education_background = htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[3]//text()')[0]else:education_background = "無"position_information['教育背景'] = education_backgroundif len(htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[4]//text()'))!=0:num_demanded = htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[4]//text()')[0]else:num_demanded = "無"position_information['人數需求'] = num_demandedif len(htmlElement.xpath('//*[@id="root"]/div[4]/div[1]/div[1]/div[1]/div//text()'))!=0:position_advantages = htmlElement.xpath('//*[@id="root"]/div[4]/div[1]/div[1]/div[1]/div//text()')position_advantages = ",".join(position_advantages)else:position_advantages = "無"position_information['職位亮點'] = position_advantagesif len(htmlElement.xpath('/html/body/div[1]/div[4]/div[1]/div[1]/div[2]/div//text()'))!=0:position_desc = htmlElement.xpath('/html/body/div[1]/div[4]/div[1]/div[1]/div[2]/div//text()')position_desc = " ".join(position_desc)else:position_desc = "無"position_information['職位描述'] = position_descif len(htmlElement.xpath('/html/body/div[1]/div[4]/div[1]/div[1]/div[3]/div/span/text()'))!=0:work_address = htmlElement.xpath('/html/body/div[1]/div[4]/div[1]/div[1]/div[3]/div/span/text()')[0]else:work_address = "無"position_information['工作地點'] = work_addressexcept Exception as e:print(e)print("詳情頁面404或者加載太慢")print("爬取成功并返回結果!")return position_information爬取詳情頁的時候,爬完以后返回的是字典,因為這樣好寫到CSV中。這樣的話就完事了。還有一點就是算是我的一點教訓吧,就是我覺得像我這個代碼模擬瀏覽器的時候需要進行頁面的關閉和切換,我覺得都放在固定的位置比較好。比如說都放在內部函數中,或者內部函數外,這樣比較好檢查代碼。我剛開始位置就不固定,給自己整蒙了。
四.源代碼:
我的代碼都會加注釋的,是我從第一遍運行到最后完成所有的改動都保留了,可能看起來會比較難受…………
from selenium import webdriver from lxml import etree import os import time from selenium .webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By from selenium.common.exceptions import TimeoutException import re import csv import sys class ZLspider():driver_path = r'E:\python_tools\geckodriver-v0.26.0-win64\geckodriver.exe'option = webdriver.FirefoxOptions()#option.add_argument('-headless')#這個是加無頭模式# option.set_preference('permissions.default.image', 2)#不讓加載圖片為了提速# option.set_preference('permissions.default.stylesheet', 2)#不讓加載CSSdef __init__(self,file):self.browser = webdriver.Firefox(executable_path=ZLspider.driver_path,options=ZLspider.option)self.url = 'https://www.zhaopin.com/'self.wait = WebDriverWait(self.browser, 5)self.out_file = fileself.to_console = sys.stdoutdef write_console(self,*args):sys.stdout = self.to_consolefor arg in args:print(arg)def write_file(self,*args):# sys.stdout = open(self.out_file,'a',encoding='utf-8')# for arg in args:# print(arg)passdef run(self):self.browser.get(self.url)# time.sleep(65)#讓我登陸一下# self.browser.close()#因為登陸以后會有新的頁面跳出# self.browser.switch_to.window(self.browser.window_handles[0])source = self.browser.page_source#因為網速原因有時候彈出框出的慢# 因為會有彈出框know_btn = self.wait.until(EC.element_to_be_clickable((By.XPATH, '/html/body/div[5]/div/div/button'))) # 按鈕必須這樣真TMD坑know_btn.click()# time.sleep(1)#感覺可刪,不過影響不大htmlElement = etree.HTML(source)# 獲取后面每個城市的網頁鏈接city_links_all = htmlElement.xpath('//div[@id="footer"]//li//a/@href')# 獲取城市名city_names_all = htmlElement.xpath('//div[@id="footer"]//li//a/text()')#####這里驗一下是不是頁面有問題 #############################這里有問題,揚州的提取方式和其他的不一樣,位置放的不一樣,fuck!# print(city_links_all)# print(city_names_all)# for i in range(len(city_links_all)):# print(city_links_all[i],city_names_all[i])city_links = []city_names = ['北京', '上海', '天津', '重慶', '哈爾濱', '銀川', '鄭州', '濟南', '太原', '合肥', '長春', '沈陽', '呼和浩特', '石家莊', '烏魯木齊','蘭州', '西寧', '西安', '張家界', '武漢', '南京', '成都', '貴陽', '昆明', '南寧', '西藏', '杭州', '南昌', '廣州', '福州', '海口']for i in range(len(city_names)):city_links.append("")self.write_console(len(city_links))self.write_file(len(city_links))for i in range(len(city_names_all)):for index, city_name in enumerate(city_names):if city_names_all[i] == city_name:city_links[index] = city_links_all[i]self.write_console(city_names[index],city_links[index])self.write_file(city_names[index],city_links[index])# print(city_names)###有幾個城市名稱和鏈接對不上# print(city_links)self.write_console("一共要爬"+str(len(city_names))+"個城市")self.write_file("一共要爬"+str(len(city_names))+"個城市")for i in range(len(city_names)):self.write_console('正在獲取'+ city_names[i]+'的信息,該城市鏈接為'+city_links[i])self.write_file('正在獲取'+ city_names[i]+'的信息,該城市鏈接為'+city_links[i])time.sleep(1)#爬每一個城市前停一下city_directory = city_names[i]#城市名即為目錄名if not os.path.exists(city_directory):os.mkdir(city_directory)#創建每個城市的目錄#這個異常處理有意義嗎?self.request_city(city_links[i],city_names[i])self.write_console(city_names[i] + '所有崗位已經爬取完畢')self.write_file(city_names[i] + '所有崗位已經爬取完畢')self.write_console('=' * 40)self.write_file('=' * 40)time.sleep(1)#認為可刪self.browser.close()self.browser.switch_to.window(self.browser.window_handles[0]) # 這里爬完一整個城市,然后要關掉窗口def request_city(self,url,city):first_second_positions = {}url = "https:"+urlself.browser.execute_script("window.open()")self.browser.switch_to.window(self.browser.window_handles[1])#把當前控制頁面切換到新一頁try:self.browser.get(url)city_source = self.browser.page_sourcehtmlElement = etree.HTML(city_source)category_first_positions = htmlElement.xpath('//*[@id="root"]/div[3]/div/div[1]/ol/li/div[1]/text()')#大方向,比如IT,金融for index,category_first_position in enumerate(category_first_positions):category_second_positions = htmlElement.xpath('//*[@id="root"]/div[3]/div/div[1]/ol/li['+str(index+1)+']/div[2]/div/div/a//text()')######################################還是有問題#//*[@id="root"]/div[3]/div[2]/div[1]/ol/li[1]/div[2]/div/div//text()first_second_positions[category_first_position] = category_second_positionsself.write_console(first_second_positions)self.write_file(first_second_positions)# category_second_positions = htmlElement.xpath('//*[@id="root"]/div[3]/div/div[1]/ol/li[1]/div[2]/div/div[2]//text()')#小方向,比如JAVA,PYTHON# print(category_first_positions)# print(category_second_positions)# # print(category_first_positions,category_second_positions)# time.sleep(1)for key,value in first_second_positions.items():if not os.path.exists(city+'/'+key):key = re.sub(r'/', '', key)if not os.path.exists(city+'/'+key):os.mkdir(city+'/'+key)for i in value:#這里的i就是每一個小方向,例如互聯網IT下的pythonroad = city+'/'+key+'/'+iif not os.path.exists(road+".csv"):# second_url = 'https://sou.zhaopin.com/?jl=601&kw='+i+'&kt=3'input = self.browser.find_element_by_xpath("/html/body/div[1]/div[1]/div/div[2]/div/div/div[2]/div/div/input")js = 'document.querySelector(".zp-search__input").value="";'self.browser.execute_script(js)#NB#input.clear() ########忘了后果很嚴重,TMD這里這個失效了,上網找了個大神的方法input.send_keys(i)button = self.browser.find_element_by_xpath('//*[@id="root"]/div[1]/div/div[2]/div/div/div[2]/div/div/a')button.click()# try:self.write_console('現在正在爬取' + city + "市" + key + "行業," + i + '崗位')self.write_file('現在正在爬取' + city + "市" + key + "行業," + i + '崗位')self.parse_second_position(road)self.write_console(city + "市" + key + "行業," + i + '崗位,爬取完成')self.write_file(city + "市" + key + "行業," + i + '崗位,爬取完成')# except Exception as e:# print(e)# print(city + "市" + key + "行業," + i + "崗位頁面加載出問題,城市頁面沒問題")self.write_console('='*30)self.write_file('='*30)# time.sleep(1)去掉或許可以提速self.browser.close()self.browser.switch_to.window(self.browser.window_handles[1])#time.sleep(1)# time.sleep(1)#self.browser.close()#某市某行業下的小方向爬完之后,關閉網頁# print(city+"市"+category_first_position+"行業,"+category_second_position+'崗位已爬取成功')# self.browser.close()#關閉該城市爬完的崗位# self.browser.switch_to.window(self.browser.window_handles[0])# time.sleep(1)繼續提速except Exception as e:self.write_console(e)self.write_file(e)self.write_console(city+"城市頁面出問題")self.write_file(city+"城市頁面出問題")#查看該城市所有的招聘信息# bt = self.browser.find_element_by_class_name('jobs-hot__button--more')# bt.click()# time.sleep(3)# self.browser.close()# self.browser.switch_to.window(self.browser.window_handles[2])# print(self.browser.current_url)# time.sleep(10)# self.browser.quit()def parse_second_position(self,road):try:#i = 1#記錄當前在爬的頁數second_position_informations = []#self.browser.execute_script("window.open()")#self.browser.switch_to.window(self.browser.window_handles[2])self.browser.switch_to.window(self.browser.window_handles[2])# self.browser.get(url)# print(self.browser.current_url)second_position_page_source = self.browser.page_sourcehtmlElement = etree.HTML(second_position_page_source)element_judges = self.wait.until(EC.presence_of_all_elements_located((By.XPATH, '//*[@id="listItemPile"]/div[3]/div/div')))#這里是判斷某地區的某行業中的某個小方向是否有招聘信息# print(element_judges)# print(element_judges[0].text)judge = re.sub(r"[\s]","",element_judges[0].text)#這里是要去掉找不到那個中間的換行# print(judge)#判斷是否有信息if judge != "很抱歉,您搜索的職位找不到!換個條件試試吧":#print("現在在爬"+road+"第"+str(i)+"頁")element_as = self.wait.until(EC.presence_of_all_elements_located((By.XPATH, '//*[@id="listContent"]/div/div/a'))) # 這里得到的是元素a,列表。這里是為了防止網速慢,未加載出來###########!!!!!!!這里面收到的錯誤類型不知道算什么.用TimeError,收不到這個錯誤類型 #for element_a in element_as:# print(element_a.get_attribute('href'))#具體職位的詳情頁面URLlink = element_a.get_attribute('href')detail_information = self.parse_detail_position(link)self.write_console(detail_information)self.write_file(detail_information)if detail_information:second_position_informations.append(detail_information)self.write_console("收到請求數據,并加入列表")self.write_file("收到請求數據,并加入列表")else:self.write_console("請求數據為空")self.write_file("請求數據為空")self.write_file()self.write_console()self.browser.close()self.browser.switch_to.window(self.browser.window_handles[2])if len(second_position_informations)!=0:####這個翻頁我整不成,不弄了,單獨調試沒有一點問題 # next_btn = self.wait.until(EC.presence_of_all_elements_located( # (By.XPATH, '//*[@id="pagination_content"]/div/button[2]'))) # # print() # #這里是判斷是否有翻頁 # print("判斷是否有下一頁") # print(type(next_btn)) # if len(htmlElement.xpath('//*[@id="pagination_content"]/div/button[2]/@disabled'))!=0: # break # else: # next_btn[0].click() # i = i+1 # print("已點擊翻頁按鈕") #個人一些見解:如果try內部有函數,函數內發生異常(即使內部函數中也有try except依舊會出現觸發外部的try except)如果是try except嵌套try except那么如果內層出現的錯誤符合內層的except則不會觸發外部的except#此處應該拉到前面,這樣如果IF成立,也會建立文件with open(road + '.csv', 'a', encoding='utf-8', errors='ignore') as fp:self.write_console("開始寫入數據")self.write_file("開始寫入數據")fieldnames = ['職位名稱', '工資', '城市', '工作經驗', '教育背景', '人數需求', '職位亮點', '職位描述', '工作地點']writer = csv.DictWriter(fp, lineterminator='\n', fieldnames=fieldnames)writer.writeheader()for row in second_position_informations:try:writer.writerow(row)except UnicodeEncodeError:self.write_console("寫入文件時,出現編碼問題")self.write_file("寫入文件時,出現編碼問題")self.write_console("數據寫入完成")self.write_file("數據寫入完成")self.write_console()self.write_file()else:with open(road + '.csv', 'a', encoding='utf-8', errors='ignore') as fp:self.write_console("開始寫入數據")self.write_file("開始寫入數據")fieldnames = ['職位名稱', '工資', '城市', '工作經驗', '教育背景', '人數需求', '職位亮點', '職位描述', '工作地點']writer = csv.DictWriter(fp, lineterminator='\n', fieldnames=fieldnames)writer.writeheader()except TimeoutException as e:self.write_console("招聘信息未加載出來")self.write_file("招聘信息未加載出來")self.write_console(e)self.write_file()except BaseException as e:self.write_file(e)self.write_console(e)# time.sleep(3)#為了防止網速慢導致加載不出來# detail_position_page_urls = htmlElement.xpath('//*[@id="listContent"]/div/div/a/@href')# print(detail_position_page_urls)# detail_position_page_urls =# print(detail_position_page_urls)# for element_a in element_as:# print(element_a.get_attribute('href'))# self.parse_detail_position(element_a.get_attribute('href'))# break# for detail_position_page_url in detail_position_page_urls:# self.parse.detail_position(detail_position_page_url)# judge_next = htmlElement.xpath('/html/body/div[1]/div[1]/div[4]/div[3]/div[3]/div/div[11]/div/div[2]/div/button[2]/@disabled')# print(judge_next)#//*[@id="pagination_content"]/div/button[2]/@disabled# if judge_next[0] == "disabled":# break# else:# next_btn = self.wait.until(# EC.element_to_be_clickable((By.XPATH, '/html/body/div[5]/div/div/button'))) # 按鈕必須這樣真TMD坑# next_btn.click()###############################################!!!!!!!!!!!!!!!!!!!!##好像是如果try中調用函數,然后這個函數中也有try,然后函數中發生異常,那么外層的也會發生異常# print("出來for循環")##此處有沒有方法打開文件,然后再文件中調函數,然后在內函數中寫文件def parse_detail_position(self,url):#print(url)self.write_console('爬取中…………')self.write_file('爬取中…………')position_information = {}self.browser.execute_script("window.open()")self.browser.switch_to.window(self.browser.window_handles[3])try:self.browser.get(url)#因為這里有可能請求不到頁面# source = self.browser.page_source# htmlElement = etree.HTML(source)# print(htmlElement)self.write_console("等待加載")self.write_file("等待加載")self.wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="root"]/div[3]/div/div/h3')))# page_htmlElement = page_htmlElement.xpath('//*[@id="root"]')[0]#因為返回的是列表!!!!!!# print(len(page_htmlElement))self.write_file("加載完畢")self.write_console("加載完畢")source = self.browser.page_sourcehtmlElement = etree.HTML(source)if len(htmlElement.xpath('//*[@id="root"]/div[3]/div/div/h3/text()'))!=0:position_name = htmlElement.xpath('//*[@id="root"]/div[3]/div/div/h3/text()')[0]else:position_name = '無'# print(position_name)position_information['職位名稱'] = position_nameif len(htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/span/text()'))!=0:salary = htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/span/text()')[0]else:salary="無"position_information['工資'] = salaryif len(htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[1]//text()'))!=0:position_city = htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[1]//text()')[0]else:posirion_city = "無"position_information['城市'] = position_cityif len(htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[2]//text()'))!=0:work_years = htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[2]//text()')[0]else:work_years = "無"position_information['工作經驗'] = work_yearsif len(htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[3]//text()'))!=0:education_background = htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[3]//text()')[0]else:education_background = "無"position_information['教育背景'] = education_backgroundif len(htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[4]//text()'))!=0:num_demanded = htmlElement.xpath('//*[@id="root"]/div[3]/div/div/div[2]/div[1]/ul/li[4]//text()')[0]else:num_demanded = "無"position_information['人數需求'] = num_demandedif len(htmlElement.xpath('//*[@id="root"]/div[4]/div[1]/div[1]/div[1]/div//text()'))!=0:position_advantages = htmlElement.xpath('//*[@id="root"]/div[4]/div[1]/div[1]/div[1]/div//text()')position_advantages = ",".join(position_advantages)else:position_advantages = "無"position_information['職位亮點'] = position_advantagesif len(htmlElement.xpath('/html/body/div[1]/div[4]/div[1]/div[1]/div[2]/div//text()'))!=0:position_desc = htmlElement.xpath('/html/body/div[1]/div[4]/div[1]/div[1]/div[2]/div//text()')position_desc = " ".join(position_desc)else:position_desc = "無"position_information['職位描述'] = position_descif len(htmlElement.xpath('/html/body/div[1]/div[4]/div[1]/div[1]/div[3]/div/span/text()'))!=0:work_address = htmlElement.xpath('/html/body/div[1]/div[4]/div[1]/div[1]/div[3]/div/span/text()')[0]else:work_address = "無"position_information['工作地點'] = work_addressself.write_console("詳情頁爬取成功")self.write_file("詳情頁爬取成功")self.write_console(position_information)self.write_file(position_information)return position_informationexcept TimeoutException as e:self.write_console("詳情頁面404或者加載太慢")self.write_file("詳情頁面404或者加載太慢")except BaseException as e:self.write_console("詳情頁面出現非超時異常")self.write_file("詳情頁面出現非超時異常")self.write_console(e)self.write_file(e)self.write_console("詳情頁爬取結束并返回結果!")self.write_file("詳情頁爬取結束并返回結果!")#####感覺這里應該修改一下,因為如果頁面沒加載出來,就會返回一個空值,這樣列表會嵌套空字典if __name__ == "__main__":spider = ZLspider("01.txt")spider.run()五.遺留問題:
1.某個城市頁面中的我想進入招聘信息頁面,也就是某個大方向下某個小方向中的招聘信息,可不可以采取獲取鏈接或者是點擊的方式?
2.某城市的某個大方向下某個小方向中的招聘信息翻頁問題。
3.能不能在對速度影響不大的情況下讓程序每次執行的時候可以精確的查看某一條招聘信息是否在CSV中,這樣可以讓損失更小。
六.代碼參考:
設置不加載CSS和圖片,以及設置成headless參考鏈接:https://blog.csdn.net/formatfa/article/details/88680303
看了比較多的崔慶才大神寫的《Python3網絡爬蟲開發實戰》
可能還有,但是忘記了收藏博客,下次我會更加注意!
七.總結:
我個人認為智聯的反爬可能算是比較友好的,我一開始比較擔心封我的IP但是最后也沒出問題。這個方法的話,反正是挺慢的,估計我要完成我的計劃可能要一天一夜吧。還有就是感覺這個selenium方式受網速影響比較大,等待時間設置太長吧,會影響程序速度,但是太短吧又會損失數據,很糾結,我選擇了要速度…………
我知道自己還有很多不足,希望可以得到大家的指導!然后如果文章中哪里影響到您,可以聯系我,我修改或者刪除文章。
總結
以上是生活随笔為你收集整理的使用selenium爬取智联招聘的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: The request was reje
- 下一篇: html页面计算圆的周长和面积,计算圆的