爬取拉勾职位信息和数据可视化(上)

2018-06-18 02:44:30 Python 阅读 (3785) 评论(0)

        利用Python语言采集拉勾网的Python职位信息,存到MySQL,然后利用PHP做数据可视化处理。本文主要是谈及Python爬虫部分,涉及到Python的requests,sqlalchemy,redis,lxml等库。


一.    需求分析

        把需要采集的职位信息和公司信息整理出来。由于我是把数据存到了MySQL,就用到了Python中非常出名的orm框架SQLAlchemy,所以就把需要采集的职位信息和公司信息的字段,存到models.py里了。

        从职位列表里获取职位的简要信息和职位对应公司的简要信息,然后再分别获取职位的详细信息和公司的详细信息。


二.    爬虫架构

        用requests请求接口获取职位的列表信息,列表信息里的positionId(职位id)和companyId(公司id)存到redis的集合里,集合能起到一个简单去重的功能。然后分别取职位集合和公司集合的id,构造相应的职位详情页的url和公司详情页的url,为了反爬虫,采用了selenium+Chrome(无头模式)采集详情页数据。


二.    代码实现    

        1. 职位列表数据

        拉勾网的职位信息,每个城市每个分类有很多页职位信息,每一页的数据是ajax动态获取的,所以就需要找到这个数据接口。

image.png

找到这个接口地址,去看这个请求的几个关键点,请求URL,请求方式,请求头和请求参数。找到这些信息后,就可以用超级好用的requests去构造请求获取数据了,其中请求参数里的pn是页码(第几页),kd是职位关键字

def get_job_company(self):
    fields = ["companyId", "companyShortName", "financeStage", "district", "companySize", "positionLables",
              "industryField", "positionId", "positionName", "createTime", "positionAdvantage", "salary",
              "workYear", "education", "city", "companyFullName"]
    url = 'https://www.lagou.com/jobs/positionAjax.json?city=%E4%B8%8A%E6%B5%B7&needAddtionalResult=false'
    for i in range(19):
        res = requests.post(url, data={'first': 'false', 'pn': str(i + 1), 'kd': 'Python'},
                            headers=self.headers).content.decode()
        res = json.loads(res)
        print(res)
        for job in res['content']['positionResult']['result']:
            item = {k: v for k, v in job.items() if k in fields}
            self.redis_db.lpush('lg_job_list', json.dumps(item))
        # print(i + 1)
        time.sleep(5)

这里要注意的是:

        (1). requests发送请求时,携带参数必须是字符串,所以请求参数里的pn要转成str;

        (2). 拉勾的这个接口请求时,必须带上浏览器的完整请求头信息,只设置User-Agent是不行的,所以直接把浏览器中这个请求的完整的请求头信息拿过来就行了;

        (3). 每请求一次后,尽量加上延时,避免请求过快,IP被封。

我这里get_job_company方法是把请求数据接口来的数据存放到redis的列表中,另外一个方法store_job_company取列表中的数据,过滤并保存数据到MySQL,并且数据里的positionId(职位id)和companyId(公司id)存到redis的集合供后续采集详情信息时使用。

        2. 职位详情数据和公司详情数据

            获取上一步存在集合里的职位id和公司id,构造职位详情页的url和公司详情页的url,使用selenium+Chrome去采集详情数据。

def get_job_info(self):
    # 初始化chrome浏览器无头模式
    chrome_options = Options()
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--disable-gpu')
    while True:
        job_id = self.redis_db.spop('lg_job_ids')
        if job_id is None:
            print('over')
            break
        driver = webdriver.Chrome(chrome_options=chrome_options)
        job_url = 'https://www.lagou.com/jobs/{}.html'.format(job_id)
        driver.get(job_url)
        time.sleep(2)
        element = etree.HTML(driver.page_source)
        desc = element.xpath('//dd[@class="job_bt"]/div//text()')
        desc_str = ''
        for item in desc:
            desc_str += self.content_pattern.sub('', item) + '*_*'
        address = element.xpath('//div[@class="work_addr"]//text()')
        address_str = ''
        for item in address:
            address_str += self.content_pattern.sub('', item)
        driver.quit()
        # 数据过滤
        if address_str == '' or desc_str == '':
            print({'msg': '失败', 'url': job_url, 'address': address_str[:-4], 'description': desc_str})
            # self.redis_db.sadd('lg_job_ids', job_id)
            continue
        # 保存数据库
        self.session.query(Job).filter(Job.lagou_id == job_id).\
            update({'url': job_url, 'address': address_str[:-4], 'description': desc_str})
        self.session.commit()
        print({'url': job_url, 'address': address_str[:-4], 'description': desc_str})

之后保存到mysql中数据就是这样的

image.png

四.    总结

        主要用到requests去请求拉勾的接口,利用redis的list做一个队列和set做一个简单的去重,然后使用selenium+Chrome(无头模式,新版本的selenium中已不能使用phantomJS)采集详情数据,数据保存到mysql。

        我这里贴的代码比较少,完整代码请看访问我的码云上的拉勾爬虫


评论