无聊日常--python+selenium+chromedriver 实现QQ空间评论自动删除

版权声明:转载请标注出处与作者,写文不易,相互尊重从小事做起。 https://blog.csdn.net/JasonRaySHD/article/details/88355287

我最初有写这个项目的想法是在18年11月底(好像是),当时我们学校的表白墙遭到了麦片的账号骚扰——不断在评论区刷麦片评论,利用表白墙的流量“拉客”。
“路见不平一声吼啊~”(破音)
但是当时学习任务紧没有太多时间,因此搁置了很久。最初是想用splash实现,但是程序有BUG,一直没有按预期运行,拖着拖着就到了现在。当然,写这篇博客也是写出来一周后了。
废话少说,我来讲讲我这个项目完成思路吧,涉及到垃圾语句的地方轻喷。(虽然在csdn评论的人还是比较少的)

对了,结论放这里。程序稳定性不好,主要因为加载说说的程序会因为网速等原因在一定时间内获取一定数量说说,而进行后一步删除操作时,若又有新的说说加载出来,则会造成操作失败。
之后通过进一步学习以后我再来优化一下吧~

1、环境:python3.7+selenium+chromdriver+chrome 72
chromdriver具体版本我忘了,但找到篇博客,里面有版本对应:
https://blog.csdn.net/yoyocat915/article/details/80580066
chromedriver下载地址:http://npm.taobao.org/mirrors/chromedriver/

2、程序思路:
登录QQ空间 —— 抓取评论 —— 判断是否存在匹配评论 —— 若存在,找到一条删除后重新进入判断循环(删除一条评论以后,网站元素的一系列信息就变化了,此时继续删除其他匹配评论就失去了意义会报错。) —— 一定时间结束循环等待下次执行

类定义以及声明的一些全局变量:

from selenium import webdriver
from selenium.common.exceptions import *
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.action_chains import  *
import time
import re
from selenium.webdriver.support.wait import WebDriverWait
# 全局变量初始化
url = "https://xui.ptlogin2.qq.com/cgi-bin/xlogin?proxy_url=https%3A//qzs.qq.com/qzone/v6/portal/proxy.html&daid=5&&hide_title_bar=1&low_login=0&qlogin_auto_login=1&no_verifyimg=1&link_target=blank&appid=549000912&style=22&target=self&s_url=https%3A%2F%2Fqzs.qq.com%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&pt_qr_app=手机QQ空间&pt_qr_link=https%3A//z.qzone.com/download.html&self_regurl=https%3A//qzs.qq.com/qzone/v6/reg/index.html&pt_qr_help_link=https%3A//z.qzone.com/download.html&pt_no_auth=0"
switchbtn_id = 'switcher_plogin'
username_id = 'u'
password_id = 'p'
loginbtn_id = 'login_button'
comment_class = 'comments-content'
deletebtn_class = 'act-delete'
ackbtn_class = re.compile("qz_dialog_layer_btn qz_dialog_layer_sub")
ackbtn_xpath = r"//a[@class='qz_dialog_layer_btn qz_dialog_layer_sub']"
# selenium初始化
caps = webdriver.DesiredCapabilities().CHROME
options = Options()
# options.add_argument("-headless")  # 此处设置是否为headless模式
prefs={
    'profile.default_content_setting_values': {
        'images': 2,
    }
}
# options.add_experimental_option('prefs',prefs) # 限制图片、js加载,
driver = webdriver.Chrome(chrome_options=options,executable_path="C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe")

# 用于完成对一条评论删除后,一次跳出多个循环
class BreakLoopException(Exception):
    pass
    
class QQ:
    def __init__(self,username,password,match,**kwargs):
        self.username = username # 账号
        self.password = password  # 密码
        self.match = match  # 需要匹配的评论
        self.interval = 5*60  # 程序执行一次的时间
        self.sleeptime = 10*60  # 程序执行一次后再执行的间隔
        self.retry = 3  # 程序错误后重试次数
        self.number = 100  # 要求加载的说说最少数目

3、步骤详解:
①登录:
在这里插入图片描述

这里普通的QQ空间进去后,登录框是在一个iframe里面,因此可以利用selenium的switch_to_frame()函数或者直接在iframe中的网站登录,如下图。
在这里插入图片描述这里用的是后面这种方法。剩下其他没什么难度,我直接上代码:

    def login(self):
        driver.get(url)
        driver.find_element_by_id(switchbtn_id).click()
        user = driver.find_element_by_id(username_id)
        user.click()
        user.clear()
        user.send_keys(self.username)
        pwd = driver.find_element_by_id(password_id)
        pwd.click()
        pwd.clear()
        pwd.send_keys(self.password)
        driver.find_element_by_id(loginbtn_id).click()
        while True:
            if re.search('<title>(.*?)的QQ空间',driver.page_source):
                print("登录成功")
                break
        self.page = driver.page_source

这里检测登录成功的方法很低级,以后再来优化吧…

②检测是否存在匹配评论:
网站源码如图所示,每一个 li 标签都表示一条说说。
在这里插入图片描述
进一步查看源码:在这里插入图片描述

可以看见在div class="f-single-foot"中包含了整个评论模块(div class=“f-single-head f -side” 为姓名,头像信息所在,div class="f-single-content f-wrap"包含说说内容),div class="comments-list"则包含所有评论,由 ul li 存储。

在这里插入图片描述

点开其中的一个 li 标签,可以看到评论在 div class=“comments-content” 中,之后我们将从text属性中提取评论内容以判断是否匹配。div class=“comments-op” 为评论操作按钮:评论+删除。
在这里插入图片描述

可见其属性为: act-delete none 。删除 回复按钮需要在有鼠标悬停时才会可见。到此我们可以完成项目了,下面放的程序会比较长,我先简单解释一下逻辑。
cleanloop() —— 控制程序间隔self.sleeptime秒,不断的执行 self.interval 秒cleanmanage()。
cleanmanage() —— 控制检查程序check()的运行,利用while控制重试次数。
check() —— 抓取评论并判断是否匹配self.match,若匹配则进入delete函数,完成操作后利用BreakLoopException跳出本次
循环后重新获取评论。
delete() —— 单纯执行删除操作

    def cleanloop(self):
        print("程序运行开始")
        flag = ''
        self.login() # 登录
        while True:
            self.cleanmanage()
            time.sleep(self.sleeptime)	# 停止运行self.sleeptime s
            flag = input("是否停止执行,Y/N").upper()
            if flag == Y:
            	break
        driver.close()
        
    def cleanmanage(self):
        count = 0
        while count < self.retry:
            try:
                self.check()
                print("程序运行 %s s结束,下一次运行时间为 %s s后" %(self.interval,self.sleeptime))
                self.time = time.time()
                break
            except:
                print('程序运行出错,5s后尝试重新运行程序 -%s' %count)
                time.sleep(5)
                count += 1
            if count == self.retry:
                print("程序运行失败,请联系开发者")

    def check(self):
        self.time = time.time()
        js = "window.scrollBy(0,document.body.scrollHeight)"
        while time.time()-self.time <= self.interval:
            count = 0
            time.sleep(2)  # 刷新以后停止2s后再进行操作
            driver.execute_script(js)
            self.comments = driver.find_elements_by_class_name(comment_class)
            # 完成页面多次下滑,从而加载说说
            while len(self.comments) < self.number:
                driver.execute_script(js)
                time.sleep(3)
                self.comments = driver.find_elements_by_class_name(comment_class)
                count+=1
                if count==3:
                    break
            print("评论内容加载完成")
            print('获取评论总数为: %s' % len(self.comments))
            try:
            	# 开始查找
                for item in self.match:
                    for comment in self.comments:
                        if re.search(item, comment.text):
                            print("发现匹配评论 %s " % str(comment.text))
                            self.delete(comment)
            except StaleElementReferenceException as e:
                print("获取元素错误,5秒后重新查找")
                print("=== " * 5)
                time.sleep(5)
                driver.refresh()
                continue
            except BreakLoopException as e:
                print("本轮查找完成,5秒后即将进行下次查找")
                print("=== " * 5)
                time.sleep(5)
                driver.refresh()
                continue
            print("本轮查找完成,5秒后即将进行下次查找")
            print("=== " * 5)
            time.sleep(5)
            driver.refresh()
            
                
    def delete(self,comment):
        while True:
            try:
                ActionChains(driver).move_to_element(comment).perform()
                comment.find_element_by_class_name(deletebtn_class).click()
                break
            except:
                try:
                    driver.execute_script('window.scrollBy(0,-100)')
                    ActionChains(driver).move_to_element(comment).perform()
                    comment.find_element_by_class_name(deletebtn_class).click()
                    break
                except:
                    try:
                        driver.execute_script('window.scrollBy(0,100)')
                        ActionChains(driver).move_to_element(comment).perform()
                        comment.find_element_by_class_name(deletebtn_class).click()
                    except:
                        print("无法获取删除按钮,退出删除操作")
                        raise(BreakLoopException)
        WebDriverWait(driver,10).until(lambda x: x.find_element_by_xpath(ackbtn_xpath)).click()
        print("评论已删除")
        raise(BreakLoopException)

到此 程序就完成了 只需要输入命令即可运行:

q = QQ('账号', '密码', ['需要匹配的评论'])
q.cleanloop()




个人项目分享,自知代码写的很烂。感谢阅读!

猜你喜欢

转载自blog.csdn.net/JasonRaySHD/article/details/88355287