从爬虫到检索的求职搜索引擎本地简单实现,含界面和特色功能(附数据分析代码)

从爬虫到检索的求职搜索引擎本地简单实现,含界面和特色功能(附数据分析代码),第1张

因为这个功能实现在第五部分,所以标题是5开头,比较多就懒得改了,大家明白就好

注意:本资源仅共学习参考,任何人切勿以任何形式商用!!!尊重信息版权
然后开头申明,本文包含的情感分类及公司排序不涉及真实排序,请勿当真,纯粹随机选的评论= =,但是都是大厂这没毛病。

温馨提示,本文虽然涉及到爬虫,但是因为博主可以说非常不喜欢爬虫,并且只是出入门户就懒得理解了,不过代码注释都非常详细,大家想要注重理解爬虫的还是找专业的吧,我这里爬虫都是一笔带过而已。当然也可以结合代码注释来理解,毕竟流程都一样。

还是老规矩,如果对大家有所帮助希望可以点赞,收藏,关注,但是这次代码不可以放上来了(害怕)

这里涉及的情感分类在我前面的博客有细致的讲解,大家最好结合前面的一起食用,我做的东西一般都是贯穿性的,因为可以加深理解,并且高效。
Bert细致讲解

5.1 核心功能实现流程描述;

首先是信息的筛选,通过爬取lp和某直聘的Python相关职位所有信息(北京和上海两个城市),将所爬取的信息作为形成数据库的基石。这里我共实现了两个,一个是lp,满足所有验收要求,一个是某直聘,满足搜索引擎(上述app)的功能要求。

1.网站1
爬取两个城市共400个职位链接->爬取详情信息->分词->数据清洗->去停->词频统计->去除无意义词汇与信息(例如单个的字)->通过TD-IDF提取关键词并生成词云

2.网站2
爬取两个城市近4K的职位数据(包括薪资,地点,所需技能,工作经验要求,学历要求以及岗位名称)->城市平均薪资,经验要求,技能需求以及学历需求的统计->技能词云

Top10公司评价统计(自己找的)->公司介绍爬取->公司总技能统计->信息树搭建->通过bert预训练的情感分析任务在评价上作zero-shot测评->根据评价得分rank公司并构建简单的关系图->搭建简易网页,实现本地搜索功能

其中Top10公司评价是自己找的原因是没有地方可以爬取,因为只有在专业求职app下面一定是夸这个公司的,不真实,但又没办法大规模爬,因为无法判别是不是评判公司的信息,所以只能我自己去找一个公司10个评价,根据predictions累计分数得到公司对应总分。

5.2 爬取流程分析;

其实感觉这个部分没有什么好讲的,我是直接套的网上的流程,然后找的对应的代码进行网页的爬取:
lp用的是request,首先在网站上输python,把网址复制下来,并且获取地区编号,找到规律一个地区爬了200个就换一个。然后用在代理池里面得到的ip作为user-agent去爬具体信息(不怕封就直接一直爬不用sleep)并存入job.txt文件待用。
直聘用的是webdriver,这个有些不一样,因为我不需要具体信息,所以爬的是python页面中的一些基本信息以及tag(技能),可以通过正则式获取,这一页爬完了就下一页,但是防封爬一页sleep 5s,一个城市爬够了就换下一个即可,request要url代号,这个只需要把对应的标签记下来就行了,爬取的信息放入数据.csv待用。

注:Boss的这个爬虫是我在网上找的改的,且只是微调,但太多一样的都标原创,我也没办法给出链接,大家一找就可以找到了,这里我只使用了他的数据做分析。

5.3 解析流程分析;

5.3.1 网站1数据:

其实这个就跟上面的流程差不多,要求的数据分析太简单了都不知道要讲什么,就大致把我写的代码过一下吧:
5.3.1.1 首先把刚才的job.txt文件读入,字符串除特殊符号相信大家都会:

说起来这个代码还是我刚自学python的时候写的。

5.3.1.2 然后分词去停,用jieba自带的lcut函数就可以了,去停对着停用词标筛就ok了,至于一些无意义词的筛选,特殊的也可以仍停用词表里去,单个或者超长的词直接删就行了。

5.3.1.3 最后就是提取关键词生成词语咯,这个也非常简单,只是我发现普通的tf-idf并不适我们爬取的文档,首先因为我忘记分类了(全存一个文件里去了…),其次就是用了之后发现rerank差别不大,所以为了更显著,我们要拉高idf的重要性。不过其实每个文档的信息差不多,所以我们把job文件等分为400份就行了(爬了400个工作),一共8w个词,所以我们200个词仍一个文档就好,然后统计逆词频

可以看到就是一个文档里面多个词只统计一次咯,不过注意我们说了要提高权重,所以与普通的idf比,我们把计算的分母乘2:

5.3.1.4 然后就可以rerank得到我们想要的结果了(并生成词云)
生成词云更可以直接套了,先根据词频对应随机颜色(温度和词频还是要有关更好)



可以看到左边和右边不一样,左边的是用寻常idf,右边是加大idf权重的结果,可以看到右边的一些技能就出来了

5.3.2 Boss

接下来算是重头戏了,这一部分是为了实现我搜索引擎的功能:
上面说了我们爬取到的信息已经存入数据.csv,如图所示:

然后我们通过预训练好的Bert情感分类模型对top10公司评价进行得分计算:

这个就不贴代码了,也没必要,把我预训练的精度图贴上来吧:

zero-shot的结果排名:


然后结合我们爬取的top10公司的介绍就可以建造如下的存储字典:

如图,这个存储结构就可以非常方便我们对应索引(虽然都是某些类别的问题)

首先我们识别的一个功能就是判断公司的好坏,我们通过每个公司对应的score来排序,实现关系,比如你问:有什么比阿里好的公司?

然后就可以在output中显示score比他高的公司简介

这里我们统一同类词,只写了几个,其他相统一都是类似的。

如上所示,统一同样的词,方便判断(其实也可以直接判断是否在列表里面)

具体实现方式其实比较简单,就是把查询的内容先分词,

然后关键词对应问题。

还有一个就是找还不错的公司,也是一样的:

前5认为好,后面的认为不好,然后返回的都是这些公司的简介

还有的功能就是对于职位需求的检索,包括对于地点,公司,具体职位,具体技能的识别与检索,代码如下:

其他的还可以实现很多功能,都是类似的,基于词语本身的,就不多写了。

然后我还实现了一个简单的网页:

这里方便起见,读文件是通过下载搜索框内的文本,然后运行我们的py脚本,就会生成output,通过文件选取和显示就可以在网页中显示了。

可以看到就在网页上显示咯,因为我不怎么会html,没办法切网页显示,所以就把所有返回的结果全扔到output里面一起显示啦。

还可以推荐工作哦,反正上面所提到过的问题基本都可以实现检索返回。

完整代码:

1.网站1内容分析:

import jieba
import matplotlib.pyplot as plt
import wordcloud
import random
import math


# 获得去除标点的文本
def get_text(file_name):
    with open(file_name, 'r', encoding='utf-8') as fr:
        text = fr.read()
        # 要删除的标点
        for ch in '|\/*-+.!@#$%^&*()''/.,,?><"~`。、“”()《》':
            text = text.replace(ch, '')  # 这里无需替换成空格
        return text


def stopwordslist(filepath):  # 定义函数创建停用词列表
    stopword = [line.strip() for line in open(filepath, 'r', encoding='utf-8').readlines()]  # 以行的形式读取停用词表,同时转换为列表
    return stopword


file_name = 'job.txt'
text = get_text(file_name)
stopwords = stopwordslist('./停用词.txt')  # 用的是百度和哈工大的中英文停用词表
# print(stopwords)
vlist = jieba.lcut(text)  # 调用jieba实现分词,返回列表
# print(len(vlist)) # 81701个词


res_dict = {}
# 进行词频统计
counts = 0
for i in vlist:
    if i not in stopwords:
        res_dict[i.title()] = res_dict.get(i, 0) + 1
    counts += 1


# 每200个词为一个文档,统计每个词出现的文档次数
def split_list_average_n(origin_list, n):
    for i in range(0, len(origin_list), n):
        yield origin_list[i:i + n]


idf_list = split_list_average_n(vlist, 400)
# for i in idf_list:
#    print(i)


res_list = list(res_dict.items())
# 降序排序
res_list.sort(key=lambda x: x[1], reverse=True)
fin_res_list = []

# 去除单个字的词
for item in res_list:
    if (len(item[0]) >= 2):
        fin_res_list.append(item)

# print(len(fin_res_list)) # 4730
idf_dict = {}
for i in idf_list:
    for j in fin_res_list:
        if j[0] in i:
            if j[0] in idf_dict.keys():
                idf_dict[j[0]] += 1
            else:
                idf_dict[j[0]] = 1

print(idf_dict)
print(len(idf_dict))

for i in idf_dict.keys():
    idf_dict[i] = math.log(200 / (idf_dict[i] + 1))


counts = 0
for i in fin_res_list:
    if i[0] in idf_dict.keys():
        idf_dict[i[0]] = idf_dict[i[0]] * i[1]  # tf-idf
        # idf_dict[i[0]] = i[1] / idf_dict[i[0]]

idf_dict = sorted(idf_dict.items(), key=lambda x: x[1], reverse=True)  # 降序排列
print(idf_dict)

for i in range(50):
    word, count = idf_dict[i]
    pstr = str(i + 1) + ':'
    print(pstr, end=' ')
    print(word, count)


# (1)自定义颜色函数
def random_color_func(word=None, font_size=None, position=None, orientation=None, font_path=None, random_state=None):
    # h = randint(0, 255)  # 从0-255取值,分别是从红→橙→黄→绿→青→蓝→紫
    # 51-70间为较亮的难以看清的黄色,0-15的红色也过于注目,改成随机在 16-50和 71-255间取值
    h = random.choice((random.randint(16, 50), random.randint(71, 255)))
    s = int(100.0 * 255.0 / 255.0)
    l = int(100.0 * float(random.randint(60, 120)) / 255.0)
    string = "hsl({}, {}%, {}%)".format(h, s, l)
    print(string)
    return string


# (2)导入背景图
back_pic = plt.imread("wordcloud_backgroud.jpg")  # 背景图

# (3)生成词云对象
wc = wordcloud.WordCloud(scale=4,  # scale越大,分辨率越高,越清晰
                         font_path='C:\Windows\Fonts\simhei.ttf',  # 设置字体,Windows系统自带了Fonts文件夹
                         background_color="white",  # 背景颜色
                         max_words=200,  # 词云显示的最大词数
                         mask=back_pic,  # 设置背景图片
                         max_font_size=250,  # 字体最大值
                         random_state=42,
                         color_func=random_color_func)

word_list = []
for i in idf_dict:
    for j in range(int(i[1])):
        word_list.append(i[0])  # 只留词,但是次数复制

random.shuffle(word_list)
print(" ".join(word_list))
my_wordcloud = wc.generate(" ".join(word_list))

plt.imshow(my_wordcloud)
plt.axis("off")
plt.show()
wc.to_file('./image/词云_猎聘.png')  # 保存图片文件
plt.close()

2.网站2内容分析+搜索引擎功能实现:

import csv
import os
import jieba
import eel
import json
import pandas as pd

with open("C:\Users\72959\Downloads\save.txt", 'r', encoding='utf-8') as fr:
    question = fr.read()

# 把网页读取的用户问题分词
question_words = jieba.lcut(question)
print(question_words)
for i in os.walk("./top10公司介绍/"):
    cp_names = i[2]

# print(cp_names)

# 现在我们应该来构建十个公司的关系以及字典
# 信息字典
infr_dict = {}

for i in cp_names:
    with open("./top10公司介绍/" + i, 'r', encoding='utf-8') as fr:
        score = fr.readline()
        introduction = fr.read()
        infr_dict[i.strip('.txt')] = {}
        infr_dict[i.strip('.txt')]['score'] = score.strip('\n')
        infr_dict[i.strip('.txt')]['introduction'] = introduction
        infr_dict[i.strip('.txt')]['job'] = {}
        infr_dict[i.strip('.txt')]['skill'] = []

# save_file = '信息字典.csv'
# with open(save_file, 'w', encoding='utf8') as f:
#   json.dump(infr_dict, f, ensure_ascii=False, indent=4)
# print(infr_dict)

# data包括:岗位0,地点1,薪资2,工作经验3,学历4,公司5,技能6
# data = pd.read_csv('./数据.csv')
# print(data.company)
# 这里我们要把信息存进去,所以对着数据的公司来找

with open('./数据.csv', encoding='utf-8') as f:
    f_csv = csv.reader(f)
    headers = next(f_csv)

    for i in f_csv:
        # print(i)
        if i[5] in infr_dict.keys():
            infr_dict[i[5]]['job'][i[0]] = {}
            infr_dict[i[5]]['job'][i[0]]['skill'] = i[6]
            infr_dict[i[5]]['job'][i[0]]['education'] = i[4]
            infr_dict[i[5]]['job'][i[0]]['experience'] = i[3]
            infr_dict[i[5]]['job'][i[0]]['salary'] = i[2]
            infr_dict[i[5]]['job'][i[0]]['location'] = i[1][:2]
            # 添加总技能 并去重

            i[6] = i[6].strip('[')
            i[6] = i[6].strip(']')
            i[6] = i[6].split(",")
            for j in i[6]:
                if j not in infr_dict[i[5]]['skill']:
                    infr_dict[i[5]]['skill'].append(j)


# print(infr_dict.keys())
"""
for i in infr_dict.keys():
    print(i)
    print(infr_dict[i]['score'])
"""
# 现在我们字典创建好了,现在就是要创建关系了
# 第一个关系就是公司的好坏,我们用上面情感分析的结果,也在字典里面的score里先排个序,说实话,懒得排序了,这里十个我直接手排了哈哈哈哈,用代码也比较简单,c++里面的冒泡就是典型的
# 这里排序不代表真实排名,因为是我自己随机取的10个数据
rank_list = ['腾讯', '蚂蚁集团', '阿里', 'bilibili', '滴滴', '携程', '拼多多', '字节跳动', '美团', '饿了么']

good_list = ['好', '很好', 'good', '比较好', '非常好']
bad_list = ['差', '很差', 'bad', '比较差', '非常差', '坏']
ali = ['阿里', '阿里巴巴', '阿里集团']
bili = ['bilibili', 'b站', 'B站', 'bili', '小破站']
eleme = ['饿了么', '饿', '饿了吗']
# 以此类推,懒得标了
# 先把question_word的词汇清洗转换一下
for i in question_words:
    if i in good_list:
        question_words[question_words.index(i)] = '好'
    if i in bad_list:
        question_words[question_words.index(i)] = '差'
    if i in ali:
        question_words[question_words.index(i)] = '阿里'
    if i in bili:
        question_words[question_words.index(i)] = 'bilibili'
    if i in eleme:
        question_words[question_words.index(i)] = '饿了么'

f = open('ouput.txt', 'w', encoding='utf-8')

# 完成公司比较的检索:
if '公司' in question_words and '比' in question_words:
    if '好' in question_words:
        for i in question_words:
            if i in rank_list:
                # print(rank_list[:rank_list.index(i)])
                for j in rank_list[:rank_list.index(i)]:
                    f.write(infr_dict[j]['introduction'])
                    f.write("\n\n\n")
    if '差' in question_words:
        for i in question_words:
            if i in rank_list:
                # print(rank_list[rank_list.index(i) + 1:])
                for j in rank_list[rank_list.index(i) + 1:]:
                    f.write(infr_dict[j]['introduction'])
                    f.write("\n\n\n")

# 好和不好的公司
if '公司' in question_words and '比较' in question_words:
    if '好' in question_words:
        # print(rank_list[:5])
        for i in rank_list[:5]:
            f.write(infr_dict[i]['introduction'])
            f.write("\n\n\n")
    if '差' in question_words:
        # print(rank_list[6:])
        for i in rank_list[6:]:
            f.write(infr_dict[i]['introduction'])
            f.write("\n\n\n")

skill_list = []
s = []
# 职位信息的搜索,则遍历职位信息
counts = 0
for i in question_words:
    if i in rank_list:
        for j in infr_dict[i]['job'].keys():
            if len(list(set(jieba.lcut(j.casefold())) & set(question_words))) == len(jieba.lcut(j)):  # 工作对
                if '上海' in question_words or '北京' in question_words:
                    if infr_dict[i]['job'][j]['location'] in question_words:
                        if '技能' in question_words:
                            # print(infr_dict[i]['skill'])
                            skill_list.append(infr_dict[i]['skill'])
                            # f.write(str(infr_dict[i]['skill']))
                            break
                        else:
                            # print(infr_dict[i]['job'][j])
                            # skill_list.append(infr_dict[i]['job'][j])
                            f.write(str(infr_dict[i]['job'][j]))  # 全部输出
            else:
                if '上海' in question_words or '北京' in question_words:
                    if infr_dict[i]['job'][j]['location'] in question_words:
                        if '技能' in question_words:
                            skill_list.append(infr_dict[i]['skill'])
                            f.write(str(infr_dict[i]['skill']))


    counts += 1
    if counts == 10:
        for item in skill_list:
            for k in item:
                s.append(k)
        # print(set(s))
        f.write(str(set(s)))

counts = 0
for i in infr_dict.keys():
    for j in infr_dict[i]['job'].keys():
        if len(list(set(jieba.lcut(j.casefold())) & set(question_words))) == len(jieba.lcut(j)):  # 工作对
            if '上海' in question_words or '北京' in question_words:
                if infr_dict[i]['job'][j]['location'] in question_words:
                    if '技能' in question_words:
                        # print(infr_dict[i]['skill'])
                        skill_list.append(infr_dict[i]['skill'])
                        # f.write(str(infr_dict[i]['skill']))
                        break
                    else:
                        # print(infr_dict[i]['job'][j])
                        # skill_list.append(infr_dict[i]['job'][j])
                        f.write(str(infr_dict[i]['job'][j]))  # 全部输出
        else:
            if '推荐' in question_words and '工作' in question_words:
                # print(infr_dict[i]['job'][j])
                # skill_list.append(infr_dict[i]['job'][j])
                f.write(str(infr_dict[i]['job'].keys()))  # 全部输出
    counts += 1
    if counts == 10 and s != []:
        for item in skill_list:
            for k in item:
                s.append(k)
        print(set(s))
        f.write(str(set(s)))
# 后面其他功能也是以此类推,在这里就不写了

# print(infr_dict)

3.搜索引擎HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">

    <title>搜索引擎</title>

    <style>
        img{
            position:absolute;
            left:450px;
            top:120px;
        }


        body,ul{
            margin:0;/*清除默认标签*/
        }
        ul{
            padding-left:0;
            list-style:none;
        }
        textarea{
            display:block;
            width:640px;
            height:30px;
            margin:100px auto 0;
            font-size: 25px;
        }
        .btn{
            width:500px;
            margin:10px auto;
            text-align:center;
            font-size: 25px;
        }
        .msg{
            margin:0 auto;
            width:500px;
        }
        .msglist{
            line-height:50px;
            border-bottom:1px dashed #ccc;
            text-indent: 2em;/*开头空两个字符*/
        }
    </style>
</head>
<body>

    <body background="./你的名字带logo.png" style=" background-repeat:no-repeat ;background-size:100% 100%;
		background-attachment: fixed;">
            <br>
			<br>
			<br>
			<br>
            <br>
			<br>
			<br>
			<br>
            <br>
			<br>

    <textarea cols="30" rows="10"></textarea>

    <div class="btn">
        <button>搜索</button>
    </div>
    <ul class="msg"></ul>


<script script type="text/javascript">
function show()
{
    var reader = new FileReader();
    reader.onload = function()
    {
        alert(this.result)
    }
    var f = document.getElementById("filePicker").files[0];
    reader.readAsText(f);
}
</script>
<input type="file" name="file" id="filePicker"/>
<div id = "div1">
</div>
<input type="button" value = "显示"  onclick="show()"/>



    <script>
        function fake_click(obj) {
    var ev = document.createEvent("MouseEvents");
    ev.initMouseEvent(
        "click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null
    );
    obj.dispatchEvent(ev);
}

    function download(name, data) {
    var urlObject = window.URL || window.webkitURL || window;

    var downloadData = new Blob([data]);

    var save_link = document.createElementNS("http://www.w3.org/1999/xhtml", "a")
    save_link.href = urlObject.createObjectURL(downloadData);
    save_link.download = name;
    fake_click(save_link);
    }


        let btn=document.querySelector("button"),//获得button元素
            textArea=document.querySelector("textarea"),
            msg=document.querySelector(".msg");
        btn.onclick=function(){
            if(textArea.value){
                //调用方法
                download("save.txt",textArea.value);
                //msg.innerHTML+="
  • "+textArea.value+"
  • "
    ;//将标签信息添加到ul中 //textArea.value="";//清空输入框 }else{ alert("你尚未输入信息,请重新输入") } } </script> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script type="text/javascript"> var openFile = function(event) { var input = event.target; var reader = new FileReader(); reader.onload = function() { if(reader.result) { //显示文件内容 $("#output").html(reader.result); } }; reader.readAsText(input.files[0]); }; </script> </body> </body> </html>

    欢迎分享,转载请注明来源:内存溢出

    原文地址: http://outofmemory.cn/langs/797472.html

    (0)
    打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
    上一篇 2022-05-06
    下一篇 2022-05-06

    发表评论

    登录后才能评论

    评论列表(0条)

    保存