文章目录
整体代码多看看,其实不多也不难,只是我的代码注释很多(我的习惯)。
抱歉哈,文章内容可能有点多了,其实我写博客的时间比写代码花的时间都多!
容我啰嗦一句,先用小号实验,泪的教训!(自己太自信了)
开始前请安装selenium库并且引入webdriver模块 from selenium import webdriver
一. 编程思想及流程
1. 浏览器进入QQ空间。
# 防止打印一些无用的日志
option = webdriver.ChromeOptions()
option.add_experimental_option("excludeSwitches", ['enable-automation', 'enable-logging'])
# 使用谷歌浏览器 或者还可以使用 Edge、Firefox
driver = webdriver.Chrome(chrome_options=option)
# 这里不使用 driver=webdriver.Chrome(),因为会打印很多无用的日志
#窗口最大化
driver.maximize_window()
#打开QQ空间网站
driver.get("https://i.qq.com")
2. 切换框架。
此处窗口是iframe框架,我们想要定位里面的元素,就要先从主框架切换到这里的iframe框架
driver.switch_to.frame("login_frame") #进入frame框架 有id,name属性直接切换
3. 登录QQ空间。
先检测电脑是否已经登录了QQ。如果登录了,则直接登录QQ空间;否则进行账号密码登录
若选择账号密码登录,别忘了在代码中填写你的账号密码
仔细观察,会发现如果电脑上了登陆了QQ,这里会多一个
<a>
标签,所以可以借此判断是否登陆了QQ。如果登陆了,那么直接定位到 a 标签并实现点击,就可以完成自动登录;如果没有,那么就依次定位 “账号密码登录”点击 -->“账号框”输入账号 --> “密码框”输入密码 -->“登录”选项点击
try:
#判断 a标签是否存在
element=driver.find_element_by_xpath("//div[@class='qlogin_list']/a")
#或者直接 driver.find_element_by_xpath("//div[@class='qlogin_list']/a")
'''
如果存在 a标签,继续执行后面代码,自动登录
否则产生NoSuchElementException异常,并直接进行异常处理,进行账号密码登录
NoSuchElementException: 元素定位不到,即不存在该元素,从而产生的异常
'''
#方式一 自动登录(电脑上已经登录了QQ才可以自动登录)
driver.find_element_by_xpath("//div[@class='qlogin_list']/a").click()
# 或者 driver.find_element_by_class_name("login").click()
except NoSuchElementException:
# 方法二 :输入账号密码登录
# 选择账号密码登录
driver.find_element_by_id("switcher_plogin").click()
# 账号框输入自己的qq账号
driver.find_element_by_id("u").send_keys("你的账号")
# 密码框输入密码
driver.find_element_by_id("p").send_keys("你的密码")
# 点击登陆按钮
driver.find_element_by_id("login_button").click()
finally:
print("登陆成功")
time.sleep(2) #延时确保已经登录进去了
4. 点击进入说说页面。
ps: 这里提醒一下,先用小号试试,不然大家懂的,从这之后我都是采用小号做演示
这里 <a>
标签没有 id、class属性,不能依据它们进行定位,但是可以用 link_text 进行文本定位,或者使用 xpath 按路径层层定位,先定位到其外层的<div>
或者<ul>
标签,再定位<li>
最后<a>
。不能直接定位<li>
,原因我认为是li与ul是一体的,ul层级比li高,必须先定位到ul
#点击说说标签,进行发表说说
driver.find_element_by_xpath("//div[@class='head-nav']/ul/li[5]/a").click()
#这个可以 driver.find_element_by_link_text("说说").click()
#这个是不行的 driver.find_element_by_xpath("//li[@class='menu_item_311']/a")
5. 写说说
- 先切换框架。可以看到写说说的区域又是位于iframe框架里。
'''
这里的iframe没有 id和name属性,但有class属性
所以这里利用class定位iframe,定位完成再进行切换框架
'''
frame1 = driver.find_element_by_css_selector("iframe.app_canvas_frame")
#切换框架
driver.switch_to.frame(frame1)
time.sleep(2) #切换框架需要一定时间
- 定位并点击文本框。我们可以想想,写说说时我们首先要点一下内容区域,当出现光标时才填写内容。这里道理一样
'''
填写说说内容前需要先将鼠标定位到说说文本框中。
'''
#定位文本框
driver.find_element_by_xpath("//div[@class='textinput textarea c_tx3']").click()
#也可以 driver.find_element_by_id("$1_substitutor_content").click()
time.sleep(2)
#填写说说内容
driver.find_element_by_id('$1_content_content').send_keys("大家好!这是一条通过selenium自动定时发送的说说")
6. 定时发布(略有麻烦)
定时这里,不难的,只是麻烦点。整篇文章有点多了,我没办法再多说了,就简洁点了。
#选择定时发布
driver.find_element_by_xpath("//*[@class='sync-timing evt_click']").click()
driver.find_element_by_link_text("设置发布时间").click()
这里要注意,弹出的窗口在主框架,不在前面的iframe框架中,所以要先回到主框架
当我们选择下拉框时,发现又进入了新的iframe框架
#定时发布需要先回到主框架
driver.switch_to.default_content()
time.sleep(1)
#再进入一个iframe弹窗框架,选择定时发布的时间
driver.switch_to.frame("popup_dialog_frame") #有 id 属性,直接切换
time.sleep(1)
#选择发表的天数
driver.find_element_by_xpath("//div[@class='mod_cont']/p[@id='dateSel']/select[@id='date']").click()
#当天 option[1] 第一个option,即为当天
driver.find_element_by_xpath("//div[@class='mod_cont']/p[@id='dateSel']/select[@id='date']/option[1]").click()
#选择发表的小时
driver.find_element_by_xpath("//div[@class='mod_cont']/p[@id='dateSel']/select[@id='hours']").click()
#23时 0~23 option[24],即23时
driver.find_element_by_xpath("//div[@class='mod_cont']/p[@id='dateSel']/select[@id='hours']/option[24]").click()
#选择发表的分钟
driver.find_element_by_xpath("//div[@class='mod_cont']/p[@id='dateSel']/select[@id='minutes']").click()
#20分 0-59 option[21],即20分
driver.find_element_by_xpath("//div[@class='mod_cont']/p[@id='dateSel']/select[@id='minutes']/option[21]").click()
这时候,我们要想到一件事情,如果我们定时时间已经过期了怎么办?我的处理是过期了就取消定时直接发布
我们可以根据图片中指示位置有没有文本内容来判断定时有没有过期
judge_time=0 #判断是否进行了定时, 0为要定时,非0则不定时
'''
如果定时没过期,则选择确定;否则,选择取消定时。
如果定时过期,指定位置会有文本提示,
所以我们只需判断该位置的文本是否为空,即可判断有没过期。
'''
if driver.find_element_by_xpath("//div[@class='tips tips_nobbor tips_highlight tips_icon icon_hint']").text == '':
#没过期,点击确认
driver.find_element_by_xpath("//a[@class='mod_btn mod_btn_sub']").click()
else:
#过期了,点击取消
driver.find_element_by_xpath("//a[@class='mod_btn mod_btn_nor']").click()
#不进行定时
judge_time=1
7. 发表说说(有重点)
别忘了!我们进入定时的弹窗之前,也是处于一个iframe框架中
所以,我们现在要回到之前的iframe框架,就要先回到主框架,再进入iframe
#回到主框架
driver.switch_to.default_content()
time.sleep(0.5)
#这里的iframe没有 id和name属性,所以先要定位iframe,定位完成再进行切换
frame = driver.find_element_by_css_selector("iframe.app_canvas_frame")
driver.switch_to.frame(frame)
time.sleep(1)
这里是重点!
#空白处点击,否则会定位不到后面 发表(保存)选项
driver.find_element_by_xpath("//div[@class='bor mod-tab author_display']").click()
time.sleep(0.5)
这里提醒一下,如果我们定时没过期,这里的文本内容会从“发表”变成“保存”,其它不变。所以就不要采用 link_text 定位了
'''
#点击发表(保存)选项,发表说说。
这里因为不定时的时侯的文本内容为下载,定时后的文本内容变为保存,
所以这里不采用link_text进行定位。
'''
driver.find_element_by_xpath("//a[@class='btn-post gb_bt evt_click']/span[@class='txt']").click()
定时成功发布的话,会有弹窗提示
'''
judge_time为 0表示要定时,弹出窗口进行最后确认,
若不为0,不会弹出窗口,直接发布,无需考虑其它问题
其实确不确认无所谓,因为已经开始定时了。
'''
if judge_time == 0:
#回到主框架
driver.switch_to.default_content()
#这里要延时长一点,大于3s
time.sleep(4)
#这里的弹窗为div样式,所以无需进入iframe框架等等操作。
#所以这里直接采用最简单的定位方式 link_text。。
driver.find_element_by_link_text("确认").click()
print("发表成功")
二. 完整代码
import time
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
# 防止打印一些无用的日志
option = webdriver.ChromeOptions()
option.add_experimental_option("excludeSwitches", ['enable-automation', 'enable-logging'])
# 使用谷歌浏览器 或者 Edge、Firefox
driver = webdriver.Chrome(chrome_options=option)
# 这里不使用 driver=webdriver.Chrome(),因为会打印很多无用的日志
#窗口最大化
driver.maximize_window()
#打开QQ空间网站
driver.get("https://i.qq.com")
#这里使用try,如果过程出现问题,直接执行finally,等待3s后关闭窗口
try:
driver.switch_to.frame("login_frame") #进入frame框架
try:
#判断 a标签是否存在
element=driver.find_element_by_xpath("//div[@class='qlogin_list']/a")
#或者直接 driver.find_element_by_xpath("//div[@class='qlogin_list']/a")
'''
如果存在 a标签,继续执行后面代码,自动登录
否则产生NoSuchElementException异常,并直接进行异常处理,进行账号密码登录
NoSuchElementException: 元素定位不到,即不存在该元素从而产生的异常
'''
#方式一 自动登录(电脑上已经登录了QQ才可以自动登录)
driver.find_element_by_xpath("//div[@class='qlogin_list']/a").click()
# 或者 driver.find_element_by_class_name("login").click()
except NoSuchElementException:
# 方法二 :输入账号密码登录
# 因为表在iframe里面,所以需要进入iframe里面
#driver.switch_to.frame("login_frame") # 找到frame入口
# 选择账号密码登录
driver.find_element_by_id("switcher_plogin").click()
# 账号框输入自己的qq账号
driver.find_element_by_id("u").send_keys("你的账号")
# 密码框输入密码
driver.find_element_by_id("p").send_keys("你的密码")
# 点击登陆按钮
driver.find_element_by_id("login_button").click()
finally:
print("登陆成功")
time.sleep(2)
#登录后为新页面,已经是主框架,无需考虑切换回主框架
#点击说说标签,进行发表说说
driver.find_element_by_xpath("//div[@class='head-nav']/ul/li[5]/a").click()
#driver.find_element_by_link_text("说说").click()
#driver.find_element_by_xpath("//li[@class='menu_item_311']/a") 这个是不行的
time.sleep(1)
'''
这里的iframe没有 id和name属性,但有class属性
所以这里利用class定位iframe,定位完成再进行切换框架
'''
frame1 = driver.find_element_by_css_selector("iframe.app_canvas_frame")
#切换框架
driver.switch_to.frame(frame1)
time.sleep(2)
'''
填写说说内容前需要先将鼠标定位到说说文本框中。
'''
#定位文本框
#也可以 driver.find_element_by_id("$1_substitutor_content").click()
driver.find_element_by_xpath("//div[@class='textinput textarea c_tx3']").click()
time.sleep(2)
#填写说说内容
driver.find_element_by_id('$1_content_content').send_keys("大家好!这是一条通过selenium自动定时发送的说说")
#选择定时发布
driver.find_element_by_xpath("//*[@class='sync-timing evt_click']").click()
driver.find_element_by_link_text("设置发布时间").click()
#定时发布需要先回到主框架
driver.switch_to.default_content()
time.sleep(1)
#再进入一个iframe弹窗框架,选择定时发布的时间
driver.switch_to.frame("popup_dialog_frame")
time.sleep(1)
#选择发表的天数
driver.find_element_by_xpath("//div[@class='mod_cont']/p[@id='dateSel']/select[@id='date']").click()
driver.find_element_by_xpath("//div[@class='mod_cont']/p[@id='dateSel']/select[@id='date']/option[1]").click() #当天
#选择发表的小时
driver.find_element_by_xpath("//div[@class='mod_cont']/p[@id='dateSel']/select[@id='hours']").click()
driver.find_element_by_xpath("//div[@class='mod_cont']/p[@id='dateSel']/select[@id='hours']/option[24]").click() #23时
#选择发表的分钟
driver.find_element_by_xpath("//div[@class='mod_cont']/p[@id='dateSel']/select[@id='minutes']").click()
driver.find_element_by_xpath("//div[@class='mod_cont']/p[@id='dateSel']/select[@id='minutes']/option[21]").click() #20分
judge_time=0 #判断是否进行了定时, 0为要定时,非0则不定时
'''
如果定时没过期,则选择确定;否则,选择取消定时。
如果定时过期,指定位置会有文本提示,
所以我们只需判断该位置的文本是否为空,即可判断有没过期。
'''
if driver.find_element_by_xpath("//div[@class='tips tips_nobbor tips_highlight tips_icon icon_hint']").text == '':
#没过期,点击确认
driver.find_element_by_xpath("//a[@class='mod_btn mod_btn_sub']").click()
else:
#过期了,点击取消
driver.find_element_by_xpath("//a[@class='mod_btn mod_btn_nor']").click()
#不进行定时
judge_time=1
#回到主框架
driver.switch_to.default_content()
time.sleep(0.5)
#这里的iframe没有 id和name属性,所以先要定位iframe,定位完成再进行切换
frame = driver.find_element_by_css_selector("iframe.app_canvas_frame")
driver.switch_to.frame(frame)
time.sleep(1)
#空白处点击,否则会定位不到后面 发表(保存)选项
driver.find_element_by_xpath("//div[@class='bor mod-tab author_display']").click()
time.sleep(0.5)
'''
#点击发表(保存)选项,发表说说。
这里因为不定时的时侯的文本内容为下载,定时后的文本内容变为保存,
所以这里不采用link_text进行定位。
'''
driver.find_element_by_xpath("//a[@class='btn-post gb_bt evt_click']/span[@class='txt']").click()
'''
judge_time为 0表示要定时,弹出窗口进行最后确认,
若不为0,不会弹出窗口,直接发布,无需考虑其它问题
其实确不确认无所谓,因为已经开始定时了。
'''
if judge_time == 0:
#回到主框架
driver.switch_to.default_content()
#这里要延时长一点,大于3s
time.sleep(4)
#这里的弹窗为div样式,所以无需进入iframe框架等等操作。
#所以这里直接采用最简单的定位方式 link_text。。
driver.find_element_by_link_text("确认").click()
print("发表成功")
finally: #如果出现问题,3s后关闭窗口,退出QQ空间
#3s后,关闭QQ空间
time.sleep(3)
driver.quit()
三. 总结及建议
代码其实存在挺多缺陷的,大家可以完善一下
例如:sleep(),其实不该用这个的,sleep是准确计时的,也就是说
如果有的人网更快,那他就可以sleep的时间可以短一点;如果网慢,那么时间就要长一点了。
大家可以去看看显示等待和隐式等待,来尝试更改sleep。
selenium 我看好像挺简单的就学了一点,就纯粹搞着玩,所以关于selenium的代码不用深究我为什么这样做。
- 如果使用的sleep,一定要考虑自己的网络因素(即延时不够),是不是因为网络导致失败的。
- 定位我建议大家多考虑用用 xpath,当你用id,class等定位失败时,不妨试试xpath,也许你会收到惊喜。
如果文章内容有问题,大家可以留言,有问题也可以留言,我尽量解答。