当前位置: 首页 > 科技观察

手把手教你用Flask搭建一个ES搜索引擎(准备)

时间:2023-03-17 13:00:38 科技观察

1前言Elasticsearch是一个开源的搜索引擎,建立在ApacheLucene?的基础上,是一个全文搜索引擎库。那么如何实现Elasticsearch和Python的联系就成了我们关心的问题(怎么万物都要和Python联系起来)。2Python交互因此,Python也提供了一个可以连接Elasticsearch的依赖库。pipinstallelasticsearch最初连接到Elasticsearch操作对象。def__init__(self,index_type:str,index_name:str,ip="127.0.0.1"):#self.es=Elasticsearch([ip],http_auth=('username','password'),port=9200)self.es=Elasticsearch("localhost:9200")self.index_type=index_typeself.index_name=index_name默认端口为9200,初始化前请确保本地已经搭建好Elasticsearch的环境。根据ID获取文档数据defget_doc(self,uid):returnsself.es.get(index=self.index_name,id=uid)插入文档数据definsert_one(self,doc:dict):self.es.index(index=self.index_name,doc_type=self.index_type,body=doc)definsert_array(self,docs:list):fordocindocs:self.es.index(index=self.index_name,doc_type=self.index_type,body=doc)搜索文档数据defsearch(self,query,count:int=30):dsl={"query":{"multi_match":{"query":query,"fields":["title","content","link"]}},"highlight":{"fields":{"title":{}}}}match_data=self.es.search(index=self.index_name,body=dsl,size=count)returnmatch_datadef__search(self,query:dict,count:int=20):#count:返回的数据大小results=[]params={'size':count}match_data=self.es.search(index=self.index_name,body=query,params=params)forhitinmatch_data['hits']['hits']:results.append(hit['_source'])returnresults删除文档数据defdelete_index(self):try:self.es.indices.delete(index=self.index_name)except:pass不错,对搜索类的封装也是为了方便调用,所以整体贴出来fromelasticsearchimportElasticsearchclasselasticSearch():def__init__(self,index_type:str,index_name:str,ip="127.0.0.1"):#self.es=Elasticsearch([ip],http_auth=('elastic','password'),port=9200)self.es=Elasticsearch("localhost:9200")self.index_type=index_typeself.index_name=index_namedefcreate_index(self):ifself.es.indices.exists(index=self.index_name)isTrue:self.es.indices.delete(index=self.index_name)self.es.indices.create(index=self.index_name,ignore=400)defdelete_index(self):try:self.es.indices.delete(index=self.index_name)except:passdefget_doc(self,uid):returnsself.es.get(index=self.index_name,id=uid)definsert_one(self,doc:dict):self.es.index(index=self.index_name,doc_type=self.index_type,body=doc)definsert_array(self,docs:list):fordocindocs:self.es.index(index=self.index_name,doc_type=self.index_type,body=doc)defsearch(self,query,count:int=30):dsl={“查询”:{“多匹配”:{“查询”:查询,“fields":["title","content","link"]}},"highlight":{"fields":{"title":{}}}}match_data=self.es.search(index=self.index_name,body=dsl,size=count)returnmatch_data尝试将Mongodb中的数据插入到ES中'蜘蛛').find({},{'_id':0,})es=elasticSearch(index_type="spider_data",index_name="spider")es.create_index()foriinsheet:data={'title':i["title"],'content':i["data"],'link':i["link"],'create_time':datetime.now()}es.insert_one(doc=data)toES勾选in并启动elasticsearch-head插件,如果是npm安装,则cd到根目录,直接运行npmrunstart,本地访问http://localhost:9100/,发现新添加的spider数据文件确实进入了就是这样3爬虫存储要想实现ES搜索,首先得有数据支持,大量的data往往来自爬虫。为了节省时间,写了一个简单的爬虫爬取百度百科。简单粗暴,先递归获取很多很多url链接importrequestsimportreimporttimeexist_urls=[]headers={'User-Agent':'Mozilla/5.0(WindowsNT6.1)AppleWebKit/537.36(KHTML,likeGecko)Chrome/62.0.3202.62Safari/537.36',}defget_link(url):try:response=requests.get(url=url,headers=headers)response.encoding='UTF-8'html=response.textlink_lists=re.findall('.*?]*?)".*?',html)returnlink_listsexceptExceptionase:passfinally:exist_urls.append(url)#爬取深度小于10层时,递归调用main函数继续爬取第二层所有链接defmain(start_url,depth=1):link_lists=get_link(start_url)iflink_lists:unique_lists=list(set(link_lists)-set(exist_urls))forunique_urlunique_lists:unique_url='https://baike.baidu.com/item/'+unique_urlwithopen('url.txt','a+')asf:f.write(unique_url+'\n')f.close()ifdepth<10:main(unique_url,depth+1)if__name__=='__main__':start_url='https://baike.baidu.com/item/%E7%99%BE%E5%BA%A6%E7%99%BE%E7%A7%91'main(start_url)将所有url保存在url.txt文件中,然后启动任务。#parse.pyfromceleryimportCeleryimportrequestsfromlxmlimportetreeimportpymongoapp=Celery('tasks',broker='redis://localhost:6379/2')client=pymongo.MongoClient('localhost',27017)db=client['baike']@app.taskdefget_url(链接):item={}headers={'User-Agent':'Mozilla/5.0(Macintosh;IntelMacOSX10_9_2)AppleWebKit/537.36(KHTML,likeGecko)Chrome/34.0.1847.131Safari/537.36'}res=requests.get(link,headers=headers)res.encoding='UTF-8'doc=etree.HTML(res.text)content=doc.xpath("//div[@class='lemma-summary']/div[@class='para']//text()")print(res.status_code)print(link,'\t','++++++++++++++++++++')item['link']=linkdata=''.join(content).replace('','').replace('\t','').replace('\n','').replace('\r','')item['data']=dataifdb['百客'].insert(dict(item)):print("isOK...")else:print('Fail')run.py飞从parseimportget_urldefmain(url):result=get_url.delay(url)returnresultdefrun():withopen('./url.txt','r')asf:forurlinf.readlines():main(url.strip('\n'))如果__name__=='__main__':run()在黑色窗口输入celery-Aparseworker-linfo-Pgevent-c10哦!你竟然用了Celery任务队列,gevent模式,-c是10个线程开始工作,速度太棒了!!什么?分散式?然后再增加几台机器,直接把代码复制到目标服务器上,使用redis共享队列,配合多台机器进行抓取。这里,数据先存储在MongoDB上(个人习惯)。也可以直接保存到ES,但是单条记录的插入速度堪忧(接下来会讲优化,哈哈)。使用前面的例子将Mongo中的数据批量导入ES中,OK!!!这个简单的数据捕获就完成了。好了,现在ES中有了数据,接下来就是Flaskweb的运行了。当然,Django和FastAPI也很优秀。嘿,你喜欢它!