java调用Linux执行Python爬虫,并将数据存储到elasticsearch中
一、以下博客代码使用的开发工具及环境如下:
1、idea:
2、jdk:1.8
3、elasticsearch:5.2.0
4、Linux
5、Python
6、maven
二、maven坐标:
<!--java连接ulinix脚本架包--> <dependency> <groupId>ch.ethz.ganymed</groupId> <artifactId>ganymed-ssh2</artifactId> <version>build209</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.4</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> <type>jar</type> <scope>compile</scope> </dependency>
<!--es相关坐标-->
<dependency>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>transport-netty4-client</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.nlpcn</groupId>
<artifactId>elasticsearch-sql</artifactId>
<version>6.3.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>5.2.0</version>
</dependency>
二、Linux脚本
cd /usr/local/python3/lib/python3.6/site-packages
python linux_sina.py &
三、Python爬虫脚本
#!/usr/bin/python # -*- coding: utf-8 -*- """ Created on Mon Aug 13 10:12:56 2018 @author: Administrator """ import public_python as p import urllib.request from bs4 import BeautifulSoup #存储到ES from elasticsearch import Elasticsearch import flask from flask import request server = flask.Flask(__name__) from selenium import webdriver @server.route('/news',methods=['get','post']) def get_html2(): #异常处理机制: #声明全局变量 #global title,time,strcon,cos try: url=request.values.get("url") #存储的新闻类型----用于数据库表中的字段 theme_id=request.values.get("theme_id")#----guonei--新闻类型 #无界面启动 firefox_options = webdriver.FirefoxOptions() firefox_options.add_argument('--headless') browser = webdriver.Firefox(firefox_options=firefox_options) #超时设置 #timeout=request.values.get("timeout") '''设置加载时间''' browser.set_page_load_timeout(30000) browser.set_script_timeout(30000)#这两种设置都进行才有效 browser.get(url) ''' 判断url是否包含多个链接,如果包含--即URL值不会是以.shtml结尾的字符串 那么就去获取链接里面所有的以.shtml结尾的链接url值。 ''' #存放页面中具体的url链接 data_urls=[] if ".shtml" not in url: list_father=browser.find_element_by_tag_name('body')#先定位大的标签 #存放所有<a>链接 ahref=list_father.find_elements_by_tag_name("a")#在打标签下寻找确定的小标签的集合-需要:elements。 ''' 对标签<a>进行遍历,获取其中的属性为:href的值, 然后过滤判断,如果包含.shtml,那么将href的值保存到数组,并且对数组进行set去重。 如果没包含.shtml,那么跳过本次循环。 最后调用获取数据的方法进行爬取数据 ''' for ah in ahref:#具体小标签中包含内容较多,所以还需要遍历 hr=ah.get_attribute("href")#获取连接的值 if ".shtml" in hr: #对链接进行遍历过滤 data_urls.append(hr) links=set(data_urls)#去重 else: pass continue #getcontent(links)#调用获取内容的方法: ''' 判断url是否包含多个链接,如果url包含。shtml,那么代表此url是单页的。 那么直接将url存入数组,然后调用获取数据的方法 ''' if ".shtml" in url: data_urls.append(url) links=set(data_urls)#去重 #getcontent(links) ''' #最后均去调用获取内容的方法: ''' getcontent(links) return "ok" #测试 #data_urls中包含网页中所有.shtml的链接。 ''' for i in range(len(data_urls)): print(data_urls[i]) ''' browser.quit()#完成后退出关闭浏览器 except urllib.error.URLError as e : if hasattr(e,"code"): print(e.code) return e.code if hasattr(e,"reason"): print(e.reason) return e.reason except Exception as e: print("exception:"+str(e)) return e def getcontent(data_urls): #异常处理机制: try: global title,time,strcon,cos from selenium import webdriver #存储的新闻类型----用于数据库表中的字段 theme_id=request.values.get("theme_id")#----guonei--新闻类型 #图片的前缀链接域名 #domain_name=request.values.get("domain_name") #无界面启动 firefox_options = webdriver.FirefoxOptions() firefox_options.add_argument('--headless') browser = webdriver.Firefox(firefox_options=firefox_options) ''' 连接ES集群,获取es ''' es=Elasticsearch(hosts=['192.168.200.211:9201'], maxsize=25) ''' 对传递过来的url数组进行遍历,获取每一个具体链接url(以.shtml结尾的url) ''' for url in data_urls: print(url) #具体每个标题链接,后缀是.shtml browser.get(url) conlist=[] #存储文章内容,先以数组进行保存 #判断源代码中id的值:artibodyTitle是否存在,存在的话将值内容赋值给标题变量 if "artibodyTitle" in browser.page_source: title=browser.find_element_by_id("artibodyTitle").text #判断class的值:main-title是否存在,存在的话将值内容赋值给标题变量 elif "main-title" in browser.page_source: title=browser.find_element_by_class_name("main-title").text ''' 以上是对新浪网新闻中标题存在的不同形式的判断。 ''' else: #跳过异常错误 继续执行 #pass #continue title="无法爬取标题" print(title) ''' 以下是获取时间的方式。 ''' if "pub_date" in browser.page_source: time=browser.find_element_by_id("pub_date").text elif "date" in browser.page_source: time=browser.find_element_by_class_name("date").text else: #pass #continue time="无法爬取时间" #print(time) ''' 以下是去获取正文内容。 先:打开url,并读取内容 ''' file=urllib.request.urlopen(url=url,timeout=30000) data=file.read().decode('utf-8','ignore') soup=BeautifulSoup(data,'lxml') '''#存实际的所有正文的内容--不以数组形式存储''' strcon="" ''' #内容有2中情况,一种在class=article的div下(class以“.”表示), 一种在id=artibody的div下(id以“#”表示) ''' if soup.select('.article ') : cos=soup.select('.article ') elif soup.select('#artibody '): cos=soup.select('#artibody ') ''' 判断包含内容的标签是否存在,以下代码均是在内容存在的情况下进行 ''' if cos: for i in cos: ''' 遍历内容标签,查找包含图片和段落的标签(img和p), 结果是bs4.element.ResultSet集合。 集合中每一个元素是一个tag标签 ''' alls=i.find_all(["img","p"])#传入一个字符串的列表,将匹配列表中标签的Tag全部返回 #print(type(alls)) #<class 'bs4.element.ResultSet'> #(type(alls[0])) #<class 'bs4.element.Tag'> ''' 对过滤后的标签结合进行遍历。 ''' for j in alls: #print(j) #---div-article标签下所以内容。包含标签在内 ''' #接下来需要将图片进行替换成本地图片: #第一步:将本页的图片按原名下载下来 #第二步,替换标签<img>中src的来源路径即可 ''' if j in soup.findAll("img"): #获取图片的连接url imgAllName=str(j.attrs["src"]) #图片名称 imgName=imgAllName.split("/")[-1].split(".")[0]#aaa.jpg格式--aaa #图片后缀 imgName_suffix=imgAllName.split("/")[-1].split(".")[-1]#类似jpg #将图片存入本地文件-由于网址中src缺少"http:",所以需要添加形成完整url路径 urllib.request.urlretrieve("http:"+imgAllName,"//opt//zc//img//"+imgName+"."+imgName_suffix) ''' #设置新的图片(目的:将本地图片地址去替换原来的链接地址)-本地图片的位置和图片名称链接 ''' imglink="http:/"+"/opt/zc/img/"+imgName+"."+imgName_suffix ''' #修改:图片位置存放链接,将本地图片地址去替换原来的链接地址 #j.attrs["src"]通过标签的attrs属性获取里面的属性值 ''' j.attrs["src"]=imglink #此添加的就是仅仅修改图片链接地址后全部的内容。 conlist.append((j)) ''' 遍历保存内容的数组,将其保存为一个整体 ''' for i in range(len(conlist)): strcon+=str(conlist[i]) #str:将标签内容转换成string类型 #print(strcon)#内容 ''' #以下是ES存储的时候的表字段 ''' #存储的新闻类型----用于数据库表中的字段 #theme_id=request.values.get("theme_id")#----guonei--新闻类型 #autoid 主键 #company_id="" # 公司ID #title:标题-title #content:内容-strcon ''' 对es中的索引进行判断,查看是否存在 如果不存在,那么就创建,将id的值赋值为1,然后添加数据 ''' if es.indices.exists(index=theme_id) is not True: autoid=1 #设置es中id的值 #将结果写入ES data={"id":autoid,"title":title, "content":strcon }#str(conlist)转换成str类型 否则序列化失败 #创建新索引---注意位置在此! es.indices.create(index=theme_id) p.insert_result(theme_id,"sina",data) ''' 如果索引存在的话,先查询出索引中所有内容,然后将数据进行转换成dataframe 然后去获取其中关于标题:title和主键:id的值。 ''' else: ''' #去重,先去查询ES,如果title不相同的,那么继续执行,否则跳出此循环,pass,continue 继续执行的前提下,查询ES中的id的最大值,然后每次存储,id+1 ''' res0=p.search(theme_id,"sina")#查询方法 res1=p.clean_data(res0)#对数据进行转换成:dataFrame res_title=res1[["title"]]#获取需要的部分数据dataframe-- res_id=res1[["id"]]#获取需要的部分数据dataframe #print(res_title.values)#---[[],[]]:二维数组 titles=[]#存储es中已经存在的title的集合 for i in res_title.values: #print(i)#[] [] [] for j in i: titles.append(j) ''' 以上,标题titles保存的就是一维数组 ''' ids=[]#存储es中已经存在的id的集合 for i in res_id.values: #print(i)#[] [] [] for j in i: ids.append(j) ''' 以上,主键ids:保存的就是一维数组 ''' ''' 由于每次插入数据id自动增加,所以先要去查看es中(ids)的最大值,然后每加一条记录+1。 #对ids数组进行遍历,获取最大值,#max(ids)是:<class 'numpy.int64'>,要转换成int类型 #print(type(ids))#list类型 ''' autoid_max=int(max(ids)) #设置es中id的值,自动增加1 #print(type(autoid_max))#int 类型 autoid=int(autoid_max+1) ''' 去重处理。 #print(titles)#titles:['','',''] #对title的值进行判断是否存在。--去重!!!!!,如果存在那么跳出本次循环 ''' if title in titles: #pass #continue print("已经存在此标题") else: data={"id":autoid,"title":title,"content":strcon } #调用方法,往es中插入数据 p.insert_result(theme_id,"sina",data) #seach获取---本地打印 res00=p.search(theme_id,"sina")#查询方法 print(res00) return "ok" except urllib.error.URLError as e : if hasattr(e,"code"): print("==="+e.code) return e.code if hasattr(e,"reason"): print("----"+e.reason) return e.reason except Exception as e: print("exception:"+str(e)) return e server.run(host='0.0.0.0',port=8000,debug=True)
以上Linux脚本及Python爬虫脚本,作者在此感谢我的同事张超提供。下一篇博客作者将为大家提供后台java代码(https://www.cnblogs.com/chenyuanbo/p/9973769.html)。此篇博客主要为Python爬虫都是自己书写的小伙伴参考