整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          實(shí)習(xí)僧招聘網(wǎng)爬蟲(chóng)數(shù)據(jù)可視化

          實(shí)習(xí)僧招聘網(wǎng)爬蟲(chóng)數(shù)據(jù)可視化


          本來(lái)對(duì)實(shí)習(xí)僧網(wǎng)站是沒(méi)什么好感的,因?yàn)橹白约涸趯?shí)習(xí)僧上投的實(shí)習(xí)簡(jiǎn)歷幾乎全部都石沉大海了(一個(gè)文科生偏要去投數(shù)據(jù)分析崗不碰壁才怪~_~)!

          然鵝看到最近知乎爬蟲(chóng)圈兒里的兩大趨勢(shì):爬美圖;爬招聘網(wǎng)站。

          后來(lái)大致了解下了,幾乎各類(lèi)大型的招聘文章都被別人爬過(guò)了,自己再去寫(xiě)免不了模仿之嫌,而且大神們都是用Python去爬的(Python我剛學(xué)會(huì)裝包和導(dǎo)數(shù)據(jù)),自己也學(xué)不來(lái)。

          現(xiàn)在只能選一個(gè)還沒(méi)怎么被盯上的招聘網(wǎng)站,沒(méi)錯(cuò)就它了——實(shí)習(xí)僧。

          說(shuō)老實(shí)話,實(shí)習(xí)僧的網(wǎng)站做的還是不錯(cuò)的,看著結(jié)構(gòu)挺簡(jiǎn)單,可是我用比較主流的Rvest和RCurl都失敗了(主要自己技術(shù)太渣了,抓包又抓不好)。最后只能勉強(qiáng)用RSelenium爬完了全部所需內(nèi)容。(用代碼驅(qū)動(dòng)瀏覽器的好處就是不用怎么考慮時(shí)延和偽裝包頭了,但是要遍歷成百上千頁(yè)網(wǎng)址真的很耗時(shí),爬完這個(gè)數(shù)據(jù)用了大約40多分鐘)。

          以下是爬蟲(chóng)部分:

          library(rvest)

          library(stringr)

          library(plyr)

          library(dplyr)

          library(Rwebdriver)

          library(dplyr)

          library(Rwordseg)

          library(wordcloud2)

          library(treemap)

          library(showtext)

          library(Cairo)

          library(ggplot2)

          library(scales)

          library(grid)

          library(RColorBrewer)

          library(ggimage)

          library(geojsonio)

          本文主要用的Rwebdriver包來(lái)驅(qū)動(dòng)Chrome瀏覽器,使用該包需要提前配置好桌面環(huán)境:

          • 下載selenium啟動(dòng)服務(wù)器;

          • 下載Chrome的chromedriver插件并放入Chrome主目錄(添加系統(tǒng)環(huán)境變量)

          • 下載Rwebdriver包

          在cmd或者powershell中啟動(dòng)Selenium服務(wù)器:

          options(stringsAsFactors=FALSE,warn=FALSE)

          cd "D:/Rwebdriver-master"

          java -jar selenium-server-standalone-3.3.1.jar

          在Rsudio中新建進(jìn)程:

          start_session(root="http://localhost:4444/wd/hub/",browser="chrome")

          遍歷實(shí)習(xí)僧的招聘信息網(wǎng)頁(yè)

          baseurl<-"http://www.shixiseng.com/interns?k=&t=zh&c=%E5%85%A8%E5%9B%BD&p="

          pageurl<-paste0(baseurl,1:500)

          本文所用到的爬蟲(chóng)代碼部分:

          homepage=internship=companyweb=company=Position=address=salary=period=duration=NULL

          fun<-function(url){

          post.url(url=url)

          baseinfo<-read_html(url,encoding="utf-8")

          homepage <-baseinfo%>%html_nodes("div.po-name>div.names>a")%>% html_attr("href")

          internship<-baseinfo%>%html_nodes("div.po-name>div.names>a")%>%html_text()

          companyweb<-baseinfo%>%html_nodes("div.po-name>div.part>a")%>%html_attr("href")

          company <-baseinfo%>%html_nodes("div.po-name>div.part>a")%>%

          html_text()

          Position <-baseinfo%>%html_nodes("div.po-name>div.part")%>%

          html_text()

          address <-baseinfo%>%html_nodes("div.po-detail>div.addr>span")%>%

          html_text()

          salary <-baseinfo%>%html_nodes("div.po-detail>div.xz>span:nth-child(2)")%>%

          html_text()

          period <-baseinfo%>%html_nodes("div.po-detail>div.xz>span:nth-child(5)")%>%

          html_text()

          duration <-baseinfo%>%html_nodes("div.po-detail>div.xz>span:nth-child(8)")%>%

          html_text()

          interninfo<-data.frame(homepage,internship,companyweb,company,Position,address,salary,period,duration)

          }

          用一個(gè)循環(huán)執(zhí)行上述程序:

          final<-data.frame()

          for (i in pageurl){

          final<-rbind(final,fun(i))

          }

          quit_session()

          DT::datatable(final)

          保存本地:

          write.table (final,"D:/R/File/shixiseng.csv",sep=",",row.names=FALSE)

          ##############################################

          接下來(lái)做數(shù)據(jù)清洗:

          mydata<-read.csv("D:/R/File/shixiseng.csv",stringsAsFactors=FALSE,check.names=FALSE)

          mydata<-mydata[-5001,]

          #補(bǔ)全實(shí)習(xí)發(fā)布單位的招聘信息主頁(yè):

          mydata$homepage<-str_c("http://www.shixiseng.com",mydata$homepage,sep="")

          #補(bǔ)全實(shí)習(xí)發(fā)布單位的公司信息主頁(yè):

          mydata$companyweb<-str_c("http://www.shixiseng.com",mydata$companyweb,sep="")

          mydata$work<-str_split(mydata$Position[1:10], " - ", simplify=TRUE)[,2]

          #清除salary中的空格和斜杠

          mydata$salary<-str_trim(mydata$salary,side="both")

          mydata$salary<-str_extract(mydata$salary,"\d+\-\d+")

          #拆分實(shí)習(xí)工資的高低區(qū)間

          mydata$salary_low<-str_split(mydata$salary, "-", simplify=TRUE)[,1]

          mydata$salary_high<-str_split(mydata$salary, "-", simplify=TRUE)[,2]

          #清除period中的漢字和特殊字符

          mydata$period<-str_extract(mydata$period,"\d+")

          #清除duration中的漢字和特殊字符

          mydata$duration<-str_extract(mydata$duration,"\d+")

          mydata <- tbl_df(mydata)

          mydata<-select(mydata,-Position)

          #因?yàn)閍ddress中所含的地址可能有存在多個(gè),影響我們后續(xù)的可視化分析,這里為了方便起見(jiàn),一律使用第一個(gè)地址。

          mydata$address_unique<-str_split(mydata$address, ",", simplify=TRUE)[,1]

          至此,數(shù)據(jù)清洗工作告一段落,接下來(lái)我們要進(jìn)入分析與可視化階段

          names(mydata)

          "homepage"-------公司實(shí)習(xí)職位簡(jiǎn)介

          "internship"-----公司招聘性質(zhì)

          "companyweb"-----公司主頁(yè)

          "company"--------公司名稱

          "address"--------所在地

          "address_unique"-所在地(唯一值,只取默認(rèn)第一個(gè)地址)

          "salary"---------實(shí)習(xí)工資區(qū)間

          "salary_low"-----實(shí)習(xí)工資(最低值)

          "salary_high"----實(shí)習(xí)工資(最高值)

          "period"---------到崗天數(shù)(每周)

          "duration"-------實(shí)習(xí)周期(按月算)

          "work"-----------具體職位

          我們最終獲取的清洗后數(shù)據(jù)如上所示。

          假如本次項(xiàng)目需求(虛擬)要求我們獲取以下幾個(gè)問(wèn)題:

          1、實(shí)習(xí)僧的實(shí)習(xí)招聘主頁(yè)崗位主要是什么性質(zhì)的?

          2、哪些公司最缺實(shí)習(xí)僧?

          3、實(shí)習(xí)崗位具體分布的地域和城市?

          4、哪些城市對(duì)實(shí)習(xí)僧的需要最為強(qiáng)烈?

          5、實(shí)習(xí)工資大致什么水平,與城市和地域是否有關(guān)系?

          6、實(shí)習(xí)崗位一般都要求每周到崗多少天?

          7、實(shí)習(xí)周期一般需要多長(zhǎng)時(shí)間?

          8、哪些職位需求最為頻繁,職位需要量與城市之間的大致是如何分布的?

          帶著這些個(gè)問(wèn)題,讓我們盡情的暢游在可視化的世界里吧……

          1、實(shí)習(xí)僧的實(shí)習(xí)招聘主頁(yè)主要是什么性質(zhì)的?

          length(unique(mydata$internship))

          3357

          絕望了,一共爬了5000條實(shí)習(xí)職位信息,做了去重處理,顯示仍有3357條,建議實(shí)習(xí)僧的產(chǎn)品運(yùn)營(yíng)團(tuán)隊(duì)考慮下要不要標(biāo)準(zhǔn)化一下這個(gè)職位性質(zhì),內(nèi)門(mén)怎么可以創(chuàng)造這么多獨(dú)特的職位~_~

          對(duì)于這個(gè)問(wèn)題,真的難倒我了,因?yàn)樗罃?shù)據(jù)中的職位性質(zhì)沒(méi)有統(tǒng)一的預(yù)設(shè)標(biāo)準(zhǔn),所以我只能用文本分詞的形式來(lái)進(jìn)行提取了,先分詞,然后統(tǒng)計(jì)高頻詞,最后按照詞頻來(lái)進(jìn)行模糊分析啦(可我我對(duì)文本挖掘一竅不通啊~_~)

          top100<-table(mydata$internship)%>%as.data.frame(stringsAsFactors=FALSE)%>% arrange(desc(Freq))%>%.[1:100,]

          treemap(top100, index=c("Var1"), vSize="Freq",title='實(shí)習(xí)僧職位性質(zhì)分布圖',palette='RdBu',

          fontsize.title=18,fontsize.labels=12,fontface.labels="plain",fontfamily.title="mono",fontfamily.labels="mono")

          從實(shí)習(xí)職位分布圖上來(lái)看,人力資源實(shí)習(xí)生職位需求最為強(qiáng)烈,其次是運(yùn)營(yíng)、財(cái)務(wù)、新媒體,這些類(lèi)型的職位多為現(xiàn)代新興服務(wù)業(yè),更為符合大學(xué)生這一群體的口味和興趣。

          myrevieww<-mydata$internship

          thewords <- segmentCN(myrevieww,nature=T)%>%unlist()

          thewords <- gsub("[a-z]|\.", "", thewords)

          thewords<-thewords[nchar(thewords)>1]

          reviewdata<-table(thewords)%>%as.data.frame(stringsAsFactors=FALSE)%>% arrange(desc(Freq))%>%filter(thewords!="實(shí)習(xí)生")

          wordcloud<-wordcloud2(reviewdata[1:1000,],color="random-light",minSize=.6,size=1,backgroundColor="dark",minRotation=-pi/6,maxRotation=-pi/6,fontFamily="微軟雅黑");wordcloud

          但是將職位性質(zhì)分詞整理成關(guān)鍵詞后,似乎結(jié)果有所不同。

          2、哪些公司最缺實(shí)習(xí)僧?

          這里我們來(lái)統(tǒng)計(jì)所爬職位信息中公司發(fā)布職位的頻率,發(fā)布最多的則作為評(píng)價(jià)公司對(duì)實(shí)習(xí)生需求的標(biāo)準(zhǔn)。

          myjob<-table(mydata$company)%>%as.data.frame(stringsAsFactors=FALSE)%>%arrange(desc(Freq))

          #看看前十名都是那些公司:

          myjob15<-arrange(myjob[1:15,],desc(Freq))

          CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/circle-rose.png",width=1580,height=950)

          showtext.begin()

          ggplot(data=myjob15,aes(x=reorder(Var1,-Freq),y=Freq,fill=Freq))+

          geom_linerange(aes(ymin=0,ymax=42),linetype=5,size=.2,colour="#858585")+

          geom_image(aes(x=0,y=-40),image="D:/R/Image/image1.jpg", size=.2)+

          geom_text(aes(y=45,label=paste0(Var1,"\n",Freq)),vjust=1,size=5)+

          geom_bar(stat="identity",width=1,col="white")+

          geom_hline(yintercept=54,color="black",size=.5)+

          geom_point(aes(y=48,size=Freq),shape=21,fill="#ED7D31",,alpha=0.6,col="orange")+

          labs(title="Top 15 of Company",caption="Data Source:shixiseng")+

          coord_polar(theta="x")+

          ylim(-40,60)+

          scale_size_area(max_size=20)+

          guides(fill=FALSE,size=guide_legend(reverse=TRUE,title=NULL))+

          theme_minimal()+

          theme(

          axis.title=element_blank(),

          axis.text=element_blank(),

          panel.grid=element_blank(),

          legend.text=element_text(family="myfont",size=12),

          legend.title=element_text(family="myfont",size=15,hjust=1),

          plot.title=element_text(family="myfont",size=35),

          plot.caption=element_text(family="myfont",size=18,hjust=0,lineheight=1.2)

          )

          showtext.end()

          dev.off()

          write.table (myjob[1:100,],"D:/R/File/shixiseng_job.csv",sep=",",row.names=FALSE)

          前一百個(gè)實(shí)習(xí)生需求最旺盛企業(yè):

          3、實(shí)習(xí)崗位具體分布的地域和城市?

          先做一個(gè)地域分布圖:

          add<-table(mydata$address_unique)%>%as.data.frame(stringsAsFactors=FALSE)%>%arrange(desc(Freq))%>%filter(nchar(Var1)==2)

          #城市經(jīng)緯度查詢:

          library(rjson)

          library(RCurl)

          library(REmap)

          library(baidumap)

          address<-add$Var1

          baidu_lng <- c()

          baidu_lat <- c()

          ak<-"X8zlxPUdSe2weshrZ1WqnWxb43cfBI2N"

          for(location in address){

          url<-paste("http://api.map.baidu.com/geocoder/v2/?ak=",ak,"&callback=renderOption&output=json&address=",location,sep="")

          url_string <- URLencode(url)

          msg.load <- tryCatch({

          json <-readLines(url_string,warn=F,encoding="UTF-8")

          msg.load <- "TRUE"

          },error=function(e) {

          "error"

          }

          )

          if(msg.load=='error'){

          Sys.sleep(runif(1,3,10))

          msg.load <- tryCatch({

          connect <- readLines(url_string,warn=F,encoding="UTF-8")

          msg.load <- "TRUE"

          }, error=function(e){

          "error"

          }

          )

          }

          geo <- fromJSON(substr(json,regexpr("\(",json)+1,nchar(json)-1))

          if(msg.load=='error'){

          lng<-'error1'

          lat<-'error1'

          }else{

          lng<-geo$result$location$lng

          lat<-geo$result$location$lat

          if(length(lng)==0){

          lng <- "error2"

          lat <- "error2"

          }

          }

          lng<-geo$result$location$lng

          lat<-geo$result$location$lat

          baidu_lng<-c(baidu_lng,lng)

          baidu_lat<-c(baidu_lat,lat)

          }

          result<-data.frame(address=address,long=baidu_lng,lat=baidu_lat,stringsAsFactors=FALSE)

          pointdata<-left_join(add,result,by=c("Var1"="address"))

          #成功獲取目標(biāo)城市經(jīng)緯度信息:

          解析來(lái)制作分布圖:

          geojson <-readOGR("D:/R/mapdata/State/china.geojson","OGRGeoJSON",stringsAsFactors=FALSE)

          Encoding(geojson$name)<-"UTF-8"

          china_Mapdata<-geojson@data

          china_MapdataPloygon<-fortify(geojson)

          CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/shixiseng_jobcity.png",width=1200,height=640)

          showtext.begin()

          ggplot()+

          geom_polygon(data=china_MapdataPloygon,aes(x=long,y=lat,group=group),col="grey60",fill="white",size=.2,alpha=.4)+

          geom_point(data=pointdata,aes(x=long,y=lat,size=Freq),shape=21,fill="#C72E29",col="#014D64",alpha=0.6)+

          scale_size_area(max_size=15,guide=guide_legend(reverse=TRUE,title=NULL))+

          coord_map("polyconic") +

          labs(title="實(shí)習(xí)僧職位需求城市分布圖",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+

          theme(

          title=element_text(family="myfont",size=18),

          plot.title=element_text(size=24),

          plot.caption=element_text(family="myfont",size=18,hjust=0),

          panel.grid=element_blank(),

          panel.background=element_blank(),

          axis.text=element_blank(),

          axis.ticks=element_blank(),

          axis.title=element_blank(),

          legend.position=c(0.02,0.6),

          )

          showtext.end()

          dev.off()

          4、哪些城市對(duì)實(shí)習(xí)僧的需要最為強(qiáng)烈?

          從第三個(gè)問(wèn)題及其分析結(jié)果上我們已經(jīng)看出了整體形勢(shì),北上廣深依然是需求最為旺盛的地區(qū),這也符合城市的實(shí)際經(jīng)濟(jì)發(fā)展情況及我們的預(yù)期。

          CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/jingjixue2.png",width=800,height=600)

          showtext.begin()

          ggplot(pointdata[1:20,],aes(reorder(Var1,Freq),Freq))+

          geom_bar(fill="#0C8DC4",stat="identity")+

          coord_flip()+

          labs(title="實(shí)習(xí)僧職位需求城市分布",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+

          geom_text(aes(y=Freq+25,label=Freq),hjust=2,colour="#C72E29",size=5)+

          theme_bw()+

          theme(

          panel.border=element_blank(),

          panel.grid.major=element_line(linetype="dashed"),

          panel.grid.minor=element_blank(),

          plot.title=element_text(size=15,colour="#003087",family="myfont"),

          plot.caption=element_text(hjust=0,size=10),

          axis.title=element_blank(),

          axis.text=element_text(size=15)

          )

          showtext.end()

          dev.off()

          5、實(shí)習(xí)工資大致什么水平,與城市和地域是否有關(guān)系?

          myjob_salary<-mydata[,c("address_unique","salary_low","salary_high")]

          myjob_salary$salary_low<-as.numeric(myjob_salary$salary_low)

          myjob_salary$salary_high<-as.numeric(myjob_salary$salary_high)

          myjob_salary<-na.omit(myjob_salary)%>%arrange(salary_high)%>%filter(salary_high>=20&salary_high<=500)

          myjob_salary$id<-seq_len(nrow(myjob_salary))

          myjob_salary$meansalary<-(myjob_salary$salary_low+myjob_salary$salary_high)/2

          CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/shixiseng_jobsaleryarea.png",width=1200,height=800)

          showtext.begin()

          ggplot(myjob_salary,aes(id))+

          geom_ribbon(aes(ymin=salary_low,ymax=salary_high),fill="grey70")+

          labs(title="實(shí)習(xí)僧職位工資區(qū)間分布",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+

          geom_line(aes(y=meansalary))+

          theme_minimal()+

          theme(

          panel.border=element_blank(),

          panel.grid.major=element_line(linetype="dashed"),

          panel.grid.minor=element_blank(),

          plot.title=element_text(size=30,colour="#003087",family="myfont"),

          plot.caption=element_text(hjust=0,size=20),

          axis.title=element_blank(),

          axis.text.y=element_text(size=15),

          axis.text.x=element_blank()

          )

          showtext.end()

          dev.off()

          myjob_salary$address_unique<-substr(myjob_salary$address_unique,1,2)

          myjobcitysalary<-aggregate(meansalary~address_unique,data=myjob_salary,FUN=mean)

          treemap(na.omit(myjobcitysalary), index=c("address_unique"),

          vSize="meansalary",title='實(shí)習(xí)僧職位薪酬地域分布圖',palette='RdBu',

          fontsize.title=18,fontsize.labels=12,fontface.labels="plain",

          fontfamily.title="mono",fontfamily.labels="mono")

          按照全部參與計(jì)算聚合的平均工資來(lái)看,北上廣深反而沒(méi)有什么吸引力了排名普遍不高,我猜想是因?yàn)橐痪€城市的低工資職位數(shù)量過(guò)多,壓低了平均值。

          接下來(lái)我們按照100,150的臨界點(diǎn)進(jìn)行工資高低的劃分。

          salary100<-myjob_salary%>%filter(meansalary<=100)%>%select(address_unique)%>%table()%>%as.data.frame(stringsAsFactors=FALSE)

          salary100<-na.omit(salary100)%>%arrange(desc(Freq));names(salary100)<-c("city","num")

          CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/salary100.png",width=1200,height=900)

          showtext.begin()

          ggplot(salary100[salary100$num>=5,],aes(reorder(city,-num),num))+

          geom_bar(fill="#0C8DC4",stat="identity")+

          labs(title="實(shí)習(xí)僧職位薪資城市分布(日薪低于100)",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+

          geom_text(aes(y=num+10,label=num),hjust=.5,colour="#C72E29",size=5)+

          theme_bw()+

          theme(

          panel.border=element_blank(),

          panel.grid.major=element_line(linetype="dashed"),

          panel.grid.minor=element_blank(),

          plot.title=element_text(size=25,colour="#003087",family="myfont"),

          plot.caption=element_text(hjust=0,size=18),

          axis.title=element_blank(),

          axis.text=element_text(size=15)

          )

          showtext.end()

          dev.off()

          salary200<-myjob_salary%>%filter(meansalary>=200)%>%select(address_unique)%>%table()%>%as.data.frame(stringsAsFactors=FALSE)

          salary200<-na.omit(salary200)%>%arrange(desc(Freq));names(salary200)<-c("city","num")

          CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/salary200.png",width=1200,height=900)

          showtext.begin()

          ggplot(salary200,aes(reorder(city,-num),num))+

          geom_bar(fill="#0C8DC4",stat="identity")+

          labs(title="實(shí)習(xí)僧職位薪資城市分布(日薪高于200)",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+

          geom_text(aes(y=num+10,label=num),hjust=.5,colour="#C72E29",size=5)+

          theme_bw()+

          theme(

          panel.border=element_blank(),

          panel.grid.major=element_line(linetype="dashed"),

          panel.grid.minor=element_blank(),

          plot.title=element_text(size=25,colour="#003087",family="myfont"),

          plot.caption=element_text(hjust=0,size=18),

          axis.title=element_blank(),

          axis.text=element_text(size=15)

          )

          showtext.end()

          dev.off()

          salary100_200<-myjob_salary%>%filter(meansalary>100 & meansalary<200)%>%select(address_unique)%>%table()%>%as.data.frame(stringsAsFactors=FALSE)

          salary100_200<-na.omit(salary100_200)%>%arrange(desc(Freq));names(salary100_200)<-c("city","num")

          CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/salary100-200.png",width=1600,height=900)

          showtext.begin()

          ggplot(salary100_200,aes(reorder(city,-num),num))+

          geom_bar(fill="#0C8DC4",stat="identity")+

          labs(title="實(shí)習(xí)僧職位薪資城市分布(日薪處于100-200之間)",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+

          geom_text(aes(y=num+10,label=num),hjust=.5,colour="#C72E29",size=5)+

          theme_bw()+

          theme(

          panel.border=element_blank(),

          panel.grid.major=element_line(linetype="dashed"),

          panel.grid.minor=element_blank(),

          plot.title=element_text(size=25,colour="#003087",family="myfont"),

          plot.caption=element_text(hjust=0,size=18),

          axis.title=element_blank(),

          axis.text=element_text(size=15)

          )

          showtext.end()

          dev.off()

          分析到這里,趨勢(shì)已經(jīng)很明顯了,因?yàn)楸鄙蠌V深等一線城市的職位實(shí)在是太多了,無(wú)論是高新職位還是低薪實(shí)習(xí)崗位都能排在全國(guó)各城市的前列,所以出現(xiàn)日均工資很普通的現(xiàn)象。相對(duì)而言,日薪在200以上的高薪職位更能代表各大城市對(duì)日常實(shí)習(xí)生需求的強(qiáng)烈程度,因?yàn)樵谶@一階段,北上廣深的優(yōu)勢(shì)非常明顯,遙遙領(lǐng)先與其他二線城市,而針對(duì)日薪高于200的實(shí)習(xí)職位統(tǒng)計(jì)結(jié)果可以看出來(lái),北上技?jí)喝盒郏ú焕⑹堑鄱己湍Ф迹?,深圳和廣州處于第二線,200以上的高新實(shí)習(xí)職位遇北上相比,相差比較大,僅占前兩者約1/3~1/5。而杭州、南京、武漢、合肥則穩(wěn)穩(wěn)處于第三梯隊(duì)。

          6、實(shí)習(xí)崗位一般都要求每周到崗多少天?

          myperiod<-mydata$period

          CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/internperiod.png",width=1000,height=750)

          showtext.begin()

          ggplot(data=NULL,aes(myperiod)) +

          geom_histogram(stat="count",show.legend=FALSE,binwidth=1,fill="#F86977",col=NA) +

          labs(title="實(shí)習(xí)職位要求每周工作天數(shù)",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+

          theme(panel.background=element_rect(fill=NA),

          plot.background=element_rect(fill=NA),

          plot.title=element_text(size=20,family="myfont"),

          plot.caption=element_text(hjust=0,family="myfont"),

          axis.line=element_line(colour="grey80"),

          axis.text=element_text(size=12,family="myfont"),

          axis.title=element_blank())

          showtext.end()

          dev.off()

          從分布上看,一周五天居多,這樣是正常的工作日現(xiàn)象。3天、4天也是用人單位補(bǔ)繳能接受的周工作天數(shù)。

          7、實(shí)習(xí)周期一般需要多長(zhǎng)時(shí)間?

          myduration<-mydata$duration

          mydurationhz<-table(myduration)%>%as.data.frame(stringsAsFactors=FALSE)%>%arrange(desc(Freq))

          CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/internduration.png",width=1000,height=750)

          showtext.begin()

          ggplot(data=mydurationhz,aes(reorder(myduration,-Freq),Freq)) +

          geom_bar(stat="identity",show.legend=FALSE,width=1,fill="#065573",col=NA) +

          geom_text(aes(y=Freq+20,label=Freq),hjust=.5,colour="#C72E29",size=5)+

          labs(title="實(shí)習(xí)職位要求工作時(shí)間周期",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+

          theme(panel.background=element_rect(fill=NA),

          plot.background=element_rect(fill=NA),

          plot.title=element_text(size=20,family="myfont"),

          plot.caption=element_text(hjust=0,family="myfont"),

          axis.line=element_line(colour="grey80"),

          axis.text=element_text(size=12,family="myfont"),

          axis.title=element_blank())

          showtext.end()

          dev.off()

          8、哪些職位需求最為旺盛?

          下面開(kāi)始分析最后一個(gè)問(wèn)題,也是我認(rèn)為最有價(jià)值,最值得探究的問(wèn)題,最后一個(gè)待分析指標(biāo)是實(shí)習(xí)職位,這個(gè)指標(biāo)跟我們最初分析的那個(gè)崗位性質(zhì)略有不同,該變量相對(duì)比較規(guī)范(職位類(lèi)別有確定的預(yù)設(shè)范圍)。

          我們新建一個(gè)分析數(shù)據(jù),用職位、工資區(qū)間的中間值,地區(qū)三個(gè)變量進(jìn)行后續(xù)分析:

          mydata$salary_high<-as.numeric(mydata$salary_high)

          mydata$salary_low<-as.numeric(mydata$salary_low)

          mydata$salary_mean<-(mydata$salary_low+mydata$salary_high)/2

          myworkdata<-mydata[,c("address_unique","work","salary_mean")]

          首先分析下崗位的集中分布情況:

          myworkcount<-table(myworkdata[,2])%>%as.data.frame(stringsAsFactors=FALSE)%>%arrange(desc(Freq))

          CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/interndworkcount.png",width=1000,height=750)

          showtext.begin()

          ggplot(data=myworkcount,aes(reorder(Var1,-Freq),Freq)) +

          geom_bar(stat="identity",show.legend=FALSE,width=.75,fill="#5D8DA6",col=NA) +

          geom_text(aes(y=Freq+50,label=Freq),hjust=.5,colour="#C72E29",size=5)+

          labs(title="實(shí)習(xí)職位類(lèi)別分布",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+

          theme(panel.background=element_rect(fill=NA),

          plot.background=element_rect(fill=NA),

          plot.title=element_text(size=20,family="myfont"),

          plot.caption=element_text(hjust=0,family="myfont"),

          axis.line=element_line(colour="grey80"),

          axis.text=element_text(size=12,family="myfont"),

          axis.title=element_blank())

          showtext.end()

          dev.off()

          各個(gè)崗位工資分布:

          myworkmean<-aggregate(salary_mean~work,data=myworkdata,FUN=mean)

          CairoPNG(file="E:/微信公眾號(hào)/公眾號(hào)——數(shù)據(jù)小魔方/2017年5月/20170512/interndworkmean.png",width=1000,height=750)

          showtext.begin()

          ggplot(data=myworkmean,aes(reorder(work,-salary_mean),salary_mean)) +

          geom_bar(stat="identity",show.legend=FALSE,width=.75,fill="#5D8DA6",col=NA) +

          geom_text(aes(y=salary_mean+5,label=round(salary_mean,1)),hjust=.5,colour="#C72E29",size=10)+

          labs(title="實(shí)習(xí)職位類(lèi)別平均工資",caption="數(shù)據(jù)來(lái)源:實(shí)習(xí)僧官網(wǎng)")+

          theme(panel.background=element_rect(fill=NA),

          plot.background=element_rect(fill=NA),

          plot.title=element_text(size=25,family="myfont"),

          plot.caption=element_text(hjust=0,family="myfont",size=20),

          axis.line=element_line(colour="grey80"),

          axis.text=element_text(size=18,family="myfont"),

          axis.title=element_blank())

          showtext.end()

          dev.off()

          從工資均數(shù)上來(lái)看,七大類(lèi)職位差距不大,說(shuō)明僅就實(shí)習(xí)崗位工資而言,結(jié)合爬取的總體樣本,不考慮地域差異,實(shí)習(xí)工資差異不很明顯。也許是因?yàn)閷?shí)習(xí)崗位中真正有含金量的并不多,換句話說(shuō),企業(yè)的高價(jià)值崗位,對(duì)于工作經(jīng)驗(yàn)、技能的要求相對(duì)較高,而實(shí)習(xí)生則在這方面都不具備優(yōu)勢(shì)。(如果是社招或者小校招崗位信息的話,可能工資均值的差異會(huì)大一些)。

          最后,讓我們用一個(gè)桑基圖來(lái)完結(jié)本次針對(duì)實(shí)習(xí)僧網(wǎng)站的爬蟲(chóng)分析:

          write.table (myworkdata,"D:/R/File/shixiseng_workdata.csv",sep=",",row.names=FALSE)

          ?;飨驁D的趨勢(shì)灰常明顯,北上兩市在所有類(lèi)別職位(7大類(lèi))上均居前列,各職位類(lèi)別中,市場(chǎng)和運(yùn)營(yíng)職位需求最為強(qiáng)烈,北京和上海在對(duì)市場(chǎng)和運(yùn)營(yíng)職位的需求容量機(jī)會(huì)平分秋色。廣州和深圳仍然略于北上,但是與其他二線城市相比較,優(yōu)勢(shì)仍然很明顯。(也許是因?yàn)閷?shí)習(xí)僧做為主打校園實(shí)習(xí)崗位信息咨詢平臺(tái),針對(duì)的主流群體基本以在校大學(xué)生為主,而北上廣深的高等教育資源分布差異明顯,在高校數(shù)量方面,北上的要沾光很多,廣州與深圳的高校資源相對(duì)比較匱乏,在以上分析的各項(xiàng)指標(biāo)中都占盡劣勢(shì))。

          爬蟲(chóng)和代碼分析,算起來(lái)整整花了將近12個(gè)小時(shí),雖然分析的不是很精準(zhǔn)、客觀,但是過(guò)程還是很有收獲的,期待下一次做的更好!

          End.

          來(lái)源:R語(yǔ)言中文社區(qū)

          國(guó)統(tǒng)計(jì)網(wǎng),是國(guó)內(nèi)最早的大數(shù)據(jù)學(xué)習(xí)網(wǎng)站,歡迎關(guān)注!

          I 鑒賞

          早幾年學(xué)習(xí)前端,大家都非常熱衷于研究jQuery源碼。

          我至今還記得當(dāng)初從jQuery源碼中學(xué)到一星半點(diǎn)應(yīng)用技巧的時(shí)候常會(huì)有一種發(fā)自內(nèi)心的驚嘆,“原來(lái)JavaScript居然可以這樣用!”

          但是隨著前端的迅猛發(fā)展,另外幾種前端框架的崛起,jQuery慢慢變得不再是必須。所有人對(duì)jQuery的熱情都降低了許多。

          jQuery在前端史上有它非常超然的歷史地位,許多從中學(xué)到的技巧在實(shí)踐開(kāi)發(fā)中仍然非常好用。簡(jiǎn)單的了解它有助于我們更加深入的理解JavaScript。如果你能夠從中看明白jquery是如何一步步被取代的,那么,我想你的收益遠(yuǎn)不止學(xué)會(huì)使用了一個(gè)庫(kù)那么簡(jiǎn)單。

          因此,我的態(tài)度是,項(xiàng)目中你可以不用,但是我仍然建議你學(xué)。

          這篇文章的主要目的,是從面向?qū)ο蟮慕嵌?,跟大家分享jquery對(duì)象是如何封裝的。算是對(duì)大家進(jìn)一步學(xué)習(xí)jQuery源碼的一個(gè)拋磚引玉。

          1

          使用jQuery對(duì)象時(shí),我們這樣寫(xiě):

          // 聲明一個(gè)jQuery對(duì)象
          $('.target')
          
          // 獲取元素的css屬性
          $('.target').css('width')
          
          // 獲取元素的位置信息
          $('.target').offset()
          

          在使用之初可能會(huì)有許多疑問(wèn),比如$是怎么回事?為什么不用new就可以直接聲明一個(gè)對(duì)象?等等。了解之后,才知道原來(lái)這正是jQuery對(duì)象創(chuàng)建的巧妙之處。

          先直接用代碼展示出來(lái),再用圖跟大家解釋是怎么回事。

          ;
          (function (ROOT) {
          
            // 構(gòu)造函數(shù)
            var jQuery=function (selector) {
          
              // 在jQuery中直接返回new過(guò)的實(shí)例,這里的init是jQuery的真正構(gòu)造函數(shù)
              return new jQuery.fn.init(selector)
            }
          
            jQuery.fn=jQuery.prototype={
              constructor: jQuery,
          
              version: '1.0.0',
          
              init: function (selector) {
                // 在jquery中這里有一個(gè)復(fù)雜的判斷,但是這里我做了簡(jiǎn)化
                var elem, selector;
                elem=document.querySelector(selector);
                this[0]=elem;
          
                // 在jquery中返回一個(gè)由所有原型屬性方法組成的數(shù)組,我們這里簡(jiǎn)化,直接返回this即可
                // return jQuery.makeArray(selector, this);
                return this;
              },
          
              // 在原型上添加一堆方法
              toArray: function () { },
              get: function () { },
              each: function () { },
              ready: function () { },
              first: function () { },
              slice: function () { }
              // ... ...
            }
          
            jQuery.fn.init.prototype=jQuery.fn;
          
            // 實(shí)現(xiàn)jQuery的兩種擴(kuò)展方式
            jQuery.extend=jQuery.fn.extend=function (options) {
          
              // 在jquery源碼中會(huì)根據(jù)參數(shù)不同進(jìn)行很多判斷,我們這里就直接走一種方式,所以就不用判斷了
              var target=this;
              var copy;
          
              for (name in options) {
                copy=options[name];
                target[name]=copy;
              }
              return target;
            }
          
            // jQuery中利用上面實(shí)現(xiàn)的擴(kuò)展機(jī)制,添加了許多方法,其中
          
            // 直接添加在構(gòu)造函數(shù)上,被稱為工具方法
            jQuery.extend({
              isFunction: function () { },
              type: function () { },
              parseHTML: function () { },
              parseJSON: function () { },
              ajax: function () { }
              // ...
            })
          
            // 添加到原型上
            jQuery.fn.extend({
              queue: function () { },
              promise: function () { },
              attr: function () { },
              prop: function () { },
              addClass: function () { },
              removeClass: function () { },
              val: function () { },
              css: function () { }
              // ...
            })
          
            // $符號(hào)的由來(lái),實(shí)際上它就是jQuery,一個(gè)簡(jiǎn)化的寫(xiě)法,在這里我們還可以替換成其他可用字符
            ROOT.jQuery=ROOT.$=jQuery;
          })(window);
          

          在上面的代碼中,我封裝了一個(gè)簡(jiǎn)化版的jQuery對(duì)象。

          它向大家簡(jiǎn)單展示了jQuery的整體骨架。

          在代碼中可以看到,jQuery自身對(duì)于原型的處理使用了一些巧妙的方式,比如jQuery.fn=jQuery.prototype,jQuery.fn.init.prototype=jQuery.fn;等,這幾句正是jQuery對(duì)象的關(guān)鍵所在??磮D分析。

          jQuery對(duì)象核心圖

          2

          對(duì)象封裝分析

          在上面的實(shí)現(xiàn)中,首先在jQuery構(gòu)造函數(shù)里聲明了一個(gè)fn屬性,并將其指向了原型jQuery.prototype。然后在原型中添加了init方法。

          jQuery.fn=jQuery.prototype={
            init: {}
          }
          

          之后又將init的原型,指向了jQuery.prototype。

          jQuery.fn.init.prototype=jQuery.fn;
          

          而在構(gòu)造函數(shù)jQuery中,返回了init的實(shí)例對(duì)象。

          var jQuery=function (selector) {
          
            // 在jQuery中直接返回new過(guò)的實(shí)例,這里的init是jQuery的真正構(gòu)造函數(shù)
            return new jQuery.fn.init(selector)
          }
          

          最后對(duì)外暴露入口時(shí),將字符$與jQuery對(duì)等起來(lái)。

          ROOT.jQuery=ROOT.$=jQuery;
          

          因此當(dāng)我們直接使用$('#test')創(chuàng)建一個(gè)對(duì)象時(shí),實(shí)際上是創(chuàng)建了一個(gè)init的實(shí)例,這里的真正構(gòu)造函數(shù)是原型中的init方法。

          注意:許多對(duì)jQuery內(nèi)部實(shí)現(xiàn)不太了解的盆友,常常會(huì)毫無(wú)節(jié)制使用$(),比如對(duì)于同一個(gè)元素的不同操作:

          var width=parseInt($('#test').css('width'));
          if(width > 20) {
            $('#test').css('backgroundColor', 'red');
          }
          

          通過(guò)我們上面的一系列分析,我們知道每當(dāng)我們執(zhí)行$()時(shí),就會(huì)重新生成一個(gè)init的實(shí)例對(duì)象,因此當(dāng)我們這樣沒(méi)有節(jié)制的使用jQuery是非常不正確的,雖然看上去方便了一些,但是對(duì)于內(nèi)存的消耗非常大。正確的做法是既然是同一個(gè)對(duì)象,那么就用一個(gè)變量保存起來(lái)后續(xù)使用即可。

          var $test=$('#test');
          var width=parseInt($test.css('width'));
          if(width > 20) {
            $test.css('backgroundColor', 'red');
          }
          

          3

          擴(kuò)展方法分析

          在上面的代碼實(shí)現(xiàn)中,我還簡(jiǎn)單實(shí)現(xiàn)了兩個(gè)擴(kuò)展方法。

          jQuery.extend=jQuery.fn.extend=function (options) {
          
            // 在jquery源碼中會(huì)根據(jù)參數(shù)不同進(jìn)行很多判斷,我們這里就直接走一種方式,所以就不用判斷了
            var target=this;
            var copy;
          
            for (name in options) {
              copy=options[name];
              target[name]=copy;
            }
            return target;
          }
          

          要理解它的實(shí)現(xiàn),首先要明確知道this的指向。如果你搞不清楚,可以回頭去看看我們之前關(guān)于this指向的講解。

          傳入的參數(shù)options為一個(gè)key: value模式的對(duì)象,我通過(guò)for in遍歷options,將key作為jQuery的新屬性,value作為該新屬性所對(duì)應(yīng)的新方法,分別添加到j(luò)Query方法和jQuery.fn中。

          也就是說(shuō),當(dāng)我們通過(guò)jQuery.extend擴(kuò)展jQuery時(shí),方法被添加到了jQuery構(gòu)造函數(shù)中,而當(dāng)我們通過(guò)jQuery.fn.extend擴(kuò)展jQuery時(shí),方法被添加到了jQuery原型中。

          上面的例子中,我也簡(jiǎn)單展示了在jQuery內(nèi)部,許多方法的實(shí)現(xiàn)都是通過(guò)這兩個(gè)擴(kuò)展方法來(lái)完成的。

          當(dāng)我們通過(guò)上面的知識(shí)了解了jQuery的大體框架之后,我們對(duì)于jQuery的學(xué)習(xí)就可以具體到諸如css/val/attr等方法是如何實(shí)現(xiàn)這樣的程度,那么源碼學(xué)習(xí)起來(lái)就會(huì)輕松很多,節(jié)省更多的時(shí)間。也給一些對(duì)于源碼敬而遠(yuǎn)之的朋友提供一個(gè)學(xué)習(xí)的可能。

          4

          有一個(gè)朋友留言給我,說(shuō)她被靜態(tài)方法,工具方法和實(shí)例方法這幾個(gè)概念困擾了很久,到底他們有什么區(qū)別?

          其實(shí)在上一篇文章中,關(guān)于封裝一個(gè)對(duì)象,我跟大家分享了一個(gè)非常非常干,但是卻只有少數(shù)幾個(gè)讀者大佬g(shù)et到的知識(shí),那就是在封裝對(duì)象時(shí),屬性和方法可以具體放置的三個(gè)位置,并且對(duì)于這三個(gè)位置的不同做了一個(gè)詳細(xì)的解讀。

          image.png

          在實(shí)現(xiàn)jQuery擴(kuò)展方法時(shí),一部分方法需要擴(kuò)展到構(gòu)造函數(shù)中,一部分方法需要擴(kuò)展到原型中,當(dāng)我們通讀jQuery源碼時(shí),還發(fā)現(xiàn)有一些方法放在了模塊作用域中,至于為什么會(huì)有這樣的區(qū)別,建議大家回過(guò)頭去讀讀前一篇文章。

          這里用一個(gè)例子簡(jiǎn)單區(qū)分一下。

          // 模塊內(nèi)部
          const a=20;
          
          function Person(name, age) {
            this.name=name;
            this.age=age;
            // 構(gòu)造函數(shù)方法,每聲明一個(gè)實(shí)例,都會(huì)重新創(chuàng)建一次,屬于實(shí)例獨(dú)有
            this.getName=function() {
              return this.name;
            }
          }
          
          // 原型方法,僅在原型創(chuàng)建時(shí)聲明一次,屬于所有實(shí)例共享
          Person.prototype.getAge=function() {
            return this.age;
          }
          
          // 工具方法,直接掛載在構(gòu)造函數(shù)名上,僅聲明一次,無(wú)法直接訪問(wèn)實(shí)例內(nèi)部屬性與方法
          Person.each=function() {}
          

          如上例中,each就是一個(gè)工具方法,或者說(shuō)靜態(tài)方法。

          工具方法的特性也和工具一詞非常貼近,他們與實(shí)例的自身屬性毫無(wú)關(guān)聯(lián),僅僅只是實(shí)現(xiàn)一些通用的功能,我們可以通過(guò)$.each與$('div').each這2個(gè)方法來(lái)體會(huì)工具方法與實(shí)例方法的不同之處。

          在實(shí)際開(kāi)發(fā)中,我們運(yùn)用得非常多的一個(gè)工具庫(kù)就是lodash.js,大家如果時(shí)間充裕一定要去學(xué)習(xí)一下他的使用。

          $.ajax()
          $.isFunction()
          $.each()
          ... ...
          

          放在原型中的方法,在使用時(shí)必須創(chuàng)建了一個(gè)新的實(shí)例對(duì)象才能訪問(wèn),因此這樣的方法叫做實(shí)例方法。也正是因?yàn)檫@一點(diǎn),他的使用成本會(huì)比工具方法高一些。但是相比構(gòu)造函數(shù)方法,原型方法更節(jié)省內(nèi)存。

          $('#test').css()
          $('#test').attr()
          $('div').each()
          

          這樣,那位同學(xué)的疑問(wèn)就被搞定啦。我們?cè)趯W(xué)習(xí)的時(shí)候,一定不要過(guò)分去糾結(jié)一些概念,而要明白這些概念背后的具體場(chǎng)景是怎么回事兒,那么學(xué)習(xí)這件事情就不會(huì)在一些奇奇怪怪的地方卡住了。

          所以通過(guò)$.extend擴(kuò)展的方法,其實(shí)就是對(duì)工具方法的擴(kuò)展,而通過(guò)$.fn.extend擴(kuò)展的方法,就是對(duì)于實(shí)例方法的擴(kuò)展。

          5

          jQuery插件的實(shí)現(xiàn)

          我在初級(jí)階段時(shí),覺(jué)得要自己編寫(xiě)一個(gè)jQuery插件是超級(jí)高大上的事情,可望不可即。但是通過(guò)對(duì)于上面的理解,我就知道擴(kuò)展jQuery插件其實(shí)是一件我們自己也可以完成的事情。

          在前面我跟大家分享了jQuery如何實(shí)現(xiàn),以及他們的方法如何擴(kuò)展,并且前一篇文章分享了拖拽對(duì)象的具體實(shí)現(xiàn)。所以建議大家暫時(shí)不要閱讀下去,自己動(dòng)手嘗試將拖拽擴(kuò)展成為jQuery的一個(gè)實(shí)例方法,這就是一個(gè)jQuery插件了。

          具體也沒(méi)有什么可多說(shuō)的了,大家看了代碼就可以明白一切。

          // Drag對(duì)象簡(jiǎn)化代碼,完整源碼可在上一篇文章中查看
          ;
          (function () {
          
            // 構(gòu)造
            function Drag(selector) { }
          
          
            // 原型
            Drag.prototype={
              constructor: Drag,
          
              init: function () {
                // 初始時(shí)需要做些什么事情
                this.setDrag();
              },
          
              // 稍作改造,僅用于獲取當(dāng)前元素的屬性,類(lèi)似于getName
              getStyle: function (property) { },
          
              // 用來(lái)獲取當(dāng)前元素的位置信息,注意與之前的不同之處
              getPosition: function () { },
          
              // 用來(lái)設(shè)置當(dāng)前元素的位置
              setPostion: function (pos) { },
          
              // 該方法用來(lái)綁定事件
              setDrag: function () { }
            }
          
            // 一種對(duì)外暴露的方式
            window.Drag=Drag;
          })();
          
          // 通過(guò)擴(kuò)展方法將拖拽擴(kuò)展為jQuery的一個(gè)實(shí)例方法
          (function ($) {
            $.fn.extend({
              becomeDrag: function () {
                new Drag(this[0]);
                return this;   // 注意:為了保證jQuery所有的方法都能夠鏈?zhǔn)皆L問(wèn),每一個(gè)方法的最后都需要返回this,即返回jQuery實(shí)例
              }
            })
          })(jQuery);
          

          下一篇:前端基礎(chǔ)進(jìn)階(十四):深入核心,詳解事件循環(huán)機(jī)制

          建議收藏,不然刷著刷著就可能找不到了。

          有什么前端的問(wèn)題歡迎私信我~期待你的到來(lái)。

          我自己是一名從事了多年開(kāi)發(fā)的web前端老程序員,目前辭職在做自己的web前端私人定制課程,今年我花了一個(gè)月整理了一份最適合2020年學(xué)習(xí)的web前端學(xué)習(xí)干貨,各種框架都有整理,送給每一位前端小伙伴,想要獲取的可以關(guān)注我的頭條號(hào)并在后臺(tái)私信我:前端,即可免費(fèi)獲取

          i,大家好,我是拾光。

          今天給大家?guī)?lái)的是js實(shí)現(xiàn)文本框自動(dòng)填充。

          下面貼圖:

          HTML:

          <!doctype html>

          <html>

          <head>

          <meta charset="UTF-8">

          <title>Document</title>

          <script src="jquery-1.8.3.min.js"></script>

          <style>

          *{

          margin:0;

          padding:0;

          }

          ul,li{

          list-style:none;

          }

          .inputElem {

          width:198px;

          height:22px;

          line-height:22px;

          border:1px solid #ff4455;

          }

          .parentCls

          {

          width:200px;

          }

          .auto-tip li

          {

          width:100%;

          height:22px;

          line-height:22px;

          font-size:14px;

          }

          .auto-tip li.hoverBg{

          background:#ddd;

          cursor:pointer;

          }

          .red

          {

          color:red;

          }

          .hidden {

          display:none;

          }

          </style>

          <script src="emailAutoComplete.js"></script>

          </head>

          <body>

          <div>

          <input type="text">

          </div>

          </body>

          </html>

          JS:

          function EmailAutoComplete(options) {

          this.config={

          targetCls : '.inputElem',

          parentCls : '.parentCls',

          hiddenCls : '.hiddenCls',

          searchForm : '.jqtransformdone',

          hoverBg : 'hoverBg',

          inputValColor : 'red',

          mailArr : ["@qq.com","@qq2.com","@gmail.com","@126.com","@163.com","@hotmail.com","@yahoo.com","@yahoo.com.cn","@live.com","@sohu.com","@sina.com"],

          isSelectHide : true,

          callback : null

          };

          this.cache={

          onlyFlag : true,

          currentIndex : -1,

          oldIndex : -1

          };

          this.init(options);

          }

          EmailAutoComplete.prototype={

          constructor: EmailAutoComplete,

          init: function(options){

          this.config=$.extend(this.config,options || {});

          var self=this,

          _config=self.config,

          _cache=self.cache;

          $(_config.targetCls).each(function(index,item){

          $(item).keyup(function(e){

          var target=e.target,

          targetVal=$.trim($(this).val()),

          keycode=e.keyCode,

          elemHeight=$(this).outerHeight(),

          elemWidth=$(this).outerWidth(),

          parentNode=$(this).closest(_config.parentCls);

          $(parentNode).css({'position':'relative'});

          if(targetVal=='') {

          $(item).attr({'data-html':''});

          $(_config.hiddenCls,parentNode).val('');

          _cache.currentIndex=-1;

          _cache.oldIndex=-1;

          $(".auto-tip",parentNode) && !$(".auto-tip",parentNode).hasClass('hidden') && $(".auto-tip",parentNode).addClass('hidden');

          self._removeBg(parentNode);

          }else {

          $(item).attr({'data-html':targetVal});

          $(_config.hiddenCls,parentNode).val(targetVal);

          $(".auto-tip",parentNode) && $(".auto-tip",parentNode).hasClass('hidden') && $(".auto-tip",parentNode).removeClass('hidden');

          self._renderHTML({keycode:keycode,e:e,target:target,targetVal:targetVal,height:elemHeight,width:elemWidth,parentNode:parentNode});

          }

          });

          });

          $(_config.searchForm).each(function(index,item) {

          $(item).keydown(function(e){

          var keyCode=e.keyCode;

          if(keyCode==13) {

          return false;

          }

          });

          });

          $(document).click(function(e){

          e.stopPropagation();

          var target=e.target,

          tagCls=_config.targetCls.replace(/^\./,'');

          if(!$(target).hasClass(tagCls)) {

          $('.auto-tip') && $('.auto-tip').each(function(index,item){

          !$(item).hasClass('hidden') && $(item).addClass('hidden');

          });

          }

          });

          },

          _renderHTML: function(cfg) {

          var self=this,

          _config=self.config,

          _cache=self.cache,

          curVal;

          var curIndex=self._keyCode(cfg.keycode);

          $('.auto-tip',cfg.parentNode).hasClass('hidden') && $('.auto-tip',cfg.parentNode).removeClass('hidden');

          if(curIndex > -1){

          self._keyUpAndDown(cfg.targetVal,cfg.e,cfg.parentNode);

          }else {

          if(/@/.test(cfg.targetVal)) {

          curVal=cfg.targetVal.replace(/@.*/,'');

          }else {

          curVal=cfg.targetVal;

          }

          if(_cache.onlyFlag) {

          $(cfg.parentNode).append('<input type="hidden" class="hiddenCls"/>');

          var wrap='<ul class="auto-tip">';

          for(var i=0; i < _config.mailArr.length; i++) {

          wrap +='<li class="p-index'+i+'">'+'<span class="output-num"></span><em class="em" data-html="'+_config.mailArr[i]+'">'+_config.mailArr[i]+'</em></li>';

          }

          wrap +='</ul>';

          _cache.onlyFlag=false;

          $(cfg.parentNode).append(wrap);

          $('.auto-tip',cfg.parentNode).css({'position':'absolute','top':cfg.height,'width':cfg.width - 2 + 'px','left':0,

          'border':'1px solid #ccc','z-index':10000});

          }

          $('.auto-tip li',cfg.parentNode).each(function(index,item){

          $('.output-num',item).html(curVal);

          !$('.output-num',item).hasClass(_config.inputValColor) &&

          $('.output-num',item).addClass(_config.inputValColor);

          var emVal=$.trim($('.em',item).attr('data-html'));

          $(item).attr({'data-html':curVal + '' +emVal});

          });

          self._accurateMate({target:cfg.target,parentNode:cfg.parentNode});

          self._itemHover(cfg.parentNode);

          self._executeClick(cfg.parentNode);

          }

          },

          _accurateMate: function(cfg) {

          var self=this,

          _config=self.config,

          _cache=self.cache;

          var curVal=$.trim($(cfg.target,cfg.parentNode).attr('data-html')),

          newArrs=[];

          if(/@/.test(curVal)) {

          var prefix=curVal.replace(/@.*/, ""),

          suffix=curVal.replace(/.*@/, "");

          $.map(_config.mailArr,function(n){

          var reg=new RegExp(suffix);

          if(reg.test(n)) {

          newArrs.push(n);

          }

          });

          if(newArrs.length > 0) {

          $('.auto-tip',cfg.parentNode).html('');

          $(".auto-tip",cfg.parentNode) && $(".auto-tip",cfg.parentNode).hasClass('hidden') &&

          $(".auto-tip",cfg.parentNode).removeClass('hidden');

          var html='';

          for(var j=0, jlen=newArrs.length; j < jlen; j++) {

          html +='<li class="p-index'+j+'">'+'<span class="output-num"></span><em class="em" data-html="'+newArrs[j]+'">'+newArrs[j]+'</em></li>';

          }

          $('.auto-tip',cfg.parentNode).html(html);

          $('.auto-tip li',cfg.parentNode).each(function(index,item){

          $('.output-num',item).html(prefix);

          !$('.output-num',item).hasClass(_config.inputValColor) &&

          $('.output-num',item).addClass(_config.inputValColor);

          var emVal=$.trim($('.em',item).attr('data-html'));

          $(item).attr('data-html','');

          $(item).attr({'data-html':prefix + '' +emVal});

          });

          _cache.currentIndex=-1;

          _cache.oldIndex=-1;

          $('.auto-tip .output-num',cfg.parentNode).html(prefix);

          self._itemHover(cfg.parentNode);

          self._executeClick(cfg.parentNode);

          }else {

          $(".auto-tip",cfg.parentNode) && !$(".auto-tip",cfg.parentNode).hasClass('hidden') &&

          $(".auto-tip",cfg.parentNode).addClass('hidden');

          $('.auto-tip',cfg.parentNode).html('');

          }

          }

          },

          _itemHover: function(parentNode) {

          var self=this,

          _config=self.config,

          _cache=self.cache;

          $('.auto-tip li',parentNode).hover(function(index,item) {

          !$(this).hasClass(_config.hoverBg) && $(this).addClass(_config.hoverBg);

          },function() {

          $(this).hasClass(_config.hoverBg) && $(this).removeClass(_config.hoverBg);

          });

          },

          _removeBg: function(parentNode){

          var self=this,

          _config=self.config;

          $(".auto-tip li",parentNode).each(function(index,item){

          $(item).hasClass(_config.hoverBg) && $(item).removeClass(_config.hoverBg);

          });

          },

          _keyUpAndDown: function(targetVal,e,parentNode) {

          var self=this,

          _cache=self.cache,

          _config=self.config;

          if($('.auto-tip' + ' li',parentNode) && $('.auto-tip' + ' li').length > 0) {

          var plen=$('.auto-tip' + ' li',parentNode).length,

          keyCode=e.keyCode;

          _cache.oldIndex=_cache.currentIndex;

          if(keyCode==38) {

          if(_cache.currentIndex==-1) {

          _cache.currentIndex=plen - 1;

          }else {

          _cache.currentIndex=_cache.currentIndex - 1;

          if(_cache.currentIndex < 0) {

          _cache.currentIndex=plen - 1;

          }

          }

          if(_cache.currentIndex !==-1) {

          !$('.auto-tip .p-index'+_cache.currentIndex,parentNode).hasClass(_config.hoverBg) &&

          $('.auto-tip .p-index'+_cache.currentIndex,parentNode).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);

          var curAttr=$('.auto-tip' + ' .p-index'+_cache.currentIndex,parentNode).attr('data-html');

          $(_config.targetCls,parentNode).val(curAttr);

          $(_config.hiddenCls,parentNode).val(curAttr);

          }

          }else if(keyCode==40) {

          if(_cache.currentIndex==plen - 1) {

          _cache.currentIndex=0;

          }else {

          _cache.currentIndex++;

          if(_cache.currentIndex > plen - 1) {

          _cache.currentIndex=0;

          }

          }

          if(_cache.currentIndex !==-1) {

          !$('.auto-tip .p-index'+_cache.currentIndex,parentNode).hasClass(_config.hoverBg) &&

          $('.auto-tip .p-index'+_cache.currentIndex,parentNode).addClass(_config.hoverBg).siblings().removeClass(_config.hoverBg);

          var curAttr=$('.auto-tip' + ' .p-index'+_cache.currentIndex,parentNode).attr('data-html');

          $(_config.targetCls,parentNode).val(curAttr);

          $(_config.hiddenCls,parentNode).val(curAttr);

          }

          }else if(keyCode==13) {

          var curVal=$('.auto-tip' + ' .p-index'+_cache.oldIndex,parentNode).attr('data-html');

          $(_config.targetCls,parentNode).val(curVal);

          $(_config.hiddenCls,parentNode).val(curVal);

          if(_config.isSelectHide) {

          !$(".auto-tip",parentNode).hasClass('hidden') && $(".auto-tip",parentNode).addClass('hidden');

          }

          _config.callback && $.isFunction(_config.callback) && _config.callback();

          _cache.currentIndex=-1;

          _cache.oldIndex=-1;

          }

          }

          },

          _keyCode: function(code) {

          var arrs=['17','18','38','40','37','39','33','34','35','46','36','13','45','44','145','19','20','9'];

          for(var i=0, ilen=arrs.length; i < ilen; i++) {

          if(code==arrs[i]) {

          return i;

          }

          }

          return -1;

          },

          _executeClick: function(parentNode) {

          var _self=this,

          _config=_self.config;

          $('.auto-tip' + ' li',parentNode).unbind('click');

          $('.auto-tip' + ' li',parentNode).bind('click',function(e){

          var dataAttr=$(this).attr('data-html');

          $(_config.targetCls,parentNode).val(dataAttr);

          if(_config.isSelectHide) {

          !$(".auto-tip",parentNode).hasClass('hidden') && $(".auto-tip",parentNode).addClass('hidden');

          }

          $(_config.hiddenCls,parentNode).val(dataAttr);

          _config.callback && $.isFunction(_config.callback) && _config.callback();

          });

          }

          };

          $(function() {

          new EmailAutoComplete({});

          });

          今天就到這里咯~

          大家研究一下吧~

          希望大家過(guò)的愉快。

          Best wishes to you.

          LiuDongYu.


          主站蜘蛛池模板: 中文字幕一区二区三区久久网站 | 无码少妇精品一区二区免费动态| 久久久国产精品一区二区18禁| 国产主播在线一区| 东京热无码av一区二区| 一区二区三区在线免费观看视频| 性色AV一区二区三区天美传媒| 国产精品一区二区不卡| 亚洲国产高清在线精品一区| 日韩精品一区二区三区中文| 夜色福利一区二区三区| 无码欧精品亚洲日韩一区| 国产视频一区二区在线播放| 亚洲一区二区三区无码中文字幕| 中文字幕在线观看一区二区 | 性色AV 一区二区三区| 无码日韩AV一区二区三区| 国产日韩精品一区二区三区 | 亚洲av成人一区二区三区在线播放| 国产一区二区三区在线观看精品| 国产精品一区视频| 麻豆AV一区二区三区久久| 亚洲狠狠狠一区二区三区| 无码少妇丰满熟妇一区二区 | 国产精品一区二区av不卡| 亚洲性日韩精品一区二区三区| 国偷自产av一区二区三区| 亚洲一区二区三区国产精华液| 国产一区内射最近更新| 一区二区三区国产精品 | 国产午夜三级一区二区三| 成人免费区一区二区三区| 国产精品无圣光一区二区 | 无码人妻精品一区二区三区9厂 | 久久国产一区二区三区| 精品欧洲av无码一区二区14| 国产成人久久一区二区不卡三区| 日韩精品一区二区三区老鸦窝| 一区二区高清在线| 亚洲爆乳无码一区二区三区| 久久无码AV一区二区三区|