从爬虫到数据可视化(1)—猎聘网


学习python爬虫有一段时间了,今天先拿猎聘网的上海公司数据练练手,并做一点数据分析,分享给大家。

一、数据获取

1、爬虫思路

①首先找到上海公司列表页面 https://www.liepin.com/company/020-000/
②由于该页面最多显示100页,所以要分行业爬取,分行业没有超过100页的了。
③获取各行业页面的网址。
④对每一个行业页面进行翻页,这样就已经得到上海公司的所有页面。
⑤再从这些页面中获取所有公司详情页的网址。
⑥对详情页进行解析获取到各公司的详细数据。

2、scrapy爬虫

4个函数分别对应后四个步骤,这里用到User-Agent随机切换,没用代理,共11548条数据用时35分钟左右
Spider模块代码如下(其他模块基本没用):

# -*- coding: utf-8 -*-

import scrapy
import requests
from bs4 import BeautifulSoup
from lxml import etree
import re
import random
import time
from LiePinWang.items import LiepinwangItem
import json

hds=[{'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'},\
    {'User-Agent':'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.12 Safari/535.11'},\
    {'User-Agent':'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)'},\
    {'User-Agent':'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:34.0) Gecko/20100101 Firefox/34.0'},\
    {'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/44.0.2403.89 Chrome/44.0.2403.89 Safari/537.36'},\
    {'User-Agent':'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50'},\
    {'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50'},\
    {'User-Agent':'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0'},\
    {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1'},\
    {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1'},\
    {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11'},\
    {'User-Agent':'Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11'},\
    {'User-Agent':'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11'}]

class LiepinSpider(scrapy.Spider):
    name = "liepin"


    def start_requests(self):
        href_list = []
        url = 'https://www.liepin.com/company/020-000/'
        req = requests.get(url).text
        soup = BeautifulSoup(req,'lxml')
        hrefs_1 = soup.select('#region > div.wrap > div.top-bar > div.industry-box > div > a')
        for href_1 in hrefs_1:
            href_list.append(href_1['href'])
        href_list.pop()
        hrefs_2 = soup.select('#region > div.wrap > div.top-bar > div.industry-box > div > div > a')
        for href_2 in hrefs_2:
            href_list.append(href_2['href'])
        href_list.pop()
        for industry_href in href_list[1:]:
            yield scrapy.Request(url = industry_href,callback=self.next_page)

    def next_page(self,response):
        base_url = response.url
        req = requests.get(base_url,headers=hds[random.randint(0,len(hds)-1)]).text
        pages = re.findall('<span.*?"addition">(.*?)<span.*?"redirect">',req,re.S)[0].replace('共','').replace('页','')
        if pages:
            for i in range(0,int(pages)):
                urls = str(base_url) + 'pn' + str(i)
                yield scrapy.Request(url = urls ,callback=self.get_company_url)
        else:
            yield scrapy.Request(url = base_url ,callback=self.get_company_url)

    def get_company_url(self,response):
        url = response.url
        req = requests.get(url,headers=hds[random.randint(0,len(hds)-1)]).text
        soup = BeautifulSoup(req,'lxml')
        company_urls = soup.select('#region > div.wrap > div.company-list.clearfix > div > div.item-top.clearfix > div > p.company-name > a')
        for company_url in company_urls:
            detail_url = company_url['href']
            yield scrapy.Request(url = detail_url ,callback=self.parse_detail)

    def parse_detail(self,response):
        url = response.url
        try:
            item = LiepinwangItem()
            req = requests.get(url,headers=hds[random.randint(0,len(hds)-1)]).text
            selector = etree.HTML(req)


            item['companyname'] = selector.xpath('//*[@id="company"]/div[2]/section/div/h1/text()')[0] if selector.xpath('//*[@id="company"]/div[2]/section/div/h1/text()') else None
            position = selector.xpath('//*[@id="company"]/div[2]/div/div/div[2]/h2/small/text()')[0] if selector.xpath('//*[@id="company"]/div[2]/div/div/div[2]/h2/small/text()') else None
            item['position_total'] = re.sub("\D", "", position)
            item['welfares'] = selector.xpath('//*[@id="company"]/div[2]/section/div/div/ul/li/text()') if selector.xpath('//*[@id="company"]/div[2]/section/div/div/ul/li/text()') else None
            item['industry'] = selector.xpath('//*[@id="company"]/div[2]/div/aside/div[2]/ul[1]/li[1]/a/text()')[0] if selector.xpath('//*[@id="company"]/div[2]/div/aside/div[2]/ul[1]/li[1]/a/text()') else None
            item['companysize'] = selector.xpath('//*[@id="company"]/div[2]/div/aside/div[2]/ul[1]/li[2]/text()')[0] if selector.xpath('//*[@id="company"]/div[2]/div/aside/div[2]/ul[1]/li[2]/text()') else None
            item['address'] = selector.xpath('//*[@id="company"]/div[2]/div/aside/div[2]/ul[1]/li[3]/text()')[0] if selector.xpath('//*[@id="company"]/div[2]/div/aside/div[2]/ul[1]/li[3]/text()') else None
            item['poi'] = selector.xpath('//*[@id="company"]/div[2]/div/aside/div[2]/ul[1]/li[3]/@data-point')[0] if selector.xpath('//*[@id="company"]/div[2]/div/aside/div[2]/ul[1]/li[3]/@data-point') else None
            item['time'] = selector.xpath('//*[@id="company"]/div[2]/div/aside/div[2]/ul[2]/li[2]/text()')[0] if selector.xpath('//*[@id="company"]/div[2]/div/aside/div[2]/ul[2]/li[2]/text()') else None
            item['capital'] = selector.xpath('//*[@id="company"]/div[2]/div/aside/div[2]/ul[2]/li[3]/text()')[0] if selector.xpath('//*[@id="company"]/div[2]/div/aside/div[2]/ul[2]/li[3]/text()') else None
            item['field'] = selector.xpath('//*[@id="company"]/div[2]/div/aside/div[2]/ul[1]/li[1]/text()')[0].strip() if selector.xpath('//*[@id="company"]/div[2]/div/aside/div[2]/ul[1]/li[1]/text()') else None
            yield item 
        except Exception:
            pass

由于数据量不大,爬取到的数据保存成csv格式就可以了,然后再把csv转换为Excel格式,方便做数据清洗和分析。

二、数据清洗

1、编号,方便做数据统计。
2、对异常数据进行清洗,数据格式统一。
3、坐标转换,猎聘网使用的是火星坐标系,所以要转换为WGS84地球坐标系,方便做分析,这里用到的是别人写好的代码,地址https://github.com/wandergis/coordTransform_py
4、通过QGIS软件匹配出个公司所在的行政区和街镇(区域)。
5、在猎聘网找到行业分类的数据,对每个行业归为13大类。
清洗之后,大概长这样:

三、数据分析及可视化

1、各行业公司数量及占比

  • 仅在猎聘网上,公司最多的行业为互联网/游戏/软件,占比25.5%,达到了上海公司的1/4以上,上海的互联网公司数量虽然跟北京没法比,但依然是占比最高的。
  • 紧随其后的就是金融行业,上海作为中国的金融中心,金融行业肯定不会少。
  • 第三位是房地产/建筑/物业,上海的房价在全国都是数一数二的,房地产建筑行业也不会少。

2、各规模的公司数量

  • 100-499人的中小型企业最多,达到了3673家,其次是1-49人和50-99人的小型企业。

3、公司福利


  • 提到福利,我脑海中就浮现出了苍老师的形象,这里用的是PPT大神阿文推荐的wordart,https://wordart.com/create
  • 福利排名前几位的是:五险一金、带薪年假、绩效奖金、岗位晋升,很显然,都是跟钱和假期有关的。
  • 由于每个公司福利数据较多,要先将福利数据在Python进行处理,并统计一下,这个比较简单,代码就不放了。

4、各街镇公司数量

  • 各区域中,公司数量最多的是陆家嘴537家,上海金融圈中心,其次是张江481家,上海程序猿最多的地方,第三位是虹梅路409家,为了探寻一下这些公司多的区域的行业占比,再进一步把各区域和行业进行交叉分析。
  • 结果显示,陆家嘴近6成的公司都是金融公司,而互联网/游戏/软件公司占比较低。
  • 张江的互联网/游戏/软件公司占比为47%,第三名的虹梅路互联网/游戏/软件公司占比同样是47%,其他行业构成也和张江近似。
  • 通过上图我们还发现,潍坊新村和花木的金融公司占比也很高,达到了40%以上,通过观察地图发现,这两个区域离陆家嘴较近,所以可能是受陆家嘴影响,金融公司也很多。

5、各街镇的密度

有些区域虽然公司多,但是面积也很大,并不能说明该区域的公司很密集,所以这里引入一个是新的指标:单位面积的密度,来看看到底哪里的公司最密集。

单位面积的密度=各街镇中公司数量/各街镇的面积
  • 密度前三位的是南京西路,淮海西路和南京东路,这几个区域虽然很小,但是写字楼比较多,大多数都是中小型企业,一个写字楼可能有几十家或者上百家公司,例如:南京西路区域虽然只有1.6平方公里,但是有195家公司,所以密度很大。

感谢您有耐心看到这里,如果您觉得有趣或者有用,请点个赞,有任何疑问可以在下方留言。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,757评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,478评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,540评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,593评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,903评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,329评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,659评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,383评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,055评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,337评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,864评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,227评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,820评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,999评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,750评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,365评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,260评论 2 258

推荐阅读更多精彩内容