0%

毕设记录

一. 爬虫数据获取相关说明

1. 数据来源:

拉勾网

2. 数据量:

越大越好(初步测试用java大数据岗位搜索到了2500页的数据)

3. 数据爬取方式

由于网站上是通过ajax请求访问得到的数据,所以我们选择伪装请求进行访问

4. 初步页面显示数据结构:

  • positionId = ‘’ #岗位id
  • positionName = ‘’ #岗位名称
  • salary = ‘’ # 薪水
  • education = ‘’ # 学历
  • positionAdvantage = ‘’ # 岗位优势
  • firstType = ‘’ # 岗位类型
  • skillLables = ‘’ #技能标签
  • jobNature = ‘’ # 是否全职
  • workYear = ‘’ # 工龄
  • companyFullName = ‘’ # 公司全称
  • city = ‘’ #公司城市
  • industryField = ‘’ # 领域
  • companyLabelList = ‘’ # 公司标签
  • companySize = ‘’ # 公司规模
  • financeStage = ‘’ # 公司资金状况,是否融资等

5. 工作地点具体信息数据结构

  • advantage 职位优势
  • job-detail 工作职责/任职资格
  • job-address 工作地点
  • company-url 有意向联系我们

. 6.数据爬取过程中遇到的问题及解决方法(这里反爬虫技术可以写很多,比如伪ip,切换cookies,延时访问等方法)

  1. 通过requests.post请求访问网页数据的时候,伪装头文件传输过去的数据无法被识别到,导致多次请求到的数据都只是初始的头文件返回来的数据

    解决方法:直接将需要更新修改的数据添加在网页链接上传输到后台请求数据,多次尝试通过对网页重定向理解得到的解决方法。

  2. 网页数据只显示30页的数据如何获取到更多

    解决方法:网页上虽然只显示了30页,但是通过在后台伪装头文件发现是可以获取到其数据库中未显示在网页上的数据的

  3. 批量获取具体信息的时候访问多条后就程序自动停止,但是将停止的数据单独获取则没有问题

    问题原因:反爬虫机制,一次大量访问后封锁ip需要验证码登录

    • 解决方法:
      中使用休眠方法但无效
      访问一定条数之后使用伪ip访问
  4. 程序报异常,打印请求返回的数据时显示“{“status”:false,”msg”:”您操作太频繁,请稍后再访问”,”clientIp”:”218.206.101.37”,”state”:2402}”

    问题原因:网站设置了cookies拦截,对于手动设置的cookie模拟浏览器访问的爬虫程序自动进行了拉黑,并且不登录就无法查看所有的数据

    • 解决方法:
      如果登录获取数据的话需要用到大量的拉勾网账号,比较复杂。这里通过使用手机app端的接口访问拉钩网进行数据的抓取。但是访问到一定数据量之后还是会被封,需要登录验证。通过app端口访问失败
      访问30条之后便更新cookie进行爬取
      最终成功方法:设置延时访问并访问一定数据量后进行自动获取当前浏览器的cookie进行更新,继续爬取数据

二.ElasticSearh的安装使说明

环境说明linux centos6.9(用户组mima12345,用户test_12345),ElasticSearch5.2.2,kibana5.2.2

1.ElasticSearch介绍(抄一些书,资料什么的)

  1. index:类,所有对象的集合

  2. document:类的实例化——》对象,以字典的形式存储,键为filed

  3. type:对象的种类

  4. shard(分片):index所有数据在集群运算中被存放在多个节点上,称之为shard

  5. replica:shard的保存副本,防止数据丢失系统出现意外

  6. ElasticSearch的概念和数据库概念的对比
    index —- 库
    document —- 行
    type —- 表
    mappings —- 表结构

  7. 中文分词器

  8. 部分操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
批量检索获取文档:
GET /lib/user/_mget
{
//检索id为1和2的对象
"ids":["1","2"]
}

批量操作:
Bulk API:

导入数据(在account.json文件的当前目录输入进行导入操作):
$ curl -H "Content-Type: application/json" -XPOST 'localhost:9200/bank/account/_bulk?pretty' --data-binary @accounts.json
查看是否导入成功:
curl "localhost:9200/_cat/indices?v"
数据导入并创建在kibana中创建index及相关使用
https://blog.csdn.net/magerguo/article/details/79849863

2.ElasticSearch安装

  1. 安装jdk
1
2
3
因为最新版的jdk1.9和ElasticSearch存在部分不兼容,所以这里安装的是jdk1.8版本的
具体步骤见:https://www.cnblogs.com/xqzt/p/4934451.html

  1. 安装elasticSearch5.2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
下载:wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.2.2.tar.gz
解压:tar -zxvf elasticsearch-5.2.2.tar.gz -C /usr/local/ElasticSearch
使用:./bin/elasticsearch
查看是否成功开启:打开“http://localhost:9200”有以下结果:
{
"name" : "zLIR9JJ",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "thS180_KTj6vZK9szI3Mag",
"version" : {
"number" : "5.2.2",
"build_hash" : "f9d9b74",
"build_date" : "2017-02-24T17:26:45.835Z",
"build_snapshot" : false,
"lucene_version" : "6.4.1"
},
"tagline" : "You Know, for Search"
}成功开启

如图所示:

  1. 安装elasticsearch-head插件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
https://www.cnblogs.com/scharfsinnig/p/6706880.html

安装node.js:
https://blog.csdn.net/liangxw1/article/details/78251025安装npm:
安装npm:nodejs安装的时候附带了npm
下载elasticserach-head插件:
git clone https://github.com/mobz/elasticsearch-head.git
安装elasticsearch-head依赖包:
npm install -g grunt-cli
遇到问题:
node npm install Error: CERT_UNTRUSTED
解决方法:
ssl验证问题,使用下面的命令取消ssl验证即可解决
npm config set strict-ssl false
打开方式:
在./elasticsearch-head目录下输入 grunt server 出现下图为正确无误结果

  1. 安装kibana5.2.2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
下载:wget https://artifacts.elastic.co/downloads/kibana/kibana-5.2.2-linux-x86_64.tar.gz
解压:tar -zxvf kibana-5.2.2-linux-x86_64.tar.gz -C /usr/local/ElasticSearch
在kibana安装目录的config下,编辑kibana.yml配置文件,添加如下配置:
server.port: 5601
server.host: "本机的IP"
elasticsearch.url: "http://192.168.222.131:9200"
其中elasticsearch.url 配置对应搜索引擎服务的真实地址

打开5601端口(kinaba默认端口):
/sbin/iptables -I INPUT -p tcp --dport 端口号 -j ACCEPT 写入修改
/etc/init.d/iptables save 保存修改
service iptables restart 重启防火墙,修改生效
启动服务
$ cd kibana-6.4.0-linux-x86_64/bin
$ ./kibana
浏览器访问“http:/.192.168.222.131:5601”验证是否成功安装
结果如下图

3.ElasticSearch的初步使用及项目实现

1.初步使用

  1. 查询功能的javaAPI使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import java.net.InetAddress;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.junit.Test;

public class EsDemo {

@Test
public void test1() throws Exception{

//指定ES集群
Settings settings = Settings.builder().put("cluster.name","my-application").build();
//创建访问es服务器的客户端
InetSocketTransportAddress node = new InetSocketTransportAddress(
InetAddress.getByName("192.168.222.131"),9300);

TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(node);
//数据查询
GetResponse response = client.prepareGet("lib","user","1").execute().get();
//打印结果
System.out.println(response.getSourceAsString());

client.close();
}

}

  1. 结构化查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
①通过id检索实现简单查询

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;

import org.apache.lucene.util.fst.Util;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.transport.client.PreBuiltTransportClient;


public class simpleSearch {

public static void main(String[] args) throws Exception {
//指定ES集群
Settings settings = Settings.builder().put("cluster.name","my-application").build();
//创建访问es服务器的客户端
InetSocketTransportAddress node = new InetSocketTransportAddress(
InetAddress.getByName("192.168.222.131"),9300);

TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(node);
//数据查询

BufferedWriter writer = new BufferedWriter(new FileWriter(new File("C:\\Users\\94452\\Desktop\\1.txt"),true));


BoolQueryBuilder qb = QueryBuilders.boolQuery();
qb.must(QueryBuilders.termQuery("positionName", "java大数据"));
// termQuery 是代表短语、不可拆分。就是不会把你teamId拿去切词,然后再去查,而是直接拿去查询
//prepareSearch写库的名称,setTypes写表的名称,setQuery写查询语句,setSize写默认结果返回条数的个数(默认为10条),get语句执行,返回的结果存放在getHits中
SearchResponse response = client.prepareSearch("lagou").setTypes("work").setQuery(qb).setSize(3000).get();
SearchHits searchHits = response.getHits();

System.out.println("查询到记录数=" + searchHits.getTotalHits());
for(SearchHit hit:searchHits.getHits()){
System.out.println(hit.getSourceAsString());
writer.write(hit.getSourceAsString()+"\n");
}

writer.close();

client.close();

}

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
②多条件查询,查询出学历要求为本科,工作城市在杭州,工作类型为全职的信息

import java.net.InetAddress;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.transport.client.PreBuiltTransportClient;

public class simpleSearch {

public static void main(String[] args) throws Exception {
// 指定ES集群
Settings settings = Settings.builder().put("cluster.name", "my-application").build();
// 创建访问es服务器的客户端
InetSocketTransportAddress node = new InetSocketTransportAddress(InetAddress.getByName("192.168.222.131"),
9300);

TransportClient client = new PreBuiltTransportClient(settings).addTransportAddress(node);
// 数据查询

QueryBuilder qb = QueryBuilders.boolQuery().must(QueryBuilders.termQuery("education.keyword", "本科"))
.must(QueryBuilders.termQuery("city.keyword", "杭州"))
.must(QueryBuilders.termQuery("jobNature.keyword", "全职"));

SearchRequestBuilder sv = client.prepareSearch("lagou").setTypes("work").setQuery(qb).setFrom(0).setSize(100);

SearchResponse response = sv.get();
SearchHits searchHits = response.getHits();
System.out.println("查询到记录数=" + searchHits.getTotalHits());
for (SearchHit hit : searchHits.getHits()) {
System.out.println(hit.getSourceAsString());
}

client.close();

}

}

  1. 出现问题及解决方法:

    对于包含中文字符的查询语句无法执行进行

    • 问题原因:elasticsearch 里默认的IK分词器是会将每一个中文都进行了分词的切割,所以你直接想查一整个词,或者一整句话是无返回结果的。
    • 解决方法:
1
2
3
4
termQuery("cityName", "北京市");
改成
termQuery("cityName.keyword", "北京市");
就可以了

2.项目实现

  1. 数据结构的设计并转换数据格式
  • 原数据格式为:
1
5309423	大数据Java工程师	8k-16k	本科	六险一金,补贴,带薪年假	开发|测试|运维类		全职	1-3年	成都数联铭品科技有限公司	成都	带薪年假/绩效奖金/扁平管理/定期体检	150-500人	C轮	
  • 需要的格式为:(index行为设置索引,第二行为数据)
1
2
{"index": {"_id":"1"}}
{"positionId":"5309423","positionName":"大数据Java工程师","salary":"8k-16k","education":"本科","positionAdvantage":"六险一金,补贴,带薪年假","firstType":"开发|测试|运维类","skillLables":"","jobNature":"全职","workYear":"1-3年","companyFullName":"成都数联铭品科技有限公司","city":"成都","companyLabelList":"带薪年假/绩效奖金/扁平管理/定期体检","companySize":"150-500人","financeStage":"C轮","detailInfo":"https://www.lagou.com/jobs/5309423.html"}
  • 以上通过python编程语言实现数据结构的转换,并存储为”.json”文件

  • 出现相关问题及解决方法:

    1
    java.lang.NoClassDefFoundError:org/apache/logging/log4j/Logger问题

    1

    1
    2
    3
    4
    5
    问题原因及解决方法:
    问题原因:log4j 1.6不适用于ElasticSearch 5.2.2。而且你还需要添加库的依赖slf4j-simple,log4j-to-slf4j和log4j-api。
    解决方法:
    必须在pom中明确包含Log4J 2作为依赖项,将之前的log4j依赖替换成以下依赖。
    Maven添加以下依赖:

    2

  1. 批量数据导入ElasticSearch系统
  • 数据导入
1
curl -H "Content-Type: application/json" -XPOST '192.168.222.131:9200/lagou/work/_bulk?pretty' --data-binary @work.json 
  • 查看结果
    如图1,图2所示

    图2

  • 通过kibana建立索引(操作步骤)

  1. 检索数据结构的设计
  • positionName:职位名称
  • salary: 20-30k(这里的数据检索前需要处理,仔细想想该怎么做)
  • education:本科/大专/硕士/不限
  • skillLables:手动填写
  • jobNature:全职/实习
  • workYear:1-3年/3-5年/不限/应届毕业生
  • city:城市
  • 公司规模:100-200人等等
  1. 通过编写javaAPI接口实现搜索功能
    javaAPI中主要使用ElasticSearch中的布尔查询来实现复杂信息的检索功能。
    1
    2
    3
    must:必须出现在匹配文档中,并且会影响匹配得分
    filter:必须出现在匹配文档中,并且匹配得分会被忽略
    should:应该出现在匹配文档中

三.小程序开发部分

小程序的相关概念学习:

  • index.js 文件配置页面入口与逻辑,还有存储数据并与网页使用的数据进行绑定;还有函数的绑定也是放在js文件中的
  • index.wxml配置布局与ui,index.wxss为页面的样式文件(类似与css),二级目录下的json文件可有可无,如果存在的话会覆盖掉app.json的数据,wxss文件同理
  1. 小程序开发软件的安装

  2. 小程序软件的编写

  • 前台与后台的交互实现部分

    服务器端使用的是tomcat8,通过微信小程序的wx.request方法对服务器端进行servlet请求,然后通过servlet层对dao层发送搜索请求,dao层处理完成后得到结果再返回微信小程序端。

实现样例:通过小程序点击按钮对“http://localhost:8080/weixin/getInfoServlet”发送请求,并传输过去data内的值,在服务器端查看数据是否传输过来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//index.js

Page({
bindtest: function () {
wx.request({
url: 'http://localhost:8080/weixin/getInfoServlet',
data: {
username: '001',
password: 'abc'
},
method: 'GET',
header: {
'content-type': 'application/json' // 默认值
},
success: function (res) {
console.log(res.data);
},
fail: function (res) {
console.log(".....fail.....");
}
})
}
}
)

//index.wxml

<view>
<button bindtap='bindtest'>test</button>
</view>

//servlet

package com.weixin.servlet;

import java.io.IOException;
import java.io.Writer;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/getInfoServlet")
public class getInfoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

public getInfoServlet() {
super();
// TODO Auto-generated constructor stub
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html;charset=utf-8");
/* 设置响应头允许ajax跨域访问 */
response.setHeader("Access-Control-Allow-Origin", "*");
/* 星号表示所有的异域请求都可以接受, */
response.setHeader("Access-Control-Allow-Methods", "GET,POST");

//获取微信小程序get的参数值并打印
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username="+username+" ,password="+password);

//返回值给微信小程序
Writer out = response.getWriter();
out.write("成功访问客户端");
out.flush();
}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}

}

查看结果:先打开tomcat8,然后打开小程序客户端点击test按钮如图(小程序测试按钮截图),可以查看到小程序的调试器界面出现了“成功访问客户端”几个字,而这几个字是通过“http://localhost:8080/weixin/getInfoServlet”所返回到小程序端的结果。然后在服务器端查看小程序端传输过去的data是否成功接收,打开服务器端(如图:小程序测试服务器端截图)可以看到数据成功传输过去了。
提交按钮

1
2
3
sequenceDiagram
小程序端->>服务器端: 传输data
服务器端->>小程序端: 返回“成功访问客户端”说明,并打印data
  • 项目具体实现

    selvert层:处理小程序端传过来的请求,传输到dao层进行查询处理

dao层:进行数据检索功能

model层:
该层创建信息对象(字段全部都为ES中的text格式,在java对象中对应设置为string格式)

  • 系统设计:三个页面
    • 主页,显示轮换广告页面和一些主页推荐公司信息
    • 搜索页面,添加搜索条件进行
    • 个人信息页面
  1. 遇到的问题及解决方法
  • 小程序页面的编写及功能实现,主要两个功能:
  • 1.不含条件的工作名称检索(默认) 2.含条件的工作名称检索。

  • 服务器端的servlet层从小程序端获取到数据后,传入dao层进行数据检索,并返回前端页面显示结果。目前存在以下问题:
  • 1.在使用javaAPI的过程中对于多条件检索语句如何编写?2.检索到的数据以什么格式存储并传输到前端的小程序中?

  • 小程序接收到数据后静态刷新页面显示结果页面。以列表形式将所有的信息打印出来,点击直接跳转到detailInfo的值包含的页面。
  • 多单选框如何传入数据
  • maven项目依赖包无法导入tomcat中进行部署(https://blog.csdn.net/class2class/article/details/83066073)
  • 前端与后端的数据传输部分(json格式的修改)
  • 事件绑定bindtap等