概要
selenium是一种简单的自动化测试的实现方式,不需要什么基础就能掌握。本人自学selenium,个人认为较为方便。这个项目用于自动给B站动态点赞。
一、获取cookies
既然要点赞那么登录是必不可少的一步,但每次都输入账号密码又太麻烦,所以可以采用登录第一次获取cookies,之后用cookies模拟登录。selenium自带有获取cookies的方法,那么可以先创建一个“读取cookie.py”的py文件,代码如下:
from selenium import webdriver
from time import sleep
import json
def grubcookies():
webd = webdriver.Chrome()
webd.get('https://www.bilibili.com')
webd.delete_all_cookies()
sleep(50)#在这50秒内需要手动登录B站,最好扫码登录,时间不够可以自己设置
dictcookies = webd.get_cookies()
jsoncookies = json.dumps(dictcookies)
with open('cookies.txt','w') as f:
f.write(jsoncookies)
webd.quit()
if __name__=='__main__':
grubcookies()
运行这段代码后,在该目录下生成了一个“cookies.txt”的文件,存放着cookies,之后就不再需要获取cookies了
二、打开B站动态首页
from selenium import webdriver
webd = webdriver.Chrome()
url = 'https://t.bilibili.com/?spm_id_from=333.1007.0.0'
#url是B站动态
webd.get(url)
然而没有登录,这需要导入我们的cookies.txt文件中的cookies。
from selenium import webdriver
import json
def process():
with open('./cookies.txt', 'r') as f:
cookies = f.read()
cookies = json.loads(cookies)
for cookie in cookies:
if 'expiry' in cookie:
del cookie['expiry']
#需要删除cookie中的"expiry",否则不能模拟登录动态首页只能模拟登录B站首页
return cookies
def main():
webd = webdriver.Chrome()
url = 'https://t.bilibili.com/?spm_id_from=333.1007.0.0'
webd.get(url)
for cookie in process():
webd.add_cookie(cookie)
webd.refresh()#刷新登录
那么到这里就打开了B站的动态首页
三、选择用于点赞的网页元素
可以用xpath选择器或者css选择器,差不多的。
然而有一个问题:如何得知已经点赞了? 鼠标右击点赞按钮,选择检查,然后鼠标左击点赞按钮进行一次点赞操作,会发现该div节点的class属性发生变化,从div[class="bili-dyn-action like"]变为了div[class="bili-dyn-action like active"]。显而易见,可以利用这一点选择元素。
css = 'div[class="bili-dyn-item"] > div[class="bili-dyn-item__main"] > div[class="bili-dyn-item__footer"] > div[class="bili-dyn-item__action"] > div[class="bili-dyn-action like"]'
#这里采用css选择器
elements = webd.find_elements(By.CSS_SELECTOR, css)
#选择出了一列表的“点赞”元素
for i in range(len(elements)):
#挨个对列表中的元素进行点击操作
element = elements[i]
#element是一个div类型元素,不能直接element.click(),要用JavaScript模拟点击
webd.execute_script("arguments[0].click();", element)
四、循环进行网页刷新
B站动态是实时变化的,需要不断刷新获取最新动态。
这里有两个方案:
1.当有新的动态时,会弹出一个按钮提醒你查看新动态,可以用css选择到这个元素模拟点击它。优点是不用整个网页刷新,较快。缺点是B站有时不能很及时地弹出这个按钮。
2.整页刷新,可以及时获取动态,但由于整页刷新加载慢。
那么选择哪一种呢? 答案是:都要!
可以两种结合,每次都检查是否有按钮弹出,但隔5次刷新一整页。
css_detect = 'div[class="bili-dyn-list-notification fs-small"]'
flag=0
#css选择B站自动弹出的刷新按钮
while True:
if flag == 5:
webd.refresh()
flag = 0
sleep(0.7)
elements = webd.find_elements(By.CSS_SELECTOR, css)
#这里的css字符串前面有
for i in range(len(elements)):
element = elements[i]
webd.execute_script("arguments[0].click();", element)
try:
btn = webd.find_element(By.CSS_SELECTOR, css_detect)
webd.execute_script("arguments[0].click();", btn)
sleep(0.7)
#注意要开头要加from selenium.common.exceptions import NoSuchElementException
except NoSuchElementException:
#如果不存在这个按钮元素
pass
sleep(1.7)
flag += 1
五、退出程序设计
设置如何退出是很必要的一步。毕竟谁也不愿意看到每次强制关闭都报错吧。
主程序在死循环中,那么就需要使用多线程检测键盘是否按下“esc”这个键作为退出的信号
import threading
import keyboard
#keyboard模块需要自己pip install keyboard下载
def detect():
global stop
keyboard.wait('esc')
stop = True
pass
def main():
global cnt, stop
while True:
if stop:
break
#main()大部分省略,只显示如何退出循环
webd.quit()#退出
if __name__ == '__main__':
stop = False
main_thread = threading.Thread(target=main)
detect_thread = threading.Thread(target=detect)
#注意这里target=函数名,函数名后面不能跟括号
detect_thread.start()
main_thread.start()
detect_thread.join()
main_thread.join()
六、完善程序
可以输出点赞了谁的动态、点赞了几条动态。虽然不是很必要甚至多此一举。
def main():
global cnt, stop
#略
while True:
#略
elements = webd.find_elements(By.CSS_SELECTOR, css)
for i in range(len(elements)):
element = elements[i]
xpath = '//div[@class="bili-dyn-item__header"]/div[@class="bili-dyn-title"]/span'
#这个xpath代表所有动态的主人的昵称,可以通过这是第几条动态进行选择
name = element.find_elements(By.XPATH, xpath)[i].text
print('#'+name)
webd.execute_script("arguments[0].click();", element)
cnt += 1
print('已经点了' + str(cnt) + '个赞')
#略
webd.quit()
pass
if __name__ == '__main__':
cnt = 0
#略
print('已停止,本次一共点了{x}个赞'.format(x=cnt))
七、完整代码
1、读取cookie.py:
from selenium import webdriver
from time import sleep
import json
def grubcookies():
webd = webdriver.Chrome()
webd.get('https://www.bilibili.com')
webd.delete_all_cookies()
sleep(50)
dictcookies = webd.get_cookies()
jsoncookies = json.dumps(dictcookies)
with open('cookies.txt','w') as f:
f.write(jsoncookies)
webd.quit()
pass
if __name__=='__main__':
grubcookies()
pass
2、main.py:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
from time import sleep
import json
import threading
import keyboard
def process():
with open('./cookies.txt', 'r') as f:
cookies = f.read()
cookies = json.loads(cookies)
for cookie in cookies:
if 'expiry' in cookie:
del cookie['expiry']
return cookies
pass
def main():
global cnt, stop
webd = webdriver.Chrome()
url = 'https://t.bilibili.com/?spm_id_from=333.1007.0.0'
webd.get(url)
for cookie in process():
webd.add_cookie(cookie)
webd.refresh()
css_detect = 'div[class="bili-dyn-list-notification fs-small"]'
css = 'div[class="bili-dyn-item"] > div[class="bili-dyn-item__main"] > div[class="bili-dyn-item__footer"] > div[class="bili-dyn-item__action"] > div[class="bili-dyn-action like"]'
sleep(5)
flag = 0
while True:
if stop:
break
if flag == 5:
webd.refresh()
flag = 0
sleep(0.7)
elements = webd.find_elements(By.CSS_SELECTOR, css)
for i in range(len(elements)):
element = elements[i]
xpath = '//../../div[@class="bili-dyn-item__header"]/div[@class="bili-dyn-title"]/span'
name = element.find_elements(By.XPATH, xpath)[i].text
print('#'+name)
webd.execute_script("arguments[0].click();", element)
cnt += 1
print('已经点了' + str(cnt) + '个赞')
try:
btn = webd.find_element(By.CSS_SELECTOR, css_detect)
webd.execute_script("arguments[0].click();", btn)
sleep(0.7)
except NoSuchElementException:
pass
sleep(1.7)
flag += 1
webd.quit()
pass
def detect():
global stop
keyboard.wait('esc')
stop = True
pass
if __name__ == '__main__':
cnt = 0
stop = False
main_thread = threading.Thread(target=main)
detect_thread = threading.Thread(target=detect)
detect_thread.start()
main_thread.start()
detect_thread.join()
main_thread.join()
print('已停止,本次一共点了{x}个赞'.format(x=cnt))