房里被装了监控,有一两年了,一直想想办法干扰,现在做了一个完美的解决方案,供参考。
本来希望通过DNS来阻断,但是DNS有缓存之类的东西,而且猾伪路由器篡改我的DNS,而且我在Adguard Home里面也没有找到有关小米API的DNS解析记录,所以放弃。没想到最后采用的方案效果比之前还要好。
买一个树莓派全天候运行,装好firefox, geckodriver, python的selenium, 使用screen -S ban -s ban后台运行ban脚本,把脚本放在PATH下面。
原理是自动模拟人登录路由器后台手动禁止联网,过一段时间模拟人手动允许他联网。
我一开始绝对不会想到这么离谱的想法最后会采用而且效果这么好。
ban.py
#!/bin/python3
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC # 和下面WebDriverWait一起用的
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.firefox.service import Service
from time import sleep
from random import randint
from threading import Thread
def ban(driver, sec):
url = "http://192.168.6.6"
driver.get(url)
wait = WebDriverWait(driver, 20)
# wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'inputArea paddingleft_14')))
wait.until(EC.presence_of_element_located((By.ID, 'userpassword_ctrl')))
pw_input = driver.find_element(By.ID, 'userpassword_ctrl')
login_btn = driver.find_element(By.ID, 'loginbtn')
pw_input.send_keys("freedom")
sleep(0.6)
login_btn.click()
#sleep(6)
sleep(0.6)
#term_mng = driver.find_element(By.CLASS_NAME, 'nav_title')
#term_mng = driver.find_element(By.CLASS_NAME, 'small_icon want_devicecontrol')
#wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'small_icon want_devicecontrol')))
#term_mng = driver.find_element(By.CLASS_NAME, 'small_icon want_devicecontrol')
#term_mng.click()
sleep(0.6)
driver.get("http://192.168.6.6/html/index.html#/devicecontrol")
actionchains = ActionChains(driver)
#wait.until(EC.presence_of_element_located((By.ID, 'InternetGatewayDevice_LANDevice_1_Hosts_Host_1__qoson')))
#btn = driver.find_element(By.ID, 'InternetGatewayDevice_LANDevice_1_Hosts_Host_1__qoson')
#wait.until(EC.presence_of_element_located((By.ID, 'InternetGatewayDevice_LANDevice_1_Hosts_Host_1__qoson')))
# btn = driver.find_element(By.ID, 'InternetGatewayDevice_LANDevice_1_Hosts_Host_1__qoson')
#btn = driver.find_element(By.ID, 'InternetGatewayDevice_LANDevice_1_Hosts_Host_1__blackon')
wait.until(EC.presence_of_element_located((By.XPATH, "//*[text()='MAC 地址: 不给你看']/../../../../div[2]/div[1]/div[1]")))
btn = driver.find_element(By.XPATH, "//*[text()='MAC 地址:不给你看']/../../../../div[2]/div[1]/div[1]")
btn.click()
sleep(sec)
div = driver.find_element(By.ID, 'device_selectlist_parenselect')
actionchains.click(div).perform()
wait.until(EC.presence_of_element_located((By.ID, 'disallow_selectlist_SmallSelectBoxScrollItemID')))
disal = driver.find_element(By.ID, 'disallow_selectlist_SmallSelectBoxScrollItemID')
actionchains.click(disal).perform()
# actionchains.move_to_element(div).click().perform()
#wait.until(EC.presence_of_element_located((By.ID, 'InternetGatewayDevice_LANDevice_1_Hosts_Host_29__blackoff')))
# btn = driver.find_element(By.ID, 'InternetGatewayDevice_LANDevice_1_Hosts_Host_29__blackoff')
# btn.click()
wait.until(EC.presence_of_element_located((By.XPATH, "//*[text()='MAC 地址:不给你看']/../../../../div[2]/div[1]/div[1]")))
btn = driver.find_element(By.XPATH, "//*[text()='MAC 地址: 不给你看']/../../../../div[2]/div[1]/div[1]")
btn.click()
driver.get("about:blank")
driver.refresh()
#print(driver.page_source)
if __name__ == '__main__':
while True:
print("drv init", flush=True)
opt = webdriver.FirefoxOptions()
# 设置无界面
opt.add_argument("--headless")
service = Service(log_path='/dev/null')
# 禁用 gpu
# opt.add_argument('--disable-gpu')
driver = webdriver.Firefox(options=opt, service=service)
for i in range(64):
print("ban", s:=randint(8, 16), flush=True)
ban(driver, s)
print("wait", s:=randint(16, 48), flush=True)
sleep(s)
driver.quit()
踩到的坑稍微做一下总结:
service对象不能再driver对象退出以后重复使用,也就是service = S……这句不能写在while True外面。否则报错。很奇怪的坑,网上没有解决方案,最后是我自己改对的。
对于要点击的对象一定要wait.until等他加载出来。
路由器里面设备的序号是会变的,正如我注释掉的代码,所以最好的方式使用MAC地址来定位。通过XPATH寻找与定位MAC文本同框的按钮,非常稳定。
driver如果每次都新实例化比较慢和占CPU, 如果每次只用同一个driver会内存泄漏,所以折中,每64次ban,关掉浏览器重新实例化一个driver.
总结
每隔几十秒断网十几秒,实测监控不会显示断线,APP上面只能看到卡顿转圈圈,卡很久能进去,看了十几秒画面又不动了。
这绝不是阿Q式的或者扎纸小人式的自我安慰,而是我想要搞你 想要恶心一下你就有能力做到恶心一下你,你想偷窥我的生活就给你看,岂有此理,没那么容易!而且这个东西的应用也在客观上确实降低了他们看的频率,毕竟我实测感觉还是非常卡的。
另外这一次也算是点亮了一点浏览器自动控制的科技树,当初云原神每天只送15分钟的时候我都是手动登录,如果有这东西那么也许不会那么麻烦,不过可惜现在云原神免费了,没用了
更新
通过故障分析,情况判断,我的程序得到了一个很好的鲁棒性提升。
有的时候程序会找不到那个小米摄像机,那是因为等待的时间太短了,此时所有的2.4G联网设备全部离线,所以导致浏览器默认进入分类是5G设备,等再久也等不到摄像机重新连上。
还有别的概率bug不可复现。随他去吧
以下是更新之后的代码
#!/bin/python3
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC # 和下面WebDriverWait一起用的
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.firefox.service import Service
from selenium.common.exceptions import TimeoutException
from time import sleep, strftime, localtime
from random import randint, choice
def ban(driver, sec):
url = "http://192.168.6.6"
driver.get(url)
# wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'inputArea paddingleft_14')))
wait.until(EC.presence_of_element_located((By.ID, 'userpassword_ctrl')))
pw_input = driver.find_element(By.ID, 'userpassword_ctrl')
wait.until(EC.presence_of_element_located((By.ID, 'loginbtn')))
login_btn = driver.find_element(By.ID, 'loginbtn')
pw_input.send_keys("freedom")
sleep(0.06)
login_btn.click()
#sleep(6)
#sleep(1)
sleep(0.06)
wait.until(EC.presence_of_element_located((By.ID, "devicecontrol")))
#term_mng = driver.find_element(By.CLASS_NAME, 'nav_title')
#term_mng = driver.find_element(By.CLASS_NAME, 'small_icon want_devicecontrol')
#wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'small_icon want_devicecontrol')))
#term_mng = driver.find_element(By.CLASS_NAME, 'small_icon want_devicecontrol')
#term_mng.click()
#sleep(0.6)
driver.get("http://192.168.6.6/html/index.html#/devicecontrol")
actionchains = ActionChains(driver)
#wait.until(EC.presence_of_element_located((By.ID, 'InternetGatewayDevice_LANDevice_1_Hosts_Host_1__qoson')))
#btn = driver.find_element(By.ID, 'InternetGatewayDevice_LANDevice_1_Hosts_Host_1__qoson')
#wait.until(EC.presence_of_element_located((By.ID, 'InternetGatewayDevice_LANDevice_1_Hosts_Host_1__qoson')))
# btn = driver.find_element(By.ID, 'InternetGatewayDevice_LANDevice_1_Hosts_Host_1__qoson')
#btn = driver.find_element(By.ID, 'InternetGatewayDevice_LANDevice_1_Hosts_Host_1__blackon')
# check if 2.4G section
while True:
wait.until(EC.presence_of_element_located((By.ID, "device_selectlist_parenselect")))
div = driver.find_element(By.ID, 'device_selectlist_parenselect')
if div.text == "2.4G 联网设备":
# print(div.text)
break
else:
print("LOCATED" + div.text)
sleep(1)
driver.refresh()
sleep(0.2)
try:
wait.until(EC.presence_of_element_located((By.XPATH, "//*[text()='MAC 地址: 94:F8:27:78:20:A1']/../../../../div[2]/div[1]/div[1]")))
btn = driver.find_element(By.XPATH, "//*[text()='MAC 地址: 94:F8:27:78:20:A1']/../../../../div[2]/div[1]/div[1]")
btn.click()
except TimeoutException:
time_str = strftime("%Y-%m-%d--%H-%M-%S", localtime())
print(time_str, "START BAN FAILED")
with open(time_str + "start_failed.log", 'a') as f:
f.write(time_str + '\n' + driver.page_source + "\nSTART BAN FAILED")
sleep(sec - 1.6)
wait.until(EC.presence_of_element_located((By.ID, 'device_selectlist_parenselect')))
div = driver.find_element(By.ID, 'device_selectlist_parenselect')
actionchains.click(div).perform()
wait.until(EC.presence_of_element_located((By.ID, 'disallow_selectlist_SmallSelectBoxScrollItemID')))
disal = driver.find_element(By.ID, 'disallow_selectlist_SmallSelectBoxScrollItemID')
actionchains.click(disal).perform()
# actionchains.move_to_element(div).click().perform()
#wait.until(EC.presence_of_element_located((By.ID, 'InternetGatewayDevice_LANDevice_1_Hosts_Host_29__blackoff')))
# btn = driver.find_element(By.ID, 'InternetGatewayDevice_LANDevice_1_Hosts_Host_29__blackoff')
# btn.click()
try:
wait.until(EC.presence_of_element_located((By.XPATH, "//*[text()='MAC 地址: 94:F8:27:78:20:A1']/../../../../div[2]/div[1]/div[1]")))
btn = driver.find_element(By.XPATH, "//*[text()='MAC 地址: 94:F8:27:78:20:A1']/../../../../div[2]/div[1]/div[1]")
btn.click()
except TimeoutException:
time_str = strftime("%Y-%m-%d--%H-%M-%S", localtime())
print(time_str, "END BAN FAILED")
with open(time_str + "end_failed.log", 'a') as f:
f.write(time_str + '\n' + driver.page_source + "\nEND BAN FAILED")
driver.get("about:blank")
sleep(0.1)
driver.refresh()
#print(driver.page_source)
if __name__ == '__main__':
while True:
print("drv init", flush=True)
opt = webdriver.FirefoxOptions()
# 设置无界面
opt.add_argument("--headless")
# opt.page_load_strategy = 'none'
# firefox_profile = webdriver.FirefoxProfile()
# firefox_profile.set_preference('permissions.default.image', 2)#某些firefox只需要这个
# firefox_profile.set_preference('permissions.default.stylesheet', 2)
service = Service(log_path='/dev/null')
# 禁用 gpu
# opt.add_argument('--disable-gpu')
driver = webdriver.Firefox(options=opt, service=service)
wait = WebDriverWait(driver, 10)
waittimelist = list(range(8, 10)) * 4 + list(range(8, 17))
for i in range(50):
time_str = strftime("%Y-%m-%d--%H-%M-%S", localtime())
print(time_str)
print(i, "ban", s:=randint(9, 16), flush=True)
ban(driver, s)
print(i, "wait", s:=choice(waittimelist), flush=True)
sleep(s)
driver.quit()