java呼叫Linux執行Python爬蟲,並將資料儲存到elasticsearch--(一、環境指令碼搭建)
阿新 • • 發佈:2018-12-22
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
<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程式碼。此篇部落格主要為Python爬蟲都是自己書寫的小夥伴參考