资讯专栏INFORMATION COLUMN

?Echarts统计拉勾网招聘信息(scrapy 爬取)

Jingbin_ / 7289人阅读

摘要:因为本人在成都从事前端,所以这次爬取的关键词既是成都,前端。仅仅有这个是不够的,因为貌似拉勾网有反爬虫,没有好像得不到数据这个还待论证,至少我这边是。

前言

今天是2018的第一天,首先祝各位小伙伴元旦快乐!
又到了新的一年,虽然离春节还有一段时间,但是程序狗打工不易啊,不关注薪资怎么行。今天要做的就是用图表统计一下现在各公司的薪资状况(虽然很多公司不能按照招聘上他们给的薪资来给)。

数据爬取

本次使用scrapy来做数据爬取,这是一个python的框架。因为本人在成都从事web前端,所以这次爬取的关键词既是:成都,web前端

scrapy startproject lagou

首先通过运行命令,得到一个爬虫项目的基础结构。

接着按照scrapy的中文教程,通过在

start_urls = [
        "https://www.lagou.com/jobs/list_web%E5%89%8D%E7%AB%AF?labelWords=sug&fromSearch=true&suginput=web"
    ]

spider中的start_urls配置好,应该就能把拉勾网页面拉取下来,然后再分析dom,提取字符串就可以了,无奈这种方法并不行。

起初也不知道,就用xpath一直找,后来发现找不到会报错,这些各种错误对于我这个爬虫萌新还是懵逼的。仔细查看他的network发现,他的招聘信息都是在另外的ajax请求当中,并且还是整理好的。

因为本人工作1年多,所以主要关注点是3年以下及3-5年,就提前选好了,城市和工作年限。该请求的传参是formdata,其中first是首页(其实写代码的时候并没有注意这个参数,所以一直传的是true,貌似也没什么影响),pn是当前页数,kd是关键词。

于是乎就去文档查阅了一下,如何在scrapy中循环发送formdata请求。最终得到这样一段可以执行的代码。

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是发送post请求的方法,FormRequest这个方法接收请求url,传递数据formdata,以及回调函数parseJson。parseJson在这里主要是接收获取的数据。

仅仅有这个是不够的,因为貌似拉勾网有反爬虫,没有header好像得不到数据(这个还待论证,至少我这边是)。然后再settings.py文件中做了一些配置,配置主要有:

请求的header(主要是这几项)

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(因为爬取到的中文是unicode字符)

FEED_EXPORT_ENCODING = "utf-8"

ROBOTSTXT_OBEY(这是一个爬虫机器的协议,如果是true,表示遵守,有些网站禁止爬取的话,这个如果是true就爬不到了)

ROBOTSTXT_OBEY = False

DOWNLOAD_DELAY(延时,这个也是去避免被反爬虫,我这边直接设置了比较长的时间,也没有去测试多少合适,因为不设置也是会报错的)

DOWNLOAD_DELAY = 10

基础的配置项配置完毕之后,就是写数据存储的模型了,因为我只想去简单统计一下,所以只存了薪资和工资这两个字段,想要统计更多的信息,就直接继续加就好了,这个比较简单,在items.py中编写

class LaGou(scrapy.Item):
    salary = scrapy.Field()
    company = scrapy.Field()

经过这几项配置,运行命令

scrapy crawl lagou -o a.json

就可以得到一份a.json,里面就是成都web前端相关,工作年限为0-5年的数据信息了。有了这份数据,接下来要做的就是数据处理了。

数据处理

在之前的a.json当中,大致可以得到一份之下的数据,总计195条

[
{"salary": "8k-16k", "company": "xx有限公司"},
......
]

为了前端处理方便,直接改为js文件加一个变量引入html,即

var a = [
    {"salary": "8k-16k", "company": "xx有限公司"},
    ......
    ]

这组数据的薪资是一个范围,不方便我统计,于是为了便于操作数据把薪资取平均值,并统计提供相同的薪资的公司数目。
js代码如下:

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变量

这段代码主要作用是把薪资范围计算成平均数,然后再统计数组中相同的平均数的个数。代码写的随意,可读性较差,见谅。这段代码处理过后,可得到类似如下数据:

{"8":1,"8.5":3}

key是薪资均值,value是个数。

于是将key,value分别存入数组。这里遇到一个问题,就是开始我是这样操作的

var xData=[...Object.keys(arr)]
var yData=[...Object.values(arr)]

这么做有一个问题就是浏览器对于对象的遍历规则,导致输出的数组,小数都到了最外边(比如这样[1,2,1.5]),这样在echarts下的图表是乱序的。也没有想到好的办法去解决,就是对数组进行一次排序,然后再根据排好的key生成相对应的value数组,最终代码:

    var xData = [...Object.keys(arr).sort(function (a, b) {
        return a - b
    })]
    var yData = xData.map(function (v) {
        return arr[v]
    })

echarts比较简单不赘述。将这两组横纵坐标输入echarts,得到最终效果:

总结

本次做这个统计很多地方没想清楚怎么更好的去表现,所以做的很简单,其实细致一点还可以去分类统计,按照公司融资情况,领域等等内容,只要数据拿到都好说。另外很多地方可能写的不够好,主要我目前也不太会写,比如之前反爬虫那块,貌似去做动态的用户代理也能行,但我还是增加了延时,选择了比较笨的方法。另外也不会python,但还好python比较好读。因为这一块才开始学习,相信以后会越写越好的,新的一年,加油!

update 2018/01/03

昨天又把爬虫优化了一下,去掉了之前的延时,增加了动态用户代理和动态IP代理,解决了之前爬虫的效率问题,也扩大了数据量。

动态IP代理

通过网上搜索免费的ip代理,获取了如下一组ip:

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过一段时间可能会失效,请自行搜索,如http://www.xicidaili.com/。
在middlewares.py中声明该IP,之后声明动态IP代理类

    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文件中声明该中间件

DOWNLOADER_MIDDLEWARES = {
    "scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware": 110,
    "tutorial.middlewares.ProxyMiddleware": 100,
}
动态用户代理

在middlewares.py中声明动态用户代理类

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 = {

"tutorial.middlewares.RandomUserAgent": 1,
"scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware": 110,
"tutorial.middlewares.ProxyMiddleware": 100,

}
再次运行scrapy crawl lagou,即可得到新的数据。

增加薪资筛选

在原有基础上增加了对于工作年限和公司规模的筛选,并计算了平均值。
更新代码如下:

// 指定图表的配置项和数据
initData();  
function initData() {
        average = 0;
        arr = temData.map(function (value) { //之前正则筛选字符串有点问题,没有考虑到有些公司格式为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)
    }

暂时这样,通过之后的学习,还会不断的优化。

展示效果:

源码地址:https://github.com/jiwenjiang...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90570.html

相关文章

  • ?Echarts统计勾网招聘信息scrapy 爬取

    摘要:因为本人在成都从事前端,所以这次爬取的关键词既是成都,前端。仅仅有这个是不够的,因为貌似拉勾网有反爬虫,没有好像得不到数据这个还待论证,至少我这边是。 前言 showImg(https://segmentfault.com/img/bV1g4S?w=700&h=490); 今天是2018的第一天,首先祝各位小伙伴元旦快乐!又到了新的一年,虽然离春节还有一段时间,但是程序狗打工不易啊,不...

    genefy 评论0 收藏0
  • Pyhton爬虫实战 - 抓取BOSS直聘职位描述 和 数据清洗

    摘要:然后准备再去抓下拉勾网的招聘数据,这也是个相对优秀的专业招聘网站了,数据也相当多,想当初找实习找正式工作,都是在这两个上找的,其他的网站几乎都没看。 原文地址:http://www.jtahstu.com/blog/s... Pyhton爬虫实战 - 抓取BOSS直聘职位描述 和 数据清洗 零、致谢 感谢BOSS直聘相对权威的招聘信息,使本人有了这次比较有意思的研究之旅。 由于爬虫持续...

    zhkai 评论0 收藏0
  • Pyhton爬虫实战 - 抓取BOSS直聘职位描述 和 数据清洗

    摘要:然后准备再去抓下拉勾网的招聘数据,这也是个相对优秀的专业招聘网站了,数据也相当多,想当初找实习找正式工作,都是在这两个上找的,其他的网站几乎都没看。 原文地址:http://www.jtahstu.com/blog/s... Pyhton爬虫实战 - 抓取BOSS直聘职位描述 和 数据清洗 零、致谢 感谢BOSS直聘相对权威的招聘信息,使本人有了这次比较有意思的研究之旅。 由于爬虫持续...

    Ocean 评论0 收藏0
  • 新手向-爬取分析勾网招聘信息

    摘要:爱写作者爱写前言看了很多网站,只发现获取拉勾网招聘信息是只用方式就可以得到,应当是非常简单了。在环境下运行通过数据爬取篇伪造浏览器访问拉勾网打开浏览器,进入拉勾网官网,右键检查,调出开发者模式。 [TOC] 爱写bug(ID:icodebugs)作者:爱写bug 前言: ​ 看了很多网站,只发现获取拉勾网招聘信息是只用post方式就可以得到,应当是非常简单了。推荐刚接触数据分析...

    yimo 评论0 收藏0
  • 使用php 爬取勾网 的php 招聘信息~

    摘要:拉勾网的爬虫还是有一定的难度的所以我们今天就爬取试一下其实并没有太大的难度只要我们用好分析一下请求就会其实没有什么难度上代码亲测可用拉钩代码 拉勾网的爬虫还是有一定的难度的 所以我们今天就爬取试一下 其实并没有太大的难度 只要我们用好network 分析一下请求 就会其实没有什么难度 上代码 2019-05-22 亲测可用 拉钩代码

    CoderDock 评论0 收藏0

发表评论

0条评论

Jingbin_

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<