输入关键字 抓取所有网页(社招进阿里的一个面试呗,你准备好了吗?)
优采云 发布时间: 2022-02-07 06:03输入关键字 抓取所有网页(社招进阿里的一个面试呗,你准备好了吗?)
内容
前言
前几天,我接到了外籍人士阿里的面试。作为一个自信狂妄的我,虽然是外籍人士,但对阿里还是有几分敬佩之情,就像高考想进清华北大,想进腾讯阿里工作一样。是的,当然,除了学校招985/211能进阿里外,其他人想通过中介被招进阿里,那就更难了,至少在某个领域是专家级别的。所以如果你有一个难得的机会,试试阿里的采访。
一、采访内容1、电话面试及项目实践题
首先是电话面试:这个一般没问题,多看书,少吃零食,多睡觉……这个肯定能回答
二是想出一个动手demo题目,如下
文档链接:
爬取左侧文档树中的所有文档列表
在查询页面输入关键词或描述性语言给出3个最佳匹配文档(从高匹配到低匹配排序)。
供应:
1. 代码
2. 匹配的想法
奖励:有关如何为描述性语言提供建议的文档。例如用户输入:我的日志 采集 is out
大多数人在听到他们要编写一个演示时都会感到恐慌。不要害怕,我不会和你分享我的经验和代码示例,所以请阅读此文章,之后应该没问题,反正我已经结束了。
2、动手主题:文档抓取和搜索
3、研究课题
首先,去链接看看。让我们来看看它是什么。原来是阿里云的帮助文档。看来这个简单的demo其实就是根据用户输入的关键词搜索对应的解决方案。小项目。
第一个小步骤,爬取内容应该不难。不管是用Java还是Python,难度是第一位的,但是Python可能更简单,Java会多写一点代码。当然,小编目前还是想先学java,所以用java代码来演示。至于Python,先学一门语言,再拓展其他语言,才能更好的辅助你。
难点在于第二个小步骤,“在查询页面输入关键词或者描述性语言,给出最佳匹配的3个文档(匹配度从高到低排序)”,
我们先不爬,因为如果爬,必须封装想要的格式。当我们没有想到查询关键词的功能时,先保留它。
①查询输入关键词,给出最佳匹配方案
当然,你可以自己写算法和匹配,但是这种情况下,匹配肯定不是很准确,一天之内几乎不可能写出来,所以看看前人对这种类型有什么想法更好的解决方案,踩在巨人的肩膀上,事半功倍。
其实有很多方法可以实现类似的功能,
比如通过分词器搜索:Jieba分词、Ansj分词……其他分词效果可以点这里:了解11个开源中文分词
或者类似搜索引擎服务器的开源框架:Elasticsearch、Lucene……其他搜索引擎服务可以点这里:了解13个开源搜索引擎
小编这里演示的是一个使用solr搜索引擎实现这个爬取和检索的demo项目
二、启动 solr
solr下载地址:最好下载低版本,高版本需要高jdk版本,我的jdk是1.7,下载的solr版本是4.7.0是的,或者当我下载我在文章末尾制作的演示时,我也会将我使用的所有内容都放入其中。
1、配置步骤
① 下载后解压
② cmd进入这个目录:xxxxx/solr-4.7.0/example
③ 执行命令:java -jar start.jar
④ 如果访问成功,在浏览器中输入:8983/solr即可访问,表示启动成功。
2、Solr接口说明及使用
具体solr的其他功能这里就不介绍了。可以参考网上资料,进一步加深对solr的理解和使用
三、开始爬取
首先在项目中引入solr的maven包
org.apache.solr
solr-solrj
4.7.0
爬取很简单,只是模拟一个浏览器访问内容,我们可以看到要爬取的网站左边的所有文本内容都在
里面,
这个很简单,这样我们就可以对爬取的数据进行正则匹配后得到我们想要的所有文本标题信息。
代码示例:
/**
* 爬取数据
* @return
*/
@ResponseBody
@RequestMapping("/getDocs")
public String getDocs() {
Map mapReturn = new HashMap(); //返回结果
try {
//爬取前先在solr上建林索引属性
alibabaService.addDefaultField();
//开始爬取指定url的数据
String htmlResult = GetAliApi.sendGet("https://help.aliyun.com/document_detail/48851.html", "");
//获取到 树文档的内容
String[] mainMenuListContainer = htmlResult.split("")[1].split("");
//log.debug(mainMenuListContainer[0]);
//log.debug("------------------------------");
//进行正则获取数据
String searchReg = "(.*?)";
Pattern pattern = Pattern.compile(searchReg); // 讲编译的正则表达式对象赋给pattern
Matcher matcher = pattern.matcher(mainMenuListContainer[0]);
int i = 0;
String pre = "A";
while (matcher.find()) {
i++;
String title = matcher.group(1);
log.debug(title);
//将数据放到solr里,添加索引
Alidocs alidocs = new Alidocs();
alidocs.setId(pre+i);
alidocs.setTitle(title);
alibabaService.addIndex(alidocs);
}
mapReturn.put("returnCode","00");
mapReturn.put("content","爬取成功");
}catch (Exception e){
e.printStackTrace();
mapReturn.put("returnCode","-1");
mapReturn.put("content","爬取失败,请重试");
}
String mapStr = JSONObject.toJSONString(mapReturn);
return mapStr;
}
addDefaultField() 方法和 addIndex() 方法:
// 添加默认索引属性
public void addDefaultField() throws SolrServerException, IOException {
// 声明要连接solr服务器的地址
String url = "http://localhost:8983/solr";
SolrServer solr = new HttpSolrServer(url);
SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", "默认情况下必须添加的字段,用来区分文档的唯一标识");
doc.addField("title", "默认的名称属性字段");
solr.add(doc);
solr.commit();
}
// 添加索引
public void addIndex(Alidocs alidocs) throws SolrServerException, IOException {
// 声明要连接solr服务器的地址
String url = "http://localhost:8983/solr";
SolrServer solr = new HttpSolrServer(url);
solr.addBean(alidocs);
solr.commit();
}
sendGet() 方法:
public static String sendGet(String url, String param) {
String result = "";
String urlName = url + "?" + param;
try {
URL realURL = new URL(urlName);
URLConnection conn = realURL.openConnection();
//伪造ip访问
String ip = randIP();
System.out.println("目前伪造的ip:"+ip);
conn.setRequestProperty("X-Forwarded-For", ip);
conn.setRequestProperty("HTTP_X_FORWARDED_FOR", ip);
conn.setRequestProperty("HTTP_CLIENT_IP", ip);
conn.setRequestProperty("REMOTE_ADDR", ip);
conn.setRequestProperty("Host", "help.aliyun.com/");
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36");
conn.setRequestProperty("Referer","https://help.aliyun.com/"); //伪造访问来源
conn.setRequestProperty("Origin", "https://help.aliyun.com/"); //伪造访问域名
conn.connect();
Map map = conn.getHeaderFields();
for (String s : map.keySet()) {
System.out.println(s + "-->" + map.get(s));
}
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
String line;
while ((line = in.readLine()) != null) {
result += "\n" + line;
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
这样,基本上爬取的功能就完成了,可以看到爬取了我们想要的信息
四、通过 关键词 检索
检索比较简单,因为使用了solr搜索引擎的服务,所以只要按照solr api传入数据就可以检索到,它会自动进行分词过滤,按照匹配度。
代码示例:
/**
* 通过关键词获取数据
* @param title
* @return
*/
@ResponseBody
@RequestMapping("/findDocs")
public String findDocs(String title) {
Map mapReturn = new HashMap(); //返回结果
try {
String result = alibabaService.findIndex(title);
mapReturn.put("returnCode","00");
mapReturn.put("content",result);
}catch (Exception e){
e.printStackTrace();
mapReturn.put("returnCode","-1");
mapReturn.put("content","查询异常");
}
String mapStr = JSONObject.toJSONString(mapReturn);
return mapStr;
}
findIndex() 方法:
// 查找索引
public String findIndex(String titleInput) throws SolrServerException {
// 声明要连接solr服务器的地址
String url = "http://localhost:8983/solr";
SolrServer solr = new HttpSolrServer(url);
// 查询条件
SolrQuery solrParams = new SolrQuery();
solrParams.setStart(0);
solrParams.setRows(10);
solrParams.setQuery("title:"+titleInput);
// 开启高亮
solrParams.setHighlight(true);
solrParams.setHighlightSimplePre("");
solrParams.setHighlightSimplePost("");
// 设置高亮的字段
solrParams.setParam("hl.fl", "title");
// SolrParams是SolrQuery的子类
QueryResponse queryResponse = solr.query(solrParams);
// (一)获取查询的结果集合
SolrDocumentList solrDocumentList = queryResponse.getResults();
List contentList = new LinkedList();
for (SolrDocument solrDocument : solrDocumentList) {
Map map = new HashMap();
map.put("id",solrDocument.get("id"));
map.put("title",solrDocument.get("title"));
contentList.add(map);
}
return contentList.toString();
}
五、首页
最后一页是前台,做的不是很好。因为我很着急,我只有一天。我白天必须去上班。晚上只能花几个小时研究后台代码。我不在乎前台。如果有时间可以美化
前端代码示例:
阿里测试题
1、先爬取文档数据
<a class="weui-btn weui-btn_mini weui-btn_primary" id="getDocs">开始爬取</a>
搜索关键词
<a class="weui-btn weui-btn_mini weui-btn_primary" id="findDocs">查询</a>
$('#getDocs').click(function () {
ajaxLoading('爬取中,请稍后...');
$.ajax({
url: "/ali/getDocs",
data: {},
type: 'post',
dataType: 'json',
success: function (data) {
ajaxLoadEnd();
$.MsgBox.Alert("提示",data.content,"确定");
},
error: function () {
$.MsgBox.Alert("异常","爬取发生异常,请联系管理员!","确定");
}
})
})
$('#findDocs').click(function () {
var keytitle = $('.keytitle').val();
if(keytitle==""){
$.MsgBox.Alert("提示","淘气!请输入内容","确定");
return
}
ajaxLoading('查询中...');
$.ajax({
url: "/ali/findDocs",
data: {"title":keytitle},
type: 'post',
dataType: 'json',
success: function (data) {
ajaxLoadEnd();
if (data.returnCode=="00"){
$.MsgBox.Alert("提示",data.content,"确定");
}else {
$.MsgBox.Alert("提示",data.content,"确定");
}
},
error: function () {
$.MsgBox.Alert("异常","查询发生异常,请联系管理员!","确定");
}
})
})
function ajaxLoading(text){
$("").css({display:"block",width:"100%",height:$(window).height()}).appendTo("body");
$("").html(text).appendTo("body").css({display:"block",left:($(document.body).outerWidth(true) - 190) / 2,top:($(window).height() - 45) / 2});
}
function ajaxLoadEnd(){
$(".datagrid-mask").remove();
$(".datagrid-mask-msg").remove();
}
六、运行渲染
这个基本没问题,也很容易完成。和我预想的还是有点不同。不过,为了赶时间,我还是赶紧发了。我在晚上 22 点 21 分左右发送的。我还以为是面试 明天官方要给出结果,但阿里这么好的公司也不是没有道理。面试官当场回复我,说我通过了。有这么敬业的程序员,这样的公司不能牛
七、总结:(附代码下载)
1.先启动solr
解压,在xxxxx/solr-4.7.0/example目录下cmd
执行命令:java -jar start.jar
2、启动项目aliTestProject
然后先点击爬取,稍等片刻,等待页面显示【爬取成功】字样,即可查询
3、查询效果图
整个项目代码下载链接:
参考文章:
感谢原作者分享,让技术人员更快解决问题