解决方案:python *敏*感*词*教你基于搜索引擎实现文章查重
优采云 发布时间: 2022-11-29 17:30解决方案:python *敏*感*词*教你基于搜索引擎实现文章查重
前言
文章抄袭在网络上很普遍,很多博主都为之烦恼。近年来,随着互联网的发展,网络上抄袭等*敏*感*词*行为愈演愈烈。甚至复制粘贴贴出原文的情况并不少见,有的抄袭文章甚至标注了一些*敏*感*词*,以便读者获取源代码等信息。这种不良行为让人愤慨。
本文利用搜索引擎结果作为文章数据库,然后与本地或互联网上的数据进行相似度比对,实现文章的抄袭检查;由于抄袭检查的实现过程与正常情况下微博情感分析的实现过程类似,因此很容易扩展情感分析功能(下一篇文章将根据数据完成从数据采集、清洗到情感分析的*敏*感*词*本文中的代码)。
由于近期时间不够,暂时实现了主要功能,细节方面没有做优化。但是在代码结构上做了一些简单的设计,方便以后的功能扩展和升级。我本人会不断更新这个工具的功能,力争让这个工具在技术上更加成熟和实用。
技术
考虑到适应大多数站点,本文实现的查重功能使用selenium进行数据获取,配置不同搜索引擎的信息,实现更通用的搜索引擎查询,不需要考虑过多的动态数据抓取;分词主要是利用jieba库完成中文句子的分词;利用余弦相似度完成文本相似度的比较,并将比较数据导出到Excel文章中,作为报表信息。
微博情感分析基于sklearn,使用朴素贝叶斯完成数据的情感分析;在数据抓取方面,实现过程类似于文本抄袭检查功能。
测试代码获取
codechina代码库:
环境
笔者的环境描述如下:
如有错误请指出并留言交流。
1.文本校验的实现 1.1 selenium安装配置
由于selenium的使用,需要确保读者在使用前已经安装了selenium。使用pip命令安装如下:
pip install selenium
安装 Selenium 后,您需要下载驱动程序。
安装好selenium后,新建一个python文件,命名为selenium_search,先在代码中引入
from selenium import webdriver
有的读者可能没有把驱动配置进环境,那么我们可以指定驱动的位置(博主已经配置进环境):
driver = webdriver.Chrome(executable_path=r'F:\python\dr\chromedriver_win32\chromedriver.exe')
新建一个变量url赋给百度首页链接,使用get方法传入url地址,尝试打开百度首页,完整代码如下:
from selenium import webdriver
url='https://www.baidu.com'
driver=webdriver.Chrome()
driver.get(url)
使用命令行运行小黑框里的python文件(windows下):
运行脚本后,谷歌浏览器将被打开并重定向到百度首页:
这样就成功使用selenium打开了指定的url,然后会查询指定的搜索关键词得到结果,然后从结果中遍历出类似的数据。
1.2 selenium百度搜索引擎关键词搜索
在自动操纵浏览器向搜索框输入关键词之前,需要获取搜索框元素对象。使用谷歌浏览器打开百度首页,右击搜索框选择查看,会弹出网页元素(代码)查看窗口,找到搜索框元素(用鼠标在元素节点中移动,元素鼠标当前位置的节点将对应网页中蓝色的索引):
在html代码中,id的值在大多数情况下是唯一的(除非是错别字),这里选择id作为获取搜索框元素对象的标签。Selenium提供了find_element_by_id方法,可以通过传入id获取网页元素对象。
input=driver.find_element_by_id('kw')
获取元素对象后,使用send_keys方法传入需要键入的值:
input.send_keys('php基础教程 第十一步 面向对象')
这里我传入“php基础教程step 11 面向对象”作为关键字作为搜索。运行脚本以查看是否在搜索框中键入了关键字。代码如下:
input.send_keys('php基础教程 第十一步 面向对象')
成功打开浏览器并输入搜索关键字:
现在只需点击“百度点击”按钮即可完成最终搜索。使用与查看搜索框相同的元素查看方法找到“百度”按钮的id值:
使用find_element_by_id方法获取元素对象,然后使用click方法让按钮完成点击操作:
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()
浏览器自动完成搜索关键字的输入和搜索功能:
1.3 搜索结果遍历
目前已经在浏览器中获取到搜索结果,下一步就是获取整个网页内容获取搜索结果。用selenium获取不是很方便。这里使用BeautifulSoup来解析整个网页并获取搜索结果。
BeautifulSoup是一个HTML/XML解析器,使用BeautifulSoup将极大方便我们获取整个html信息。
在使用 BeautifulSoup 之前确保已安装它。安装命令如下:
pip install BeautifulSoup
安装完成后,在当前python文件的头部引入:
from bs4 import BeautifulSoup
要获取 html 文本,您可以调用 page_source:
html=driver.page_source
得到html代码后,创建一个BeautifulSoup对象,传入html内容并指定解析器,这里指定html.parser解析器:
soup = BeautifulSoup(html, "html.parser")
接下来查看搜索内容,发现所有结果都收录
在一个h标签中,类别为t:
BeautifulSoup提供了select方法获取标签,支持通过类名、标签名、id、属性、组合进行搜索。我们发现在百度搜索结果中,所有的结果都有一个class="t",这时候遍历类名是最方便的:
search_res_list=soup.select('.t')
在select方法中,传入类名t,在类名前加一个点(.),表示通过类名获取元素。
完成这一步后,可以添加print来尝试打印出结果:
print(search_res_list)
一般情况下,输出的search_res_list可能是一个空列表。这是因为在浏览器解析数据并呈现给浏览器之前,我们已经获取了浏览器当前页面的内容。有一个简单的方法可以解决这个问题,但是这个方法效率不高,暂时只用到这里,以后会换成其他比这个方法效率更高的代码(使用时间需要介绍在标题中):
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 #获取网页内容
soup = BeautifulSoup(html, "html.parser")
search_res_list=soup.select('.t')
print(search_res_list)
运行程序会输出:
得到的结果都是类t的标签,包括标签的子节点,子节点元素可以通过点(.)操作得到。通过浏览器获取的搜索内容都是链接,点击跳转,那么只需要获取每个元素下的a标签即可:
for el in search_res_list:
print(el.a)
从结果中可以看出,已经得到了搜索结果的a标签,那么接下来我们要做的就是提取每个a标签中的href超链接。使用list获取元素直接获取href超链接:
for el in search_res_list:
print(el.a['href'])
成功运行脚本会导致:
细心的读者可能会发现,得到的结果都是百度网址。其实这些URL可以说是“索引”,通过这些索引再次跳转到真正的URL。由于这些“索引”不一定会变,也不利于长期保存,所以这里还是需要获取真实的链接。
我们调用js脚本来访问这些url,这些url会跳转到真实的url,跳转后获取当前的url信息。调用execute_script方法执行js代码,代码如下:
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#获取所有句柄
获取句柄后,需要将当前操作的对象切换到新的页面。由于打开一个页面后只有2个页面,所以干脆使用遍历进行替换:
handle_exchange=None#要切换的句柄
for handle in handle_all:#不匹配为新句柄
if handle != handle_this:#不等于当前句柄就交换
handle_exchange = handle
driver.switch_to.window(handle_exchange)#切换
切换后,操作对象为当前刚打开的页面。通过current_url属性获取新页面的url:
real_url=driver.current_url
print(real_url)
然后关闭当前页面,将操作对象设置为初始页面:
driver.close()
driver.switch_to.window(handle_this)#换回最初始界面
运行脚本成功获取真实url:
最后用一个list来存储得到真实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 获取源文本
在当前文件所在目录下新建一个文件夹,命名为textsrc,在该目录下新建一个txt文件,在text中存放要比较的文本。我这里存放的内容是《PHP基础教程面向对象第十一步》一文的内容。
在代码中写一个函数获取文本内容:
def read_txt(path=''):
f = open(path,'r')
return f.read()
src=read_txt(r'F:\tool\textsrc\src.txt')
为了测试方便,这里使用绝对路径。
得到文本内容后,写一个余弦相似度的比较方法。
1.5 余弦相似度
相似度计算参考《Python实现余弦相似度文本比较》一文,我修改了一部分实现。
本文相似度比较采用余弦相似度算法,大致步骤分为分词->向量计算->计算相似度。
创建一个名为 Analyze 的新 Python 文件。新建一个类叫Analyze,在类中添加一个分词方法,在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方法接收一个文本变量,为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
合并的方法很简单,就不解释了。接下来添加向量计算方法:
# 得出文档向量
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):#两个向量组合成 [(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)
相似度方法采用两个向量,计算相似度并将其返回。为了减少代码冗余,这里简单的增加一个方法来完成计算过程:
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类的完整代码如下:
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):#两个向量组合成 [(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,新建一个对象:
from Analyse import Analyse
Analyse=Analyse()
将新打开页面的网页内容添加到遍历的搜索结果中:
time.sleep(5)
html_2=driver.page_source
使用 time.sleep(5) 等待浏览器有时间渲染当前网页内容。获取新打开页面的内容后,比较相似度:
Analyse.get_Tfidf(src,html_2)
既然返回了一个值,那么用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)
运行脚本:
结果显示有几个高度相似的链接,因此这些是涉嫌抄袭的文章。
上面是完成基本查重的代码,但是和代码相比,显得冗余和凌乱。接下来,让我们优化代码。
2.代码优化
通过上面的程序编程,大致可以分为:获取搜索内容->获取结果->计算相似度。我们可以新建三个类,分别是:Browser、Analyze(新创建的)、SearchEngine。
浏览器用于搜索、数据获取等;Analyze用于相似度分析、向量计算等;SearchEngine用于不同搜索引擎的基础配置,因为大部分搜索引擎的搜索方式都比较一致。
2.1浏览器类
初始化
新建一个名为 Browser 的 python 文件,并添加一个初始化方法:
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() 是创建一个新的浏览器对象;conf是传入的搜索配置,然后通过编写配置字典来实现搜索内容;self.engine_conf=EngineConfManage().get_Engine_conf(conf['engine'] ).get_conf()是获取搜索引擎的配置。不同搜索引擎的输入框和搜索按钮不一致,通过不同的配置信息实现多搜索引擎搜索。
添加搜索方法
#搜索内容写入到搜素引擎中
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']通过初始化方法获取对应的搜索引擎配置信息,直接获取信息获取元素。
点击搜索
#搜索框点击
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")))
#内容通过 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
上面的方法和之前写的遍历搜索结果类似,添加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")) 是否找到一个id为page的网页元素,id为page的网页元素为分页按钮的标签id。如果没有获取到,说明当前网页没有加载完成,等待时间timeout=3030秒,如果已经过去,则跳过等待。
上面的代码并没有比较相似度,而是通过res_link[real_url]=self.browser.page_source将内容和url存入字典,然后返回,再进行相似度比较,有利于以后的功能扩展。
打开目标搜索引擎进行搜索
#打开目标搜索引擎进行搜索
def search(self):
self.browser.get(self.engine_conf['website']) #打开搜索引擎站点
self.send_keyword() #输入搜索kw
self.click_search_btn() #点击搜索
return self.get_search_res_url() #获取web页搜索数据
最后添加一个search方法,直接调用search方法即可实现前面的所有操作,无需过多暴露,简化使用。
完整代码如下:
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()
#搜索内容写入到搜素引擎中
def send_keyword(self):
input = self.browser.find_element_by_id(self.engine_conf['searchTextID'])
input.send_keys(self.conf['kw'])
#搜索框点击
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")))
#内容通过 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
#打开目标搜索引擎进行搜索
def search(self):
self.browser.get(self.engine_conf['website']) #打开搜索引擎站点
self.send_keyword() #输入搜索kw
self.click_search_btn() #点击搜索
return self.get_search_res_url() #获取web页搜索数据
2.2SearchEngine类
SearchEngine类主要用于不同搜索引擎的配置编写。更容易实现搜索引擎或类似业务的扩展。
#搜索引擎配置
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
这里只实现了百度搜索引擎的配置。各种搜索引擎都继承了EngineConf基类,所以子类都有get_conf方法。EngineConfManage类用于调用不同的搜索引擎,传入引擎名称即可。
2.3 如何使用
先介绍两个类:
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',
}
新建一个Browser类,传入配置信息:
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]))
你觉得更舒服吗?简直不要太清爽。你认为这是结束了吗?还没完,接下来我们来扩展一下功能。
3、功能扩展
暂时这个小工具的功能只是检查重量的基本功能,这里面还有很多问题。如果没有白名单过滤,只能查一篇文章的相似度,偷懒的话,没有直接获取文章列表自动查重并导出结果的功能。接下来会逐步完善一些功能。限于篇幅,实现的功能这里就不一一列举了,以后会不断更新。
3.1 自动获取文本
创建一个名为 FileHandle 的新 Python 文件。该类用于自动获取指定目录下的txt文件,txt文件的名称为关键字,内容为该名称的文章内容。类代码如下:
import os
class FileHandle:
#获取文件内容
def get_content(self,path):
f = open(path,"r") #设置文件对象
content = f.read() #将txt文件的所有内容读入到字符串str中
f.close() #将文件关闭
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>
有两个方法get_content 和get_text。get_text是获取目录下所有的txt文件路径,通过get_content获取详细的文本内容,返回local_text;local_text key是文件名,value是文本内容。
3.2BrowserManage类
在Browser类文件中添加一个继承自Browser的BrowserManage类,并添加方法:
#打开目标搜索引擎进行搜索
def search(self):
self.browser.get(self.engine_conf['website']) #打开搜索引擎站点
self.send_keyword() #输入搜索kw
self.click_search_btn() #点击搜索
return self.get_search_res_url() #获取web页搜索数据
添加这个类将 Browser 类的逻辑与其他方法分开,以便于扩展。
3.3 Browser类的扩展
在Browser类中添加next page方法,这样在搜索内容的时候可以获取更多的内容,可以指定获取结果的个数:
#下一页
def click_next_page(self,md5):
WebDriverWait(self.browser,timeout=30,poll_frequency=1).until(EC.presence_of_element_located((By.ID, "page")))
#百度搜索引擎翻页后下一页按钮 xpath 不一致 默认非第一页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 进行 webpag text 对比,判断是否已翻页 (暂时使用,存在bug)
i=0
while md5==hashlib.md5(self.browser.page_source.encode(encoding='UTF-8')).hexdigest():#md5 对比
time.sleep(0.3)#防止一些错误,暂时使用强制停止保持一些稳定
i+=1
if i>100:
return False
return True
百度搜索引擎翻页后,下一页按钮的xpath不一致。默认不是第一页的xpath。如果出现异常,则使用另一个 xpath。然后在页面上进行md5,比较md5值。如果当前页面没有刷新,md5值不会改变。稍等片刻,然后单击下一页。
3.4 修改get_search_res_url方法
修改了get_search_res_url方法的部分内容,添加指定数量的结果,获取下一页内容,更改白名单设置后的代码如下:
<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")))
#内容通过 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)