爬取前程无忧51job海量职位信息

准备阶段

前程无忧官网:https://www.51job.com/
本文对职位的爬取以python职位为例。
现在网站的反爬措施比较强,但可以用selenium进行爬取,虽然速度相对较慢但是爬取的方式较为方便。
我们在爬取之前需要安装和配置selenium和安装python所需的依赖库。
在这里插入图片描述

规划阶段

步骤 目标 函数名 所用知识
爬取前的准备 确定目标网站 ready()
开始爬取 爬取网页代码 begin() selenium
页面分析 得到解析的前端代码、得到职位总页数 read_text()、getpage() etree、xpath
爬取数据 对各条职位信息进行查找与提取其中的数据 save_database() selenium
数据清洗 将数据转化成特定的格式 data_change_xinxi()、data_change_jy()、data_change_money() re正则表达式
数据存储 把数据存入sqlite与csv中 save_csv()、save_database() sql语句、sqlite

代码编写阶段

1.爬取前的准备:

from lxml import etree
import sqlite3
from selenium import webdriver
import time
import re
import csv
def ready():
    url='https://search.51job.com/list/000000,000000,' \
        '0000,00,9,99,%25E7%25BD%2591%25E7%25BB%259C,2,2.html?lang=c&post' \
        'channel=0000&workyear=99&cotype=99&degreefrom=99' \
        '&jobterm=99&companysize=99&ord_field=0&dibiaoid=0&line=&welfare='
    begin(url)

2.开始爬取

#开始爬取
def begin(url):
    opt=webdriver.ChromeOptions()
    opt.add_argument('--headless')
    opt.add_argument('--disable-gpu') #无界面模式
    drive = webdriver.Chrome(options=opt)
    drive.get(url)
    #page=getpage(drive.page_source) #总页数
    #由于网站更新,已获取不到page总页数
    #for i in range(page):   #对每一页进行自动操作和爬取,控制最大页面为page页
    for i in range(100):#对每一页进行自动操作和爬取,控制最大页面为100页
        time.sleep(2)    #每一页爬取完毕休息,减少给对方服务器造成的压力
        
        text = drive.page_source
        text_zw = read_text(text)
        save_database(text_zw)
        #可能在爬取进行的时候,职位页数有减少
        try:
            drive.find_element_by_xpath('//li[@class="next"]//i[@class="e_icons"]').click()#寻找下一页按钮并自动点击下一页
        except:
            drive.quit()
            return
        print('第%d页爬取完毕' % (i + 1))
        time.sleep(5)
    drive.quit()

3.页面解析

#利用xpath解析得到该页所有职位元素,返回所有职位元素,供后续提取
def read_text(text):
    tree=etree.HTML(text)
    all_zw=tree.xpath('//div[@class="j_joblist"]/div[@class="e"]')
    return all_zw
def getpage(url_text):
    text=etree.HTML(url_text)
    page_text=text.xpath('//div[@class="j_page"]//div[@class="p_in"]/span[1]/text()')[0]
    page_text=re.findall('\d+',page_text)[0]
    page=int(page_text)
    return page

4.爬取数据与存入数据库

#利用sqlite来存储数据
def save_database(all_zw):
    connect = sqlite3.connect("wl.db") #数据库文件地址,数据库连接
    c = connect.cursor() #游标建立
    sql = '''
                create table job(
                name text,
                money text,
                pj_money int,
                company text,
                place text,
                expri text,
                min_expri int,
                xueli text,
                num text,
                job_url text,
                company_xinxi1 text,
                company_xinxi2 text,
                fl text
                ) 
                '''
    try: #执行sql语句,建立数据表
        c.execute(sql)
        connect.commit()
    except:
        pass
    for zw in all_zw: #对所有职位的信息进行提取
        zw_name = ''.join(zw.xpath('.//p[@class="t"]/span[1]/text()'))  #职位名称
        zw_money = ''.join(zw.xpath('.//p[@class="info"]/span[1]/text()')) #职位工资
        pj_money=data_change_money(zw_money)  #对职位工资进行处理,得到平均工资
        xinxi3=''
        try:
            xinxi = zw.xpath('.//p[@class="info"]/span[2]/text()')[0]  # 职位信息(地点、经验、学历、招聘人数)
            xinxi3 = data_change_xinxi(xinxi)  #对信息进行处理
            zw_place = xinxi3[0]  # 地点
        except:
            zw_place='null'
        try:
            zw_expri = xinxi3[1]  # 经验
            zw_xueli = xinxi3[2]  # 学历
            zw_num = xinxi3[3]  # 招聘人数
            min_jy = data_change_jy(zw_expri)  # 提出最低经验要求
        except:
            zw_expri = 'null'
            zw_xueli = 'null'
            zw_num = 'null'
            min_jy = -2
        company_xinxi2 = ''.join(zw.xpath('./div[@class="er"]/p[2]/text()'))  # 公司类型
        zw_company = ''.join(zw.xpath('./div[@class="er"]/a/text()'))  #公司名称
        job_url = ''.join(zw.xpath('.//a/@href'))  #职位的url
        if 'jobs.51job.com' not in job_url:  #筛选出该关键词的网站,为之后的再次爬取做准备
            job_url=''
        company_xinxi1 = ''.join(zw.xpath('./div[@class="er"]/p[1]/text()')) #外资合资
        fl_all=zw.xpath('.//p[@class="tags"]//i') #公司福利(五险一金、补贴等)
        fl=''
        for f in fl_all: #福利
            fl=fl+''.join(f.xpath('./text()'))
        csv_list=[zw_name, zw_money,pj_money, zw_company, zw_place, zw_expri, min_jy,zw_xueli, zw_num,job_url,company_xinxi1,company_xinxi2,fl]#存入csv
        save_csv(csv_list)
        # print(zw_name, zw_money,pj_money, zw_company, zw_place, zw_expri,min_jy, zw_xueli, zw_num,job_url,company_xinxi1,company_xinxi2,fl)
        try:#将每个职位的信息存入数据表
            sql2 = '''
                insert into job
                (name,money,pj_money,company,place,expri,min_expri,xueli,num,job_url,company_xinxi1,company_xinxi2,fl)
                values("%s","%s",%d,"%s","%s","%s",%d,"%s","%s","%s","%s","%s","%s")
                ''' % (zw_name, zw_money,pj_money, zw_company, zw_place, zw_expri,min_jy, zw_xueli, zw_num,job_url,company_xinxi1,company_xinxi2,fl)
            c.execute(sql2)
            connect.commit()
        except:
            pass
    c.close()#关闭游标
    connect.close()#关闭数据库

5.数据清洗

#对工资进行处理,返回平均工资类型为int
def data_change_money(zw_money):
    int_money = re.findall(r'\d+\.?\d*', zw_money)
    if '万/年' in zw_money or '万以上/年' in zw_money:
        if len(int_money) == 2:
            pj1_money = (float(int_money[0]) + float(int_money[1])) / 2 * 10000 / 12
            pj_money = int(format(pj1_money, '.0f'))
        else:
            pj1_money = float(int_money[0]) * 10000 / 12
            pj_money = int(format(pj1_money, '.0f'))
    elif '万/月' in zw_money or '万以上/月' in zw_money:
        if len(int_money) == 2:
            pj1_money = (float(int_money[0]) + float(int_money[1])) / 2 * 10000
            pj_money = int(format(pj1_money, '.0f'))
        else:
            pj1_money = float(int_money[0]) * 10000
            pj_money = int(format(pj1_money, '.0f'))
    elif '千/月' in zw_money:
        if len(int_money) == 2:
            pj1_money = (float(int_money[0]) + float(int_money[1])) / 2 * 1000
            pj_money = int(format(pj1_money, '.0f'))
        else:
            pj1_money = float(int_money[0]) * 1000
            pj_money = int(format(pj1_money, '.0f'))
    elif '元/天' in zw_money:
        if len(int_money) == 2:
            pj1_money = (float(int_money[0]) + float(int_money[1])) / 2 * 30
            pj_money = int(format(pj1_money, '.0f'))
        else:
            pj1_money = float(int_money[0]) * 30
            pj_money = int(format(pj1_money, '.0f'))
    else:
        pj_money =-2 #值为-2的都表示之后不处理
    return pj_money
    
#将(地点、经验、学历、招聘人数)信息进行分割,返回一个列表
def data_change_xinxi(xinxi):
    xinxi2 = xinxi.split('|')
    xinxi3 = []
    for xx in xinxi2:
        xinxi3.append(xx.strip())
    return xinxi3
    
#提出最低经验要求,类型为int
def data_change_jy(zw_expri):
    int_jy = re.findall(r'\d+', zw_expri)
    if '在校生' in zw_expri:
        min_jy=-1
        return min_jy
    if '无需经验' in zw_expri:
        min_jy=0
        return min_jy
    try:
        min_jy = int(int_jy[0])
    except:
        min_jy=-2
    return min_jy

6.存入csv

#将数据存入csv
def save_csv(csv_list):
    with open(r'wl2.csv', 'a', newline='') as file_csv: #csv地址
        csv_write=csv.writer(file_csv)
        csv_write.writerow(csv_list)
        file_csv.close()

运行展示

程序运行控制台展示:
在这里插入图片描述
文件路径生成:
“51job_spider.py”为爬虫运行文件
“wl.db”为生成的sqlite数据库文件
“wl2.csv”为生成的csv文件

使用SQLiteSpy可视化软件查看生成的sqlit数据库文件
在这里插入图片描述
在这里插入图片描述
生成csv文件中的数据:
在这里插入图片描述

爬取了海量数据后,接下来就是数据分析与可视化的过程。

猜你喜欢

转载自blog.csdn.net/t1300870172/article/details/121381066