近段时间,因熊孩子沉迷于电视而致命学习成绩下降,遂有了在不影响家里老人正常观看电视的情况下对电视进行限制的需求,经过思索后准备利用爬虫技术来实现,即在熊孩子放学时自动登录网管交换机来对机顶盒进行限速,熊孩子上学后再解除针对机顶盒的限速。`
现在的熊孩子岁数不大却非常聪明,可以自己开电视并换台寻找喜爱的电视节目,之前采用拨网线的暴力方法来禁止熊孩子无休止的观看电视,后因经常拨网线后忘了重新插上而导致老人无法看电视,遂此方法被废弃………
好在经过思索,发现家里的 IPTV 连在了 Netgear 网管交换机上,我们可以在交换机上对 IPTV 端口进行限速,以使电视无法正常观看。
说起爬虫,首先想到的就是 Python,经过一翻google,确定了使用Selenium、Firefox/Chrome来实现爬虫功能。
Github-Selenium
Selenium 是一个用于 Web 应用程序的测试工具。Selenium 直接调用浏览器来进行测试,就像真正的用户在操作一样。它支持 IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera,HtmlUnit,phantomjs,Android(需安装 Selendroid 或 appium),IOS(需安装ios-driver 或 appium)等。
Selenium 支持 C# / JavaScript / Java / Python / Ruby 开发语言。它使用 WebDriver 来操作浏览器进行网页测试。
在爬虫中 Selenium 主要用来解决 JavaScript 的渲染问题。
Webdriver 是一个用来和浏览器进行交互的编程接口,通过它可以操作浏览器打开或关闭、发送鼠标点击、模拟键盘输入等等。
W3C 定义了 WebDriver 规范。现在最流行的 WebDrver 为开源软件 Selenium WebDriver。
WebDriver 包含多个模块:
:~$ apt-get install python3 python3-pip
:~$ pip3 install selenium
:`$ apt-get install chromium-driver
Geckodriver
,自github-geckodriver下载。:~$ wget https://github.com/mozilla/geckodriver/releases/download/v0.26.0/geckodriver-v0.26.0-linux64.tar.gz
:~$ tar -xvf geckodriver-v0.26.0-linux64.tar.gz
:~$ mv geckodriver /usr/local/bin/
这里我们使用 Python 语言。
先来一段爬虫界的Hello World
。
#!/usr/bin/env python3
# coding=utf-8
import time
from selenium import webdriver
print("初始化 ChromeDriver,并打开 Chrome")
driver = webdriver.Chrome()
print("打开 shixuen.com 网址")
driver.get("https://www.shixuen.com")
time.sleep(5)
print("关闭浏览器")
driver.close()
print("初始化 geckodriver 并打开 Firefox 浏览器")
driver = webdriver.Firefox()
driver.get("https://www.shixuen.com")
time.sleep(5)
driver.close()
from selenium import webdriver
driver = webdriver.Chrome()
driver = webdriver.Firefox()
2. 使用driver.get( "https://www.shixuen.com" )
来打开网站
3. 关闭浏览器,driver.close()
。
我们再添加点新功能,打开https://www.shixuen.com
后,点击文章VIM Plugin - YouCompleteMe
。
依旧先看代码
#!/usr/bin/env python3
# coding=utf-8
import time
from selenium import webdriver
print("初始化 ChromeDriver,并打开 Chrome")
driver = webdriver.Chrome()
print("打开 shixuen.com 网址")
driver.get("https://www.shixuen.com")
print("搜索指定文本的链接")
article = driver.find_element_by_link_text("VIM Plugin - YouCompleteMe")
print("点击此链接")
article.click()
time.sleep(5)
print("关闭浏览器")
driver.close()
关键代码为driver.find_element_by_link_text( "VIM Plugin - YouCompleteMe" )
,搜索文字内容为VIM Plugin - YouCompleteMe
的链接,找到后返回此节点的对象。
如网页节点的代码:
ID
进行搜索,driver.find_element_by_id( "btn_apply" )
链接的文本内容
进行搜索,driver.find_element_by_link_text( "Apply" )
class
进行搜索,driver.find_element_by_class_name( "btn_class" )
xpath
进行搜索,driver.find_element_by_xpath( "//a[@id='btn_apply' and @class='btn_class']" )
/
:从根节点开始进行搜索//
:搜索所有节点./
:搜索本节点下的子节点上面的代码算是爬虫界的Hello World
吧。
下面,进入本文的正题,登录并配置 Netgear 网管交换机。依旧不废话,先上代码。
#!/usr/bin/env python3
# coding=utf-8
import time, sys, getopt, os
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.select import Select
_gs105e_rate_limit = {
"unlimit": 1,
"limit": 3
}
gs105e_conf = {
"url": "http://192.168.1.2",
"password": "0123456789",
"rate": _gs105e_rate_limit["limit"],
"port": "port2"
}
def browser( driver ):
print( "打开交换机网页" )
driver.get( gs105e_conf["url"] )
print( "输入密码" )
passwd_input = WebDriverWait( driver, 10 ).until( EC.presence_of_element_located( (By.ID,"password") ) )
passwd_input.send_keys(gs105e_conf["password"])
print("点击登录")
btn_login = driver.find_element_by_id("loginBtn")
bt_login.click()
print("点击 菜单" )
menu_qos = WebDriverWait(driver,10).until( EC.presence_of_element_located( (By.ID, "QoS") ) )
menu_qos.click()
print("点击 菜单" )
menu_qos_ratelimit = driver.find_element_by_id("QoS_RateLimit")
menu_qos_ratelimit.click()
print("等待子页面加载完成")
time.sleep(4)
print("跳转至子页面")
iframe = driver.find_element_by_xpath("//iframe[@id='maincontent']")
driver.switch_to.frame( iframe )
print("点击端口对应的 " )
WebDriverWait(driver,10).until( EC.presence_of_element_located( (By.NAME,gs105e_conf["port"]) ) ).click()
print("选择入站速率")
btn_select = driver.find_element_by_name("IngressRate")
Select( btn_select ).select_by_index( gs105e_conf["rate"] )
print("选择出站速率")
btn_select = driver.find_element_by_name("EgressRate")
Select( btn_select ).select_by_index( gs105e_conf["rate"] )
print("由子页面返回主页面")
driver.switch_to.default_content()
print("点击 <应用> 按钮")
btn_apply = driver.find_element_by_id("btn_Apply")
btn_apply.click()
print("点击 <退出> 按钮")
btn_logout = WebDriverWait(driver,10).until( EC.presence_of_element_located( (By.ID,"logout") ) )
btn_logout.click()
def main():
try:
driver = webdriver.Firefox()
browser(driver)
except:
print("error in script!")
finally:
print("Close Brwoser!")
driver.close()
if __name__ == "__main__":
main()
上面的代码已经可以实现登录 Netgear网管交换机并自动对 TV 端口进行限速了。每一步都写得非常清楚,只不过多了几个函数和页面间的跳转而已。
下面对代码进行解析:
driver.get( "url" )
打开 Netgear 网管交换机的登录界面。WebDriverWait( driver,10 ).until( EC.presence_of_element_located( (By.ID,"password") ) )
,它的意思就是在10秒
内使用driver
来获取ID
为password
的元素,如果获取成功则返回元素对象,如果超时则报错。By
、EC
和WebDriverWait
需要提前import
。By.ID
即以ID
进行查找,同理还有By.NAME
、By.XPATH
、By.CLASS_NAME
、By.LINK_TEXT
等等。ID
为 password
的元素,我们代码就会报错。所以上面那句代码也可以改为print ("等待页面加载完成后,获取 ID 为 password 的元素")
time.sleep(10)
passwd_input = driver.find_element_by_id("password")
而passwd_input.send_keys( gs105e_conf["password"] )
则是模拟键盘输入字符
QoS --> 速率限制
,见下图。QoS 速率限制
是以iframe
方式加载,所以我们需要先将driver
的当前页面跳转至iframe
上,使用driver.switch_to.frame( iframe )
来进行跳转。否则搜索不到Checkbox
选择框。CheckBox
以选中端口,然后对修改入站速率与出站速率,这里因为出入站速率为下拉列表,所以这里需要使用selenium.webdriver.support.select
类来进行选择,Select( btn_select ).select_by_index( 3 )
为选择从上数第四选项,第一选项索引为0
.iframe
返回主页面并点击应用
。退出登录
。上面的代码必须在图形界面运行,因为其会弹出浏览器窗口。而我们的服务器因为没有图形界面运行时会报错,所以这里我们使用--headless
选项来禁止浏览器加载图形界面,使其可以在终端里运行。
下面是最终代码,对上面的代码其进行了修饰,并添加了选项功能,可以对 Netgear 网管交换机的某端口进行限速,也可以解除某端口的限速。
#!/usr/bin/env python3
# coding=utf-8
#####################################################
# > File Name: automanagetv.py
# > Author: haven200
# > Mail: [email protected]
# > Created Time: Saturday, November 16, 2019 AM10:14:30 HKT
#####################################################
import time, sys, getopt, os
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.select import Select
_gs105e_dict = {
"unlimit":1,
"limit":3,
"huawei":"port2",
"phicomm":"port5"
}
gs105e_conf = {
"url":"http://192.168.1.2",
"password":"0123456789",
"rate":_gs105e_dict["unlimit"],
"port":_gs105e_dict["huawei"],
"browser":""
}
def browser(driver):
print("open gs105 webpage")
driver.get(gs105e_conf["url"])
print("login")
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID,"password"))
).send_keys(gs105e_conf["password"])
driver.find_element_by_id("loginBtn").click()
print("goto Qos page")
WebDriverWait(driver,10).until(EC.presence_of_element_located((By.ID, "QoS"))).click()
driver.find_element_by_id("QoS_RateLimit").click()
time.sleep(4)
driver.switch_to.frame(driver.find_element_by_xpath("//iframe[@id='maincontent']"))
print("modify the rate")
WebDriverWait(driver,10).until(EC.presence_of_element_located((By.NAME,gs105e_conf["port"]))).click()
Select(driver.find_element_by_name("IngressRate")).select_by_index(gs105e_conf["rate"])
Select(driver.find_element_by_name("EgressRate")).select_by_index(gs105e_conf["rate"])
print("click Apply button")
driver.switch_to.default_content()
driver.find_element_by_id("btn_Apply").click()
WebDriverWait(driver,10).until(EC.presence_of_element_located((By.ID,"logout"))).click()
def main():
try:
if gs105e_conf["browser"] == "firefox":
print("Open [geckodriver]")
firefox_options = webdriver.FirefoxOptions()
firefox_options.add_argument('--headless')
firefox_options.add_argument("user-agent='Mozilla/5.0 (X11; Linux i686; rv:67.0) Gecko/20100101 Firefox/67.0'")
driver = webdriver.Firefox(options=firefox_options)
elif gs105e_conf["browser"] == "chrome" :
print("Open [chromedriver]")
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument("user-agent='Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3831.6 Safari/537.36'")
driver = webdriver.Chrome(options=chrome_options)
else:
show_help()
browser(driver)
except:
print("error in script!")
finally:
print("Close Brwoser!")
driver.close()
def show_help():
print("automanagetv.py -r -p [tv|phicomm] -b [firefox|chrome]" )
print("made by [email protected], version 0.0.1\n")
print(" -r, --rate limit: limit the network speed to 1Mb/s")
print(" unlimit: release network speed limit")
print(" -p, --port huawei: Huawei Set_Top_Box")
print(" phicomm: phicomm_n1 Set_Top_Box")
print(" -b, --browser firefox: use firefox")
print(" chrome: use chrome")
sys.exit()
if __name__ == "__main__":
if len(sys.argv) == 1: show_help()
if len(os.popen("whereis geckodriver | awk '{print $2}'").read()) > 5:
gs105e_conf["browser"] = "firefox"
elif len(os.popen("whereis chromedriver | awk '{print $2}'").read()) > 5:
gs105e_conf["browser"] = "chrome"
try:
opts, args = getopt.getopt(sys.argv[1:], "hr:p:b:", ["rate=", "port=", "browser="])
except getopt.GetoptError:
show_help()
for opt, arg in opts:
if opt == '-h':
show_help()
elif opt in ("-r", "--rate"):
if arg == "limit" or arg == "unlimit": gs105e_conf["rate"] = _gs105e_dict[arg]
elif opt in ("-p", "--port"):
if arg == "huawei" or arg == "phicomm": gs105e_conf["port"] = _gs105e_dict[arg]
elif opt in ("-b", "--browser"):
if arg == "firefox" or arg == "chrome": gs105e_conf["browser"] = arg
main()
脚本的使用方法:
# 对 tv 端口的速率限速
:~$ python3 automanagetv.py -r limit -p tv
# 恢复 TV 端口的速率
:~$ python3 automanagetv.py -r unlimit -p tv
最后,我们在Cron
里添加定时运行即可。
:~$ crontab -e
00 12 * * 1-5 /etc/init.d/automanagetv.py -r limit -p tv
00 13 * * 1-5 /etc/init.d/automanagetv.py -r unlimit -p tv
00 19 * * 1-5 /etc/init.d/automanagetv.py -r limit -p tv
40 20 * * 1-5 /etc/init.d/automanagetv.py -r unlimit -p tv
周一至周五,中午12点至13点进行限速,晚上19:00至20:40进行限速。而周六、周日嘛,电视就属于熊孩子的了。
References:
- selenium.org
- testproject
- hongkiat
- csdn