解決方案:python *敏*感*詞*教你基于搜索引擎實(shí)現文章查重
優(yōu)采云 發(fā)布時(shí)間: 2022-11-29 17:30解決方案:python *敏*感*詞*教你基于搜索引擎實(shí)現文章查重
前言
文章抄襲在網(wǎng)絡(luò )上很普遍,很多博主都為之煩惱。近年來(lái),隨著(zhù)互聯(lián)網(wǎng)的發(fā)展,網(wǎng)絡(luò )上抄襲等*敏*感*詞*行為愈演愈烈。甚至復制粘貼貼出原文的情況并不少見(jiàn),有的抄襲文章甚至標注了一些*敏*感*詞*,以便讀者獲取源代碼等信息。這種不良行為讓人憤慨。
本文利用搜索引擎結果作為文章數據庫,然后與本地或互聯(lián)網(wǎng)上的數據進(jìn)行相似度比對,實(shí)現文章的抄襲檢查;由于抄襲檢查的實(shí)現過(guò)程與正常情況下微博情感分析的實(shí)現過(guò)程類(lèi)似,因此很容易擴展情感分析功能(下一篇文章將根據數據完成從數據采集、清洗到情感分析的全過(guò)程本文中的代碼)。
由于近期時(shí)間不夠,暫時(shí)實(shí)現了主要功能,細節方面沒(méi)有做優(yōu)化。但是在代碼結構上做了一些簡(jiǎn)單的設計,方便以后的功能擴展和升級。我本人會(huì )不斷更新這個(gè)工具的功能,力爭讓這個(gè)工具在技術(shù)上更加成熟和實(shí)用。
技術(shù)
考慮到適應大多數站點(diǎn),本文實(shí)現的查重功能使用selenium進(jìn)行數據獲取,配置不同搜索引擎的信息,實(shí)現更通用的搜索引擎查詢(xún),不需要考慮過(guò)多的動(dòng)態(tài)數據抓??;分詞主要是利用jieba庫完成中文句子的分詞;利用余弦相似度完成文本相似度的比較,并將比較數據導出到Excel文章中,作為報表信息。
微博情感分析基于sklearn,使用樸素貝葉斯完成數據的情感分析;在數據抓取方面,實(shí)現過(guò)程類(lèi)似于文本抄襲檢查功能。
測試代碼獲取
codechina代碼庫:
環(huán)境
筆者的環(huán)境描述如下:
如有錯誤請指出并留言交流。
1.文本校驗的實(shí)現 1.1 selenium安裝配置
由于selenium的使用,需要確保讀者在使用前已經(jīng)安裝了selenium。使用pip命令安裝如下:
pip install selenium
安裝 Selenium 后,您需要下載驅動(dòng)程序。
安裝好selenium后,新建一個(gè)python文件,命名為selenium_search,先在代碼中引入
from selenium import webdriver
有的讀者可能沒(méi)有把驅動(dòng)配置進(jìn)環(huán)境,那么我們可以指定驅動(dòng)的位置(博主已經(jīng)配置進(jìn)環(huán)境):
driver = webdriver.Chrome(executable_path=r'F:\python\dr\chromedriver_win32\chromedriver.exe')
新建一個(gè)變量url賦給百度首頁(yè)鏈接,使用get方法傳入url地址,嘗試打開(kāi)百度首頁(yè),完整代碼如下:
from selenium import webdriver
url='https://www.baidu.com'
driver=webdriver.Chrome()
driver.get(url)
使用命令行運行小黑框里的python文件(windows下):
運行腳本后,谷歌瀏覽器將被打開(kāi)并重定向到百度首頁(yè):
這樣就成功使用selenium打開(kāi)了指定的url,然后會(huì )查詢(xún)指定的搜索關(guān)鍵詞得到結果,然后從結果中遍歷出類(lèi)似的數據。
1.2 selenium百度搜索引擎關(guān)鍵詞搜索
在自動(dòng)操縱瀏覽器向搜索框輸入關(guān)鍵詞之前,需要獲取搜索框元素對象。使用谷歌瀏覽器打開(kāi)百度首頁(yè),右擊搜索框選擇查看,會(huì )彈出網(wǎng)頁(yè)元素(代碼)查看窗口,找到搜索框元素(用鼠標在元素節點(diǎn)中移動(dòng),元素鼠標當前位置的節點(diǎn)將對應網(wǎng)頁(yè)中藍色的索引):
在html代碼中,id的值在大多數情況下是唯一的(除非是錯別字),這里選擇id作為獲取搜索框元素對象的標簽。Selenium提供了find_element_by_id方法,可以通過(guò)傳入id獲取網(wǎng)頁(yè)元素對象。
input=driver.find_element_by_id('kw')
獲取元素對象后,使用send_keys方法傳入需要鍵入的值:
input.send_keys('php基礎教程 第十一步 面向對象')
這里我傳入“php基礎教程step 11 面向對象”作為關(guān)鍵字作為搜索。運行腳本以查看是否在搜索框中鍵入了關(guān)鍵字。代碼如下:
input.send_keys('php基礎教程 第十一步 面向對象')
成功打開(kāi)瀏覽器并輸入搜索關(guān)鍵字:
現在只需點(diǎn)擊“百度點(diǎn)擊”按鈕即可完成最終搜索。使用與查看搜索框相同的元素查看方法找到“百度”按鈕的id值:
使用find_element_by_id方法獲取元素對象,然后使用click方法讓按鈕完成點(diǎn)擊操作:
search_btn=driver.find_element_by_id('su')
search_btn.click()
完整代碼如下:
from selenium import webdriver
url='https://www.baidu.com'
driver=webdriver.Chrome()
driver.get(url)
input=driver.find_element_by_id('kw')
input.send_keys('php基礎教程 第十一步 面向對象')
search_btn=driver.find_element_by_id('su')
search_btn.click()
瀏覽器自動(dòng)完成搜索關(guān)鍵字的輸入和搜索功能:
1.3 搜索結果遍歷
目前已經(jīng)在瀏覽器中獲取到搜索結果,下一步就是獲取整個(gè)網(wǎng)頁(yè)內容獲取搜索結果。用selenium獲取不是很方便。這里使用BeautifulSoup來(lái)解析整個(gè)網(wǎng)頁(yè)并獲取搜索結果。
BeautifulSoup是一個(gè)HTML/XML解析器,使用BeautifulSoup將極大方便我們獲取整個(gè)html信息。
在使用 BeautifulSoup 之前確保已安裝它。安裝命令如下:
pip install BeautifulSoup
安裝完成后,在當前python文件的頭部引入:
from bs4 import BeautifulSoup
要獲取 html 文本,您可以調用 page_source:
html=driver.page_source
得到html代碼后,創(chuàng )建一個(gè)BeautifulSoup對象,傳入html內容并指定解析器,這里指定html.parser解析器:
soup = BeautifulSoup(html, "html.parser")
接下來(lái)查看搜索內容,發(fā)現所有結果都收錄
在一個(gè)h標簽中,類(lèi)別為t:
BeautifulSoup提供了select方法獲取標簽,支持通過(guò)類(lèi)名、標簽名、id、屬性、組合進(jìn)行搜索。我們發(fā)現在百度搜索結果中,所有的結果都有一個(gè)class="t",這時(shí)候遍歷類(lèi)名是最方便的:
search_res_list=soup.select('.t')
在select方法中,傳入類(lèi)名t,在類(lèi)名前加一個(gè)點(diǎn)(.),表示通過(guò)類(lèi)名獲取元素。
完成這一步后,可以添加print來(lái)嘗試打印出結果:
print(search_res_list)
一般情況下,輸出的search_res_list可能是一個(gè)空列表。這是因為在瀏覽器解析數據并呈現給瀏覽器之前,我們已經(jīng)獲取了瀏覽器當前頁(yè)面的內容。有一個(gè)簡(jiǎn)單的方法可以解決這個(gè)問(wèn)題,但是這個(gè)方法效率不高,暫時(shí)只用到這里,以后會(huì )換成其他比這個(gè)方法效率更高的代碼(使用時(shí)間需要介紹在標題中):
time.sleep(2)
完整代碼如下:
from selenium import webdriver
from bs4 import BeautifulSoup
import time
url='https://www.baidu.com'
driver=webdriver.Chrome()
driver.get(url)
input=driver.find_element_by_id('kw')
input.send_keys('php基礎教程 第十一步 面向對象')
search_btn=driver.find_element_by_id('su')
search_btn.click()
time.sleep(2)#在此等待 使瀏覽器解析并渲染到瀏覽器
html=driver.page_source #獲取網(wǎng)頁(yè)內容
soup = BeautifulSoup(html, "html.parser")
search_res_list=soup.select('.t')
print(search_res_list)
運行程序會(huì )輸出:
得到的結果都是類(lèi)t的標簽,包括標簽的子節點(diǎn),子節點(diǎn)元素可以通過(guò)點(diǎn)(.)操作得到。通過(guò)瀏覽器獲取的搜索內容都是鏈接,點(diǎn)擊跳轉,那么只需要獲取每個(gè)元素下的a標簽即可:
for el in search_res_list:
print(el.a)
從結果中可以看出,已經(jīng)得到了搜索結果的a標簽,那么接下來(lái)我們要做的就是提取每個(gè)a標簽中的href超鏈接。使用list獲取元素直接獲取href超鏈接:
for el in search_res_list:
print(el.a['href'])
成功運行腳本會(huì )導致:
細心的讀者可能會(huì )發(fā)現,得到的結果都是百度網(wǎng)址。其實(shí)這些URL可以說(shuō)是“索引”,通過(guò)這些索引再次跳轉到真正的URL。由于這些“索引”不一定會(huì )變,也不利于長(cháng)期保存,所以這里還是需要獲取真實(shí)的鏈接。
我們調用js腳本來(lái)訪(fǎng)問(wèn)這些url,這些url會(huì )跳轉到真實(shí)的url,跳轉后獲取當前的url信息。調用execute_script方法執行js代碼,代碼如下:
for el in search_res_list:
js = 'window.open("'+el.a['href']+'")'
driver.execute_script(js)
打開(kāi)新網(wǎng)頁(yè)后,需要獲取新網(wǎng)頁(yè)的句柄,否則無(wú)法操作新網(wǎng)頁(yè)。獲取句柄的方法如下:
handle_this=driver.current_window_handle#獲取當前句柄
handle_all=driver.window_handles#獲取所有句柄
獲取句柄后,需要將當前操作的對象切換到新的頁(yè)面。由于打開(kāi)一個(gè)頁(yè)面后只有2個(gè)頁(yè)面,所以干脆使用遍歷進(jìn)行替換:
handle_exchange=None#要切換的句柄
for handle in handle_all:#不匹配為新句柄
if handle != handle_this:#不等于當前句柄就交換
handle_exchange = handle
driver.switch_to.window(handle_exchange)#切換
切換后,操作對象為當前剛打開(kāi)的頁(yè)面。通過(guò)current_url屬性獲取新頁(yè)面的url:
real_url=driver.current_url
print(real_url)
然后關(guān)閉當前頁(yè)面,將操作對象設置為初始頁(yè)面:
driver.close()
driver.switch_to.window(handle_this)#換回最初始界面
運行腳本成功獲取真實(shí)url:
最后用一個(gè)list來(lái)存儲得到真實(shí)url后的結果:
real_url_list.append(real_url)
該部分完整代碼如下:
from selenium import webdriver
from bs4 import BeautifulSoup
import time
url='https://www.baidu.com'
driver=webdriver.Chrome()
driver.get(url)
input=driver.find_element_by_id('kw')
input.send_keys('php基礎教程 第十一步 面向對象')
search_btn=driver.find_element_by_id('su')
search_btn.click()
time.sleep(2)#在此等待 使瀏覽器解析并渲染到瀏覽器
html=driver.page_source
soup = BeautifulSoup(html, "html.parser")
search_res_list=soup.select('.t')
real_url_list=[]
# print(search_res_list)
for el in search_res_list:
js = 'window.open("'+el.a['href']+'")'
driver.execute_script(js)
handle_this=driver.current_window_handle#獲取當前句柄
handle_all=driver.window_handles#獲取所有句柄
handle_exchange=None#要切換的句柄
for handle in handle_all:#不匹配為新句柄
if handle != handle_this:#不等于當前句柄就交換
handle_exchange = handle
driver.switch_to.window(handle_exchange)#切換
real_url=driver.current_url
print(real_url)
real_url_list.append(real_url)#存儲結果
driver.close()
driver.switch_to.window(handle_this)
1.4 獲取源文本
在當前文件所在目錄下新建一個(gè)文件夾,命名為textsrc,在該目錄下新建一個(gè)txt文件,在text中存放要比較的文本。我這里存放的內容是《PHP基礎教程面向對象第十一步》一文的內容。
在代碼中寫(xiě)一個(gè)函數獲取文本內容:
def read_txt(path=''):
f = open(path,'r')
return f.read()
src=read_txt(r'F:\tool\textsrc\src.txt')
為了測試方便,這里使用絕對路徑。
得到文本內容后,寫(xiě)一個(gè)余弦相似度的比較方法。
1.5 余弦相似度
相似度計算參考《Python實(shí)現余弦相似度文本比較》一文,我修改了一部分實(shí)現。
本文相似度比較采用余弦相似度算法,大致步驟分為分詞->向量計算->計算相似度。
創(chuàng )建一個(gè)名為 Analyze 的新 Python 文件。新建一個(gè)類(lèi)叫Analyze,在類(lèi)中添加一個(gè)分詞方法,在head中引入jieba分詞庫,采集
數統計:
from jieba import lcut
import jieba.analyse
import collections
計數方法:
#分詞
def Count(self,text):
tag = jieba.analyse.textrank(text,topK=20)
word_counts = collections.Counter(tag) #計數統計
return word_counts
Count方法接收一個(gè)文本變量,為text,使用textrank方法分詞,使用Counter計數。
然后添加MergeWord方法,方便詞合并后的向量計算:
#詞合并
def MergeWord(self,T1,T2):
MergeWord = []
for i in T1:
MergeWord.append(i)
for i in T2:
if i not in MergeWord:
MergeWord.append(i)
return MergeWord
合并的方法很簡(jiǎn)單,就不解釋了。接下來(lái)添加向量計算方法:
# 得出文檔向量
def CalVector(self,T1,MergeWord):
TF1 = [0] * len(MergeWord)
for ch in T1:
TermFrequence = T1[ch]
word = ch
if word in MergeWord:
TF1[MergeWord.index(word)] = TermFrequence
return TF1
最后添加相似度計算方法:
def cosine_similarity(self,vector1, vector2):
dot_product = 0.0
normA = 0.0
normB = 0.0
for a, b in zip(vector1, vector2):#兩個(gè)向量組合成 [(1, 4), (2, 5), (3, 6)] 最短形式表現
dot_product += a * b
normA += a ** 2
normB += b ** 2
if normA == 0.0 or normB == 0.0:
return 0
else:
return round(dot_product / ((normA**0.5)*(normB**0.5))*100, 2)
相似度方法采用兩個(gè)向量,計算相似度并將其返回。為了減少代碼冗余,這里簡(jiǎn)單的增加一個(gè)方法來(lái)完成計算過(guò)程:
def get_Tfidf(self,text1,text2):#測試對比本地數據對比搜索引擎方法
# self.correlate.word.set_this_url(url)
T1 = self.Count(text1)
T2 = self.Count(text2)
mergeword = self.MergeWord(T1,T2)
return self.cosine_similarity(self.CalVector(T1,mergeword),self.CalVector(T2,mergeword))
Analyze類(lèi)的完整代碼如下:
from jieba import lcut
import jieba.analyse
import collections
class Analyse:
def get_Tfidf(self,text1,text2):#測試對比本地數據對比搜索引擎方法
# self.correlate.word.set_this_url(url)
T1 = self.Count(text1)
T2 = self.Count(text2)
mergeword = self.MergeWord(T1,T2)
return self.cosine_similarity(self.CalVector(T1,mergeword),self.CalVector(T2,mergeword))
#分詞
def Count(self,text):
tag = jieba.analyse.textrank(text,topK=20)
word_counts = collections.Counter(tag) #計數統計
return word_counts
#詞合并
def MergeWord(self,T1,T2):
MergeWord = []
for i in T1:
MergeWord.append(i)
for i in T2:
if i not in MergeWord:
MergeWord.append(i)
return MergeWord
# 得出文檔向量
def CalVector(self,T1,MergeWord):
TF1 = [0] * len(MergeWord)
for ch in T1:
TermFrequence = T1[ch]
word = ch
if word in MergeWord:
TF1[MergeWord.index(word)] = TermFrequence
return TF1
#計算 TF-IDF
def cosine_similarity(self,vector1, vector2):
dot_product = 0.0
normA = 0.0
normB = 0.0
for a, b in zip(vector1, vector2):#兩個(gè)向量組合成 [(1, 4), (2, 5), (3, 6)] 最短形式表現
dot_product += a * b
<p>
" />
normA += a ** 2
normB += b ** 2
if normA == 0.0 or normB == 0.0:
return 0
else:
return round(dot_product / ((normA**0.5)*(normB**0.5))*100, 2)
</p>
1.6 比較搜索結果內容與文本的相似度
在selenium_search文件中引入Analyze,新建一個(gè)對象:
from Analyse import Analyse
Analyse=Analyse()
將新打開(kāi)頁(yè)面的網(wǎng)頁(yè)內容添加到遍歷的搜索結果中:
time.sleep(5)
html_2=driver.page_source
使用 time.sleep(5) 等待瀏覽器有時(shí)間渲染當前網(wǎng)頁(yè)內容。獲取新打開(kāi)頁(yè)面的內容后,比較相似度:
Analyse.get_Tfidf(src,html_2)
既然返回了一個(gè)值,那么用print輸出:
print('相似度:',Analyse.get_Tfidf(src,html_2))
完整代碼如下:
from selenium import webdriver
from bs4 import BeautifulSoup
import time
from Analyse import Analyse
def read_txt(path=''):
f = open(path,'r')
return f.read()
#獲取對比文件
src=read_txt(r'F:\tool\textsrc\src.txt')
Analyse=Analyse()
url='https://www.baidu.com'
driver=webdriver.Chrome()
driver.get(url)
input=driver.find_element_by_id('kw')
input.send_keys('php基礎教程 第十一步 面向對象')
search_btn=driver.find_element_by_id('su')
search_btn.click()
time.sleep(2)#在此等待 使瀏覽器解析并渲染到瀏覽器
html=driver.page_source
soup = BeautifulSoup(html, "html.parser")
search_res_list=soup.select('.t')
real_url_list=[]
# print(search_res_list)
for el in search_res_list:
js = 'window.open("'+el.a['href']+'")'
driver.execute_script(js)
handle_this=driver.current_window_handle#獲取當前句柄
handle_all=driver.window_handles#獲取所有句柄
handle_exchange=None#要切換的句柄
for handle in handle_all:#不匹配為新句柄
if handle != handle_this:#不等于當前句柄就交換
handle_exchange = handle
driver.switch_to.window(handle_exchange)#切換
real_url=driver.current_url
time.sleep(5)
html_2=driver.page_source
print('相似度:',Analyse.get_Tfidf(src,html_2))
print(real_url)
real_url_list.append(real_url)
driver.close()
driver.switch_to.window(handle_this)
運行腳本:
結果顯示有幾個(gè)高度相似的鏈接,因此這些是涉嫌抄襲的文章。
上面是完成基本查重的代碼,但是和代碼相比,顯得冗余和凌亂。接下來(lái),讓我們優(yōu)化代碼。
2.代碼優(yōu)化
通過(guò)上面的程序編程,大致可以分為:獲取搜索內容->獲取結果->計算相似度。我們可以新建三個(gè)類(lèi),分別是:Browser、Analyze(新創(chuàng )建的)、SearchEngine。
瀏覽器用于搜索、數據獲取等;Analyze用于相似度分析、向量計算等;SearchEngine用于不同搜索引擎的基礎配置,因為大部分搜索引擎的搜索方式都比較一致。
2.1瀏覽器類(lèi)
初始化
新建一個(gè)名為 Browser 的 python 文件,并添加一個(gè)初始化方法:
def __init__(self,conf):
self.browser=webdriver.Chrome()
self.conf=conf
self.engine_conf=EngineConfManage().get_Engine_conf(conf['engine']).get_conf()
self.browser=webdriver.Chrome() 是創(chuàng )建一個(gè)新的瀏覽器對象;conf是傳入的搜索配置,然后通過(guò)編寫(xiě)配置字典來(lái)實(shí)現搜索內容;self.engine_conf=EngineConfManage().get_Engine_conf(conf['engine'] ).get_conf()是獲取搜索引擎的配置。不同搜索引擎的輸入框和搜索按鈕不一致,通過(guò)不同的配置信息實(shí)現多搜索引擎搜索。
添加搜索方法
#搜索內容寫(xiě)入到搜素引擎中
def send_keyword(self):
input = self.browser.find_element_by_id(self.engine_conf['searchTextID'])
input.send_keys(self.conf['kw'])
上述方法中self.engine_conf['searchTextID']和self.conf['kw']通過(guò)初始化方法獲取對應的搜索引擎配置信息,直接獲取信息獲取元素。
點(diǎn)擊搜索
#搜索框點(diǎn)擊
def click_search_btn(self):
search_btn = self.browser.find_element_by_id(self.engine_conf['searchBtnID'])
search_btn.click()
使用 self.engine_conf['searchBtnID'] 獲取搜索按鈕的 ID。
獲取搜索結果和文本
#獲取搜索結果與文本
def get_search_res_url(self):
res_link={}
WebDriverWait(self.browser,timeout=30,poll_frequency=1).until(EC.presence_of_element_located((By.ID, "page")))
#內容通過(guò) BeautifulSoup 解析
content=self.browser.page_source
soup = BeautifulSoup(content, "html.parser")
search_res_list=soup.select('.'+self.engine_conf['searchContentHref_class'])
for el in search_res_list:
js = 'window.open("'+el.a['href']+'")'
self.browser.execute_script(js)
handle_this=self.browser.current_window_handle #獲取當前句柄
handle_all=self.browser.window_handles #獲取所有句柄
handle_exchange=None #要切換的句柄
for handle in handle_all: #不匹配為新句柄
if handle != handle_this: #不等于當前句柄就交換
handle_exchange = handle
self.browser.switch_to.window(handle_exchange) #切換
real_url=self.browser.current_url
time.sleep(1)
res_link[real_url]=self.browser.page_source #結果獲取
self.browser.close()
self.browser.switch_to.window(handle_this)
return res_link
上面的方法和之前寫(xiě)的遍歷搜索結果類(lèi)似,添加WebDriverWait(self.browser,timeout=30,poll_frequency=1).until(EC.presence_of_element_located((By.ID, "page")))代替sleep ,用于判斷EC.presence_of_element_located((By.ID, "page")) 是否找到一個(gè)id為page的網(wǎng)頁(yè)元素,id為page的網(wǎng)頁(yè)元素為分頁(yè)按鈕的標簽id。如果沒(méi)有獲取到,說(shuō)明當前網(wǎng)頁(yè)沒(méi)有加載完成,等待時(shí)間timeout=3030秒,如果已經(jīng)過(guò)去,則跳過(guò)等待。
上面的代碼并沒(méi)有比較相似度,而是通過(guò)res_link[real_url]=self.browser.page_source將內容和url存入字典,然后返回,再進(jìn)行相似度比較,有利于以后的功能擴展。
打開(kāi)目標搜索引擎進(jìn)行搜索
#打開(kāi)目標搜索引擎進(jìn)行搜索
def search(self):
self.browser.get(self.engine_conf['website']) #打開(kāi)搜索引擎站點(diǎn)
self.send_keyword() #輸入搜索kw
self.click_search_btn() #點(diǎn)擊搜索
return self.get_search_res_url() #獲取web頁(yè)搜索數據
最后添加一個(gè)search方法,直接調用search方法即可實(shí)現前面的所有操作,無(wú)需過(guò)多暴露,簡(jiǎn)化使用。
完整代碼如下:
from selenium import webdriver
from bs4 import BeautifulSoup
from SearchEngine import EngineConfManage
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
class Browser:
def __init__(self,conf):
self.browser=webdriver.Chrome()
self.conf=conf
self.engine_conf=EngineConfManage().get_Engine_conf(conf['engine']).get_conf()
#搜索內容寫(xiě)入到搜素引擎中
def send_keyword(self):
input = self.browser.find_element_by_id(self.engine_conf['searchTextID'])
input.send_keys(self.conf['kw'])
#搜索框點(diǎn)擊
def click_search_btn(self):
search_btn = self.browser.find_element_by_id(self.engine_conf['searchBtnID'])
search_btn.click()
#獲取搜索結果與文本
def get_search_res_url(self):
res_link={}
WebDriverWait(self.browser,timeout=30,poll_frequency=1).until(EC.presence_of_element_located((By.ID, "page")))
#內容通過(guò) BeautifulSoup 解析
content=self.browser.page_source
soup = BeautifulSoup(content, "html.parser")
search_res_list=soup.select('.'+self.engine_conf['searchContentHref_class'])
for el in search_res_list:
js = 'window.open("'+el.a['href']+'")'
self.browser.execute_script(js)
handle_this=self.browser.current_window_handle #獲取當前句柄
handle_all=self.browser.window_handles #獲取所有句柄
handle_exchange=None #要切換的句柄
for handle in handle_all: #不匹配為新句柄
if handle != handle_this: #不等于當前句柄就交換
handle_exchange = handle
self.browser.switch_to.window(handle_exchange) #切換
real_url=self.browser.current_url
time.sleep(1)
res_link[real_url]=self.browser.page_source #結果獲取
self.browser.close()
self.browser.switch_to.window(handle_this)
return res_link
#打開(kāi)目標搜索引擎進(jìn)行搜索
def search(self):
self.browser.get(self.engine_conf['website']) #打開(kāi)搜索引擎站點(diǎn)
self.send_keyword() #輸入搜索kw
self.click_search_btn() #點(diǎn)擊搜索
return self.get_search_res_url() #獲取web頁(yè)搜索數據
2.2SearchEngine類(lèi)
SearchEngine類(lèi)主要用于不同搜索引擎的配置編寫(xiě)。更容易實(shí)現搜索引擎或類(lèi)似業(yè)務(wù)的擴展。
#搜索引擎配置
class EngineConfManage:
def get_Engine_conf(self,engine_name):
if engine_name=='baidu':
return BaiduEngineConf()
elif engine_name=='qihu360':
return Qihu360EngineConf()
elif engine_name=='sougou':
return SougouEngineConf()
class EngineConf:
def __init__(self):
self.engineConf={}
def get_conf(self):
return self.engineConf
class BaiduEngineConf(EngineConf):
engineConf={}
def __init__(self):
self.engineConf['searchTextID']='kw'
self.engineConf['searchBtnID']='su'
self.engineConf['nextPageBtnID_xpath_f']='//*[@id="page"]/div/a[10]'
self.engineConf['nextPageBtnID_xpath_s']='//*[@id="page"]/div/a[11]'
self.engineConf['searchContentHref_class']='t'
self.engineConf['website']='http://www.baidu.com'
class Qihu360EngineConf(EngineConf):
def __init__(self):
pass
class SougouEngineConf(EngineConf):
def __init__(self):
pass
這里只實(shí)現了百度搜索引擎的配置。各種搜索引擎都繼承了EngineConf基類(lèi),所以子類(lèi)都有g(shù)et_conf方法。EngineConfManage類(lèi)用于調用不同的搜索引擎,傳入引擎名稱(chēng)即可。
2.3 如何使用
先介紹兩個(gè)類(lèi):
from Browser import Browser
from Analyse import Analyse
創(chuàng )建一個(gè)讀取本地文件的新方法:
def read_txt(path=''):
f = open(path,'r')
return f.read()
獲取文件并新建一個(gè)數據分析類(lèi):
src=read_txt(r'F:\tool\textsrc\src.txt')#獲取本地文本
Analyse=Analyse()
配置信息字典寫(xiě)法:
#配置信息
conf={
'kw':'php基礎教程 第十一步 面向對象',
'engine':'baidu',
}
新建一個(gè)Browser類(lèi),傳入配置信息:
drvier=Browser(conf)
獲取搜索結果和內容
url_content=drvier.search()#獲取搜索結果及內容
遍歷結果,計算相似度:
for k in url_content:
print(k,'相似度:',Analyse.get_Tfidf(src,url_content[k]))
完整代碼如下:
from Browser import Browser
from Analyse import Analyse
def read_txt(path=''):
f = open(path,'r')
return f.read()
src=read_txt(r'F:\tool\textsrc\src.txt')#獲取本地文本
Analyse=Analyse()
#配置信息
conf={
'kw':'php基礎教程 第十一步 面向對象',
'engine':'baidu',
}
drvier=Browser(conf)
url_content=drvier.search()#獲取搜索結果及內容
for k in url_content:
print(k,'相似度:',Analyse.get_Tfidf(src,url_content[k]))
你覺(jué)得更舒服嗎?簡(jiǎn)直不要太清爽。你認為這是結束了嗎?還沒(méi)完,接下來(lái)我們來(lái)擴展一下功能。
3、功能擴展
暫時(shí)這個(gè)小工具的功能只是檢查重量的基本功能,這里面還有很多問(wèn)題。如果沒(méi)有白名單過(guò)濾,只能查一篇文章的相似度,偷懶的話(huà),沒(méi)有直接獲取文章列表自動(dòng)查重并導出結果的功能。接下來(lái)會(huì )逐步完善一些功能。限于篇幅,實(shí)現的功能這里就不一一列舉了,以后會(huì )不斷更新。
3.1 自動(dòng)獲取文本
創(chuàng )建一個(gè)名為 FileHandle 的新 Python 文件。該類(lèi)用于自動(dòng)獲取指定目錄下的txt文件,txt文件的名稱(chēng)為關(guān)鍵字,內容為該名稱(chēng)的文章內容。類(lèi)代碼如下:
import os
class FileHandle:
#獲取文件內容
def get_content(self,path):
f = open(path,"r") #設置文件對象
content = f.read() #將txt文件的所有內容讀入到字符串str中
f.close() #將文件關(guān)閉
return content
#獲取文件內容
def get_text(self):
file_path=os.path.dirname(__file__) #當前文件所在目錄
txt_path=file_path+r'\textsrc' #txt目錄
rootdir=os.path.join(txt_path) #目標目錄內容
local_text={}
# 讀txt 文件
<p>
" />
for (dirpath,dirnames,filenames) in os.walk(rootdir):
for filename in filenames:
if os.path.splitext(filename)[1]=='.txt':
flag_file_path=dirpath+'\\'+filename #文件路徑
flag_file_content=self.get_content(flag_file_path) #讀文件路徑
if flag_file_content!='':
local_text[filename.replace('.txt', '')]=flag_file_content #鍵值對內容
return local_text
</p>
有兩個(gè)方法get_content 和get_text。get_text是獲取目錄下所有的txt文件路徑,通過(guò)get_content獲取詳細的文本內容,返回local_text;local_text key是文件名,value是文本內容。
3.2BrowserManage類(lèi)
在Browser類(lèi)文件中添加一個(gè)繼承自Browser的BrowserManage類(lèi),并添加方法:
#打開(kāi)目標搜索引擎進(jìn)行搜索
def search(self):
self.browser.get(self.engine_conf['website']) #打開(kāi)搜索引擎站點(diǎn)
self.send_keyword() #輸入搜索kw
self.click_search_btn() #點(diǎn)擊搜索
return self.get_search_res_url() #獲取web頁(yè)搜索數據
添加這個(gè)類(lèi)將 Browser 類(lèi)的邏輯與其他方法分開(kāi),以便于擴展。
3.3 Browser類(lèi)的擴展
在Browser類(lèi)中添加next page方法,這樣在搜索內容的時(shí)候可以獲取更多的內容,可以指定獲取結果的個(gè)數:
#下一頁(yè)
def click_next_page(self,md5):
WebDriverWait(self.browser,timeout=30,poll_frequency=1).until(EC.presence_of_element_located((By.ID, "page")))
#百度搜索引擎翻頁(yè)后下一頁(yè)按鈕 xpath 不一致 默認非第一頁(yè)xpath
try:
next_page_btn = self.browser.find_element_by_xpath(self.engine_conf['nextPageBtnID_xpath_s'])
except:
next_page_btn = self.browser.find_element_by_xpath(self.engine_conf['nextPageBtnID_xpath_f'])
next_page_btn.click()
#md5 進(jìn)行 webpag text 對比,判斷是否已翻頁(yè) (暫時(shí)使用,存在bug)
i=0
while md5==hashlib.md5(self.browser.page_source.encode(encoding='UTF-8')).hexdigest():#md5 對比
time.sleep(0.3)#防止一些錯誤,暫時(shí)使用強制停止保持一些穩定
i+=1
if i>100:
return False
return True
百度搜索引擎翻頁(yè)后,下一頁(yè)按鈕的xpath不一致。默認不是第一頁(yè)的xpath。如果出現異常,則使用另一個(gè) xpath。然后在頁(yè)面上進(jìn)行md5,比較md5值。如果當前頁(yè)面沒(méi)有刷新,md5值不會(huì )改變。稍等片刻,然后單擊下一頁(yè)。
3.4 修改get_search_res_url方法
修改了get_search_res_url方法的部分內容,添加指定數量的結果,獲取下一頁(yè)內容,更改白名單設置后的代碼如下:
<p>#獲取搜索結果與文本
def get_search_res_url(self):
res_link={}
WebDriverWait(self.browser,timeout=30,poll_frequency=1).until(EC.presence_of_element_located((By.ID, "page")))
#內容通過(guò) BeautifulSoup 解析
content=self.browser.page_source
soup = BeautifulSoup(content, "html.parser")
search_res_list=soup.select('.'+self.engine_conf['searchContentHref_class'])
while len(res_link)