摘要:因?yàn)楸救嗽诔啥紡氖虑岸耍赃@次爬取的關(guān)鍵詞既是成都,前端。僅僅有這個(gè)是不夠的,因?yàn)槊菜评淳W(wǎng)有反爬蟲,沒(méi)有好像得不到數(shù)據(jù)這個(gè)還待論證,至少我這邊是。
前言
今天是2018的第一天,首先祝各位小伙伴元旦快樂(lè)!
又到了新的一年,雖然離春節(jié)還有一段時(shí)間,但是程序狗打工不易啊,不關(guān)注薪資怎么行。今天要做的就是用圖表統(tǒng)計(jì)一下現(xiàn)在各公司的薪資狀況(雖然很多公司不能按照招聘上他們給的薪資來(lái)給)。
本次使用scrapy來(lái)做數(shù)據(jù)爬取,這是一個(gè)python的框架。因?yàn)楸救嗽诔啥紡氖聎eb前端,所以這次爬取的關(guān)鍵詞既是:成都,web前端。
</>復(fù)制代碼
scrapy startproject lagou
首先通過(guò)運(yùn)行命令,得到一個(gè)爬蟲項(xiàng)目的基礎(chǔ)結(jié)構(gòu)。
接著按照scrapy的中文教程,通過(guò)在
</>復(fù)制代碼
start_urls = [
"https://www.lagou.com/jobs/list_web%E5%89%8D%E7%AB%AF?labelWords=sug&fromSearch=true&suginput=web"
]
spider中的start_urls配置好,應(yīng)該就能把拉勾網(wǎng)頁(yè)面拉取下來(lái),然后再分析dom,提取字符串就可以了,無(wú)奈這種方法并不行。
起初也不知道,就用xpath一直找,后來(lái)發(fā)現(xiàn)找不到會(huì)報(bào)錯(cuò),這些各種錯(cuò)誤對(duì)于我這個(gè)爬蟲萌新還是懵逼的。仔細(xì)查看他的network發(fā)現(xiàn),他的招聘信息都是在另外的ajax請(qǐng)求當(dāng)中,并且還是整理好的。
因?yàn)楸救斯ぷ?年多,所以主要關(guān)注點(diǎn)是3年以下及3-5年,就提前選好了,城市和工作年限。該請(qǐng)求的傳參是formdata,其中first是首頁(yè)(其實(shí)寫代碼的時(shí)候并沒(méi)有注意這個(gè)參數(shù),所以一直傳的是true,貌似也沒(méi)什么影響),pn是當(dāng)前頁(yè)數(shù),kd是關(guān)鍵詞。
于是乎就去文檔查閱了一下,如何在scrapy中循環(huán)發(fā)送formdata請(qǐng)求。最終得到這樣一段可以執(zhí)行的代碼。
</>復(fù)制代碼
def start_requests(self):
url = "https://www.lagou.com/jobs/positionAjax.json?gj=3%E5%B9%B4%E5%8F%8A%E4%BB%A5%E4%B8%8B%2C3-5%E5%B9%B4&xl=%E6%9C%AC%E7%A7%91&px=default&city=%E6%88%90%E9%83%BD&needAddtionalResult=false&isSchoolJob=0"
for i in range(1, 14):
formdata = {"first": "true", "pn": str(i), "kd": "web前端"}
yield scrapy.FormRequest(str(url), callback=self.parseJson, formdata=formdata)
start_requests是發(fā)送post請(qǐng)求的方法,F(xiàn)ormRequest這個(gè)方法接收請(qǐng)求url,傳遞數(shù)據(jù)formdata,以及回調(diào)函數(shù)parseJson。parseJson在這里主要是接收獲取的數(shù)據(jù)。
僅僅有這個(gè)是不夠的,因?yàn)槊菜评淳W(wǎng)有反爬蟲,沒(méi)有header好像得不到數(shù)據(jù)(這個(gè)還待論證,至少我這邊是)。然后再settings.py文件中做了一些配置,配置主要有:
請(qǐng)求的header(主要是這幾項(xiàng))
</>復(fù)制代碼
DEFAULT_REQUEST_HEADERS={
Accept:application/json, text/javascript, */*; q=0.01
Host:www.lagou.com
Origin:https://www.lagou.com
Referer:https://www.lagou.com/jobs/list_web%E5%89%8D%E7%AB%AF?px=default&gj=3%E5%B9%B4%E5%8F%8A%E4%BB%A5%E4%B8%8B,3-5%E5%B9%B4&city=%E6%88%90%E9%83%BD
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
}
FEED_EXPORT_ENCODING(因?yàn)榕廊〉降闹形氖莡nicode字符)
</>復(fù)制代碼
FEED_EXPORT_ENCODING = "utf-8"
ROBOTSTXT_OBEY(這是一個(gè)爬蟲機(jī)器的協(xié)議,如果是true,表示遵守,有些網(wǎng)站禁止爬取的話,這個(gè)如果是true就爬不到了)
</>復(fù)制代碼
ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY(延時(shí),這個(gè)也是去避免被反爬蟲,我這邊直接設(shè)置了比較長(zhǎng)的時(shí)間,也沒(méi)有去測(cè)試多少合適,因?yàn)椴辉O(shè)置也是會(huì)報(bào)錯(cuò)的)
</>復(fù)制代碼
DOWNLOAD_DELAY = 10
基礎(chǔ)的配置項(xiàng)配置完畢之后,就是寫數(shù)據(jù)存儲(chǔ)的模型了,因?yàn)槲抑幌肴ズ?jiǎn)單統(tǒng)計(jì)一下,所以只存了薪資和工資這兩個(gè)字段,想要統(tǒng)計(jì)更多的信息,就直接繼續(xù)加就好了,這個(gè)比較簡(jiǎn)單,在items.py中編寫
</>復(fù)制代碼
class LaGou(scrapy.Item):
salary = scrapy.Field()
company = scrapy.Field()
經(jīng)過(guò)這幾項(xiàng)配置,運(yùn)行命令
</>復(fù)制代碼
scrapy crawl lagou -o a.json
就可以得到一份a.json,里面就是成都web前端相關(guān),工作年限為0-5年的數(shù)據(jù)信息了。有了這份數(shù)據(jù),接下來(lái)要做的就是數(shù)據(jù)處理了。
數(shù)據(jù)處理在之前的a.json當(dāng)中,大致可以得到一份之下的數(shù)據(jù),總計(jì)195條
</>復(fù)制代碼
[
{"salary": "8k-16k", "company": "xx有限公司"},
......
]
為了前端處理方便,直接改為js文件加一個(gè)變量引入html,即
</>復(fù)制代碼
var a = [
{"salary": "8k-16k", "company": "xx有限公司"},
......
]
這組數(shù)據(jù)的薪資是一個(gè)范圍,不方便我統(tǒng)計(jì),于是為了便于操作數(shù)據(jù)把薪資取平均值,并統(tǒng)計(jì)提供相同的薪資的公司數(shù)目。
js代碼如下:
</>復(fù)制代碼
var arr = data.map(function (value) {
return value.salary && value.salary.replace(/k|K/g, "").split("-").reduce(function (pV, nV) {
return pV + nV / 2
}, 0)
}).reduce(function (pV, nV) {
nV in pV ? pV[nV]++ : (pV[nV] = 1);
return pV;
}, {})
//這里的data既是上邊的a變量
這段代碼主要作用是把薪資范圍計(jì)算成平均數(shù),然后再統(tǒng)計(jì)數(shù)組中相同的平均數(shù)的個(gè)數(shù)。代碼寫的隨意,可讀性較差,見(jiàn)諒。這段代碼處理過(guò)后,可得到類似如下數(shù)據(jù):
</>復(fù)制代碼
{"8":1,"8.5":3}
key是薪資均值,value是個(gè)數(shù)。
于是將key,value分別存入數(shù)組。這里遇到一個(gè)問(wèn)題,就是開(kāi)始我是這樣操作的
</>復(fù)制代碼
var xData=[...Object.keys(arr)]
var yData=[...Object.values(arr)]
這么做有一個(gè)問(wèn)題就是瀏覽器對(duì)于對(duì)象的遍歷規(guī)則,導(dǎo)致輸出的數(shù)組,小數(shù)都到了最外邊(比如這樣[1,2,1.5]),這樣在echarts下的圖表是亂序的。也沒(méi)有想到好的辦法去解決,就是對(duì)數(shù)組進(jìn)行一次排序,然后再根據(jù)排好的key生成相對(duì)應(yīng)的value數(shù)組,最終代碼:
</>復(fù)制代碼
var xData = [...Object.keys(arr).sort(function (a, b) {
return a - b
})]
var yData = xData.map(function (v) {
return arr[v]
})
echarts比較簡(jiǎn)單不贅述。將這兩組橫縱坐標(biāo)輸入echarts,得到最終效果:
本次做這個(gè)統(tǒng)計(jì)很多地方?jīng)]想清楚怎么更好的去表現(xiàn),所以做的很簡(jiǎn)單,其實(shí)細(xì)致一點(diǎn)還可以去分類統(tǒng)計(jì),按照公司融資情況,領(lǐng)域等等內(nèi)容,只要數(shù)據(jù)拿到都好說(shuō)。另外很多地方可能寫的不夠好,主要我目前也不太會(huì)寫,比如之前反爬蟲那塊,貌似去做動(dòng)態(tài)的用戶代理也能行,但我還是增加了延時(shí),選擇了比較笨的方法。另外也不會(huì)python,但還好python比較好讀。因?yàn)檫@一塊才開(kāi)始學(xué)習(xí),相信以后會(huì)越寫越好的,新的一年,加油!
update 2018/01/03昨天又把爬蟲優(yōu)化了一下,去掉了之前的延時(shí),增加了動(dòng)態(tài)用戶代理和動(dòng)態(tài)IP代理,解決了之前爬蟲的效率問(wèn)題,也擴(kuò)大了數(shù)據(jù)量。
動(dòng)態(tài)IP代理通過(guò)網(wǎng)上搜索免費(fèi)的ip代理,獲取了如下一組ip:
</>復(fù)制代碼
PROXIES = [
{"ip_port": "106.39.179.244:80"},
{"ip_port": "65.52.223.99:80"},
{"ip_port": "1.52.248.207:3128"},
{"ip_port": "45.77.198.207:3128"},
{"ip_port": "177.125.119.16:8080"},
{"ip_port": "174.138.65.233:3128"},
]
該IP過(guò)一段時(shí)間可能會(huì)失效,請(qǐng)自行搜索,如http://www.xicidaili.com/。
在middlewares.py中聲明該IP,之后聲明動(dòng)態(tài)IP代理類
</>復(fù)制代碼
import random
class ProxyMiddleware(object):
def process_request(self, request, spider):
proxy = random.choice(PROXIES)
request.meta["proxy"] = "http://%s" % proxy["ip_port"]
print("**************ProxyMiddleware no pass************" + proxy["ip_port"])
在settings.py文件中聲明該中間件
</>復(fù)制代碼
DOWNLOADER_MIDDLEWARES = {
"scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware": 110,
"tutorial.middlewares.ProxyMiddleware": 100,
}
動(dòng)態(tài)用戶代理
在middlewares.py中聲明動(dòng)態(tài)用戶代理類
</>復(fù)制代碼
class RandomUserAgent(object):
"""Randomly rotate user agents based on a list of predefined ones"""
def __init__(self, agents):
self.agents = agents
@classmethod
def from_crawler(cls, crawler):
return cls(crawler.settings.getlist("USER_AGENTS"))
def process_request(self, request, spider):
# print "**************************" + random.choice(self.agents)
request.headers.setdefault("User-Agent", random.choice(self.agents))
同樣在settings.py的中間件里聲明
DOWNLOADER_MIDDLEWARES = {
</>復(fù)制代碼
"tutorial.middlewares.RandomUserAgent": 1,
"scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware": 110,
"tutorial.middlewares.ProxyMiddleware": 100,
}
再次運(yùn)行scrapy crawl lagou,即可得到新的數(shù)據(jù)。
在原有基礎(chǔ)上增加了對(duì)于工作年限和公司規(guī)模的篩選,并計(jì)算了平均值。
更新代碼如下:
</>復(fù)制代碼
// 指定圖表的配置項(xiàng)和數(shù)據(jù)
initData();
function initData() {
average = 0;
arr = temData.map(function (value) { //之前正則篩選字符串有點(diǎn)問(wèn)題,沒(méi)有考慮到有些公司格式為10k以上這種。
return value.salary && value.salary.replace(/[k|Ku4e00-u9fa5]/g, "").split("-").reduce(function (pV, nV, i, array) {
if (array.length > 1) {
average = Number(average) + pV + nV / 2
return pV + nV / 2
} else {
average = +average + Number(nV)
return nV
}
// return array.length > 1 ? pV + nV / 2 : nV
}, 0)
}).reduce(function (pV, nV) {
nV in pV ? pV[nV]++ : (pV[nV] = 1);
return pV;
}, {})
average = (average / temData.length).toFixed(2)
}
暫時(shí)這樣,通過(guò)之后的學(xué)習(xí),還會(huì)不斷的優(yōu)化。
展示效果:
源碼地址:https://github.com/jiwenjiang...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/90570.html
摘要:因?yàn)楸救嗽诔啥紡氖虑岸耍赃@次爬取的關(guān)鍵詞既是成都,前端。僅僅有這個(gè)是不夠的,因?yàn)槊菜评淳W(wǎng)有反爬蟲,沒(méi)有好像得不到數(shù)據(jù)這個(gè)還待論證,至少我這邊是。 前言 showImg(https://segmentfault.com/img/bV1g4S?w=700&h=490); 今天是2018的第一天,首先祝各位小伙伴元旦快樂(lè)!又到了新的一年,雖然離春節(jié)還有一段時(shí)間,但是程序狗打工不易啊,不...
摘要:然后準(zhǔn)備再去抓下拉勾網(wǎng)的招聘數(shù)據(jù),這也是個(gè)相對(duì)優(yōu)秀的專業(yè)招聘網(wǎng)站了,數(shù)據(jù)也相當(dāng)多,想當(dāng)初找實(shí)習(xí)找正式工作,都是在這兩個(gè)上找的,其他的網(wǎng)站幾乎都沒(méi)看。 原文地址:http://www.jtahstu.com/blog/s... Pyhton爬蟲實(shí)戰(zhàn) - 抓取BOSS直聘職位描述 和 數(shù)據(jù)清洗 零、致謝 感謝BOSS直聘相對(duì)權(quán)威的招聘信息,使本人有了這次比較有意思的研究之旅。 由于爬蟲持續(xù)...
摘要:然后準(zhǔn)備再去抓下拉勾網(wǎng)的招聘數(shù)據(jù),這也是個(gè)相對(duì)優(yōu)秀的專業(yè)招聘網(wǎng)站了,數(shù)據(jù)也相當(dāng)多,想當(dāng)初找實(shí)習(xí)找正式工作,都是在這兩個(gè)上找的,其他的網(wǎng)站幾乎都沒(méi)看。 原文地址:http://www.jtahstu.com/blog/s... Pyhton爬蟲實(shí)戰(zhàn) - 抓取BOSS直聘職位描述 和 數(shù)據(jù)清洗 零、致謝 感謝BOSS直聘相對(duì)權(quán)威的招聘信息,使本人有了這次比較有意思的研究之旅。 由于爬蟲持續(xù)...
摘要:愛(ài)寫作者愛(ài)寫前言看了很多網(wǎng)站,只發(fā)現(xiàn)獲取拉勾網(wǎng)招聘信息是只用方式就可以得到,應(yīng)當(dāng)是非常簡(jiǎn)單了。在環(huán)境下運(yùn)行通過(guò)數(shù)據(jù)爬取篇偽造瀏覽器訪問(wèn)拉勾網(wǎng)打開(kāi)瀏覽器,進(jìn)入拉勾網(wǎng)官網(wǎng),右鍵檢查,調(diào)出開(kāi)發(fā)者模式。 [TOC] 愛(ài)寫bug(ID:icodebugs)作者:愛(ài)寫bug 前言: ? 看了很多網(wǎng)站,只發(fā)現(xiàn)獲取拉勾網(wǎng)招聘信息是只用post方式就可以得到,應(yīng)當(dāng)是非常簡(jiǎn)單了。推薦剛接觸數(shù)據(jù)分析...
摘要:拉勾網(wǎng)的爬蟲還是有一定的難度的所以我們今天就爬取試一下其實(shí)并沒(méi)有太大的難度只要我們用好分析一下請(qǐng)求就會(huì)其實(shí)沒(méi)有什么難度上代碼親測(cè)可用拉鉤代碼 拉勾網(wǎng)的爬蟲還是有一定的難度的 所以我們今天就爬取試一下 其實(shí)并沒(méi)有太大的難度 只要我們用好network 分析一下請(qǐng)求 就會(huì)其實(shí)沒(méi)有什么難度 上代碼 2019-05-22 親測(cè)可用 拉鉤代碼
閱讀 2400·2021-11-12 10:34
閱讀 1475·2019-08-29 16:15
閱讀 2687·2019-08-29 15:17
閱讀 1347·2019-08-23 17:09
閱讀 395·2019-08-23 11:37
閱讀 2456·2019-08-23 10:39
閱讀 474·2019-08-22 16:43
閱讀 3114·2019-08-22 14:53