這篇文章給大家分享的是用selenium工具抓取網(wǎng)站數(shù)據(jù)的方法,相信大部分人都還沒學(xué)會(huì)這個(gè)技能,為了讓大家學(xué)會(huì),給大家總結(jié)了以下內(nèi)容,話不多說,一起往下看吧。
公司主營(yíng)業(yè)務(wù):網(wǎng)站設(shè)計(jì)、做網(wǎng)站、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)推出順河免費(fèi)做網(wǎng)站回饋大家。
用到的主要工具:
python3.5
selenium
scrapy
由于[網(wǎng)站的數(shù)據(jù)跟單(http://www.gendan5.com/tech.html)是可以按照地市來查詢的,所以先訪問該網(wǎng)站支持的城市劃分
使用scrapy的self.start_urls進(jìn)行請(qǐng)求
self.start_urls = ['https://www.zhipin.com/wapi/zpCommon/data/city.json',]
1
同時(shí)使用selenium請(qǐng)求該網(wǎng)站主頁
self.driver.get('https://www.zhipin.com/')
1
后來發(fā)現(xiàn)網(wǎng)站可以識(shí)別selenium,不返回?cái)?shù)據(jù),于是添加
options = webdriver.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-automation'])
self.driver = webdriver.Chrome(options=options)
將程序設(shè)置為開發(fā)者模式,數(shù)據(jù)可以正常請(qǐng)求到
接下來就是解析支持搜索的城市名,并且匯總成我們能使用的數(shù)據(jù)格式
dic = {}
json_text = json.loads(response.text)['zpData']['cityList']
for i in range(len(json_text)):
# 獲取到各個(gè)省的名稱,并且作為字典的鍵名賦值
province = json_text[i]['name']
provinces = json_text[i]['subLevelModelList']
dic.setdefault(province,[])
citys = []
# 分類直轄市和地級(jí)市,并歸類到字典的值
if provinces.__len__() > 1:
for ii in range(len(provinces)):
city = provinces[ii]['name']
citys.append(city)
else:
city = province
citys.append(city)
dic[province] = citys
準(zhǔn)備工作完成了,接下來就是請(qǐng)求數(shù)據(jù)了
self.driver.find_element_by_xpath('//*[@id="wrap"]/div[3]/div/div/div[1]/form/div[2]/p/input').send_keys('需要查詢的崗位') # 主頁搜索框,過度用
sleep(2)
self.driver.find_element_by_xpath('//*[@id="wrap"]/div[3]/div/div/div[1]/form/button').click()
sleep(2)
到這里,程序算是進(jìn)入了正軌,直接貼上代碼。如下:
import scrapy
import json
import re
from scrapy.spiders import CrawlSpider
from time import sleep
from ..items import ZhaopinBossZhipinItem
from scrapy.selector import Selector
import importlib
import random
from selenium import webdriver
import sys
importlib.reload(sys)
class ZP_boss(CrawlSpider):
name = "boss"
custom_settings = {
'ITEM_PIPELINES': {'zhaopin_bosszhipin.pipelines.ZhaopinBossPipeline': 300, },
'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': 1,
'DOWNLOAD_DELAY': 0.5,
'MYEXT_ENABLED': True
}
def __init__(self,):
super(ZP_boss,self).__init__()
self.allowed_domains = ["https://www.baidu.com"] # 過濾的url
self.start_urls = ['https://www.zhipin.com/wapi/zpCommon/data/city.json',] # 訪問網(wǎng)頁支持搜索的城市
options = webdriver.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-automation'])
self.driver = webdriver.Chrome(options=options)
self.driver.maximize_window() # 瀏覽器設(shè)置成頁面最大化
self.driver.get('https://www.zhipin.com/')
def parse(self, response):
dic = {}
json_text = json.loads(response.text)['zpData']['cityList']
for i in range(len(json_text)):
# 獲取到各個(gè)省的名稱,并且作為字典的鍵名賦值
province = json_text[i]['name']
provinces = json_text[i]['subLevelModelList']
dic.setdefault(province,[])
citys = []
# 分類直轄市和地級(jí)市,并歸類到字典的值
if provinces.__len__() > 1:
for ii in range(len(provinces)):
city = provinces[ii]['name']
citys.append(city)
else:
city = province
citys.append(city)
dic[province] = citys
self.driver.find_element_by_xpath('//*[@id="wrap"]/div[3]/div/div/div[1]/form/div[2]/p/input').send_keys('python') # 主頁搜索框,過度用
sleep(2)
self.driver.find_element_by_xpath('//*[@id="wrap"]/div[3]/div/div/div[1]/form/button').click()
sleep(2)
for prov in dic.keys(): # 循環(huán)抓取到的省名
cts = dic[prov] # 單個(gè)省或者直轄市包含的所有城市
for ct in cts: # 單個(gè)城市名
query = '搜索的崗位'+ct
self.driver.find_element_by_xpath('//p[@class="ipt-wrap"]/input[@name="query"]').clear()
# sleep(0.1)
self.driver.find_element_by_xpath('//p[@class="ipt-wrap"]/input[@name="query"]').send_keys(query)
sleep(0.2)
self.driver.find_element_by_xpath('//button[@class="btn btn-search"]').click() # 點(diǎn)擊查詢數(shù)據(jù)
sleep(1)
# source = Selector(text=self.driver.page_source)
panduan = True
while panduan: # 循環(huán)翻頁
sou = Selector(text=self.driver.page_source)
link_lens = sou.xpath('//*[@id="main"]/div/div[2]/ul/li').extract() # 獲取當(dāng)前頁面所有的li標(biāo)簽,一個(gè)標(biāo)簽就是一條招聘數(shù)據(jù)
# 分解出當(dāng)前頁面每一個(gè)li標(biāo)簽,并獲取到部分?jǐn)?shù)據(jù)
for link_text in link_lens:
sel = Selector(text=link_text)
# 招聘單位
company = ''.join(sel.xpath('//div[@class="company-text"]/h4/a/text()').extract()).strip()
# 城市
city = ct
# 學(xué)歷要求
education = ''.join(sel.xpath('//div[@class="info-primary"]/p/text()[3]').extract()).strip()
# 工作經(jīng)驗(yàn)
experience = ''.join(sel.xpath('//div[@class="info-primary"]/p/text()[2]').extract()).strip()
# 獲取數(shù)據(jù)的城市地址
adrs_text = sel.xpath('//p/text()').extract()
if adrs_text: # 加這個(gè)判斷是為了保證有城市數(shù)據(jù),有時(shí)候網(wǎng)頁會(huì)抽風(fēng)導(dǎo)致 下標(biāo)越界或空對(duì)象沒有g(shù)roup()方法的錯(cuò)
adrs = re.search('(\w+?)\s',''.join(adrs_text[0])).group().strip() # 匹配出當(dāng)前招聘所在城市名
if adrs != ct: # 如果沒有匹配數(shù)據(jù),網(wǎng)站會(huì)把該省的其他市數(shù)據(jù)返回,篩選掉這部分?jǐn)?shù)據(jù),只做精準(zhǔn)匹配
panduan = False
continue
else:
pass
are = re.search('\s(\w+?)\s',''.join(adrs_text[0])) # 城市的區(qū)
if are:
area = are.group().strip()
else:
area = ''
main_url = 'https://www.zhipin.com'
link_href = ''.join(sel.xpath('//div[@class="info-primary"]/h4[@class="name"]/a/@href').extract()).strip()
url = main_url + link_href
# 獲取詳情頁的索引值
href_index = ''.join(sel.xpath('//div[@class="info-primary"]/h4[@class="name"]/a/@data-index').extract()).strip()
# 點(diǎn)擊進(jìn)入詳情頁
link_page = self.driver.find_element_by_xpath('//div[@class="info-primary"]/h4/a[@data-index="{}"]/div[@class="job-title"]'.format(href_index))
link_page.click()
# driver切換到新頁面,獲取詳情頁數(shù)據(jù)
n = self.driver.window_handles # 獲取到所有窗口,返回的是一個(gè)list,下標(biāo)從0開始
self.driver.switch_to.window(n[1]) # 切換到新的網(wǎng)頁窗口視圖,driver的page_source也會(huì)更改成新頁面的
sleep(1)
se = Selector(text=self.driver.page_source)
# 崗位
job_name = ''.join(se.xpath('//div[@class="name"]/h2/text()').extract()).strip()
# 薪資
salary = ''.join(se.xpath('//div[@class="name"]/span[@class="salary"]/text()').extract()).strip()
# 福利
welfare = ';'.join(se.xpath('//*[@id="main"]/div[1]/div/div/div[2]/div[3]/div[2]/span/text()').extract()).strip()
# 發(fā)布時(shí)間
publishtime = ''.join(re.findall('\d+.*',''.join(se.xpath('//*[@id="main"]/div[3]/div/div[1]/div[2]/p[@class="gray"]/text()').extract()))).strip()
# 崗位職責(zé)
Duty = ''.join(se.xpath('//*[@id="main"]/div[3]/div/div[2]/div[2]/div[1]/div[@class="text"]').extract()).strip()
# 詳細(xì)地址
address = ''.join(se.xpath('//*[@id="main"]/div[3]/div/div[2]/div[2]/div/div[@class="job-location"]/div[@class="location-address"]/text()').extract()).strip()
print('發(fā)布時(shí)間:',publishtime)
print('崗位名稱:',job_name)
print('招聘單位:',company)
print('學(xué)歷要求:',education)
print('工作經(jīng)驗(yàn):',experience)
print('薪資:',salary)
print('福利:',welfare)
print('地址:',address)
print('崗位職責(zé):',Duty)
self.driver.close() # 必須關(guān)閉當(dāng)前數(shù)據(jù)頁面,否則會(huì)占用大量資源,查詢數(shù)據(jù)量很大的時(shí)候會(huì)導(dǎo)致宕機(jī)。。。
sleep(0.5)
self.driver.switch_to.window (n[0]) # 切換回原網(wǎng)頁
else:
continue
# 先判斷是否有分頁信息,每頁最多30條數(shù)據(jù)(30個(gè)li標(biāo)簽),少于30條數(shù)據(jù)表示沒有下一頁了
if link_lens.__len__() < 30:
print('沒有下一頁了')
panduan = False
else:
if panduan: # 會(huì)出現(xiàn)有下一頁但是數(shù)據(jù)不是我們查詢的市的數(shù)據(jù),已在上方進(jìn)行了判斷(if adrs != ct:)
if ''.join(sou.xpath('//a[@ka="page-next"]/@href').extract()) == "javascript:;": # 網(wǎng)站最多顯示10頁數(shù)據(jù),不做判斷會(huì)導(dǎo)致死循環(huán)
panduan = False
else:
next_page = self.driver.find_element_by_xpath('//a[@ka="page-next"]') # 翻頁按鈕
next_page.click() # 點(diǎn)擊翻頁
print('準(zhǔn)備抓取下一頁')
sleep(random.randint(1,5)) # 考慮到封ip,適當(dāng)休眠
else:
break
sleep(random.randint(5,15))
self.driver.quit() # 程序運(yùn)行結(jié)束,關(guān)閉瀏覽器進(jìn)程
數(shù)據(jù)爬取完畢。
pipelines,sttings和item的代碼千篇一律,這里就不放上來了。
由于使用的是selenium,注定了爬取速度不會(huì)很快。
看完這篇文章,你們學(xué)會(huì)用selenium工具抓取網(wǎng)站數(shù)據(jù)的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀。