1.背景:
突发奇想,每天值班需要截图的,想让程序实现截图再发邮件出来以下只进行了实现,有待完善。走了不少弯路。这里记录下。
起初用的python 的 requests模块(带session保持的)实现后发现,只能爬取页面代码就像浏览器打开页面后 查看源代码一样。
这并不是我想要的(如果爬的是cacti可以获取页面的链接,然后再请求链接,存到png里就是cacti的图。参考链接:http://blog.51cto.com/zhangfang2012/1586391) 下边先讲的这个。
我想要的是登录网站,然后打开页面,然后截屏。下边后讲的是这个。
2.requests模块自动登录及会话保持。
相关问题可以参考 "requests的高级用法(http://docs.python-requests.org/zh_CN/latest/user/advanced.html)
上代码及说明 其实requests模块相当于替代浏览器发起请求,所以很多东西都需要分析清楚再构造出来。
#!/usr/bin/env python # -*- coding:utf-8 -*- import requests # 本文没有用到,不过据说这个模块值得学习。 from bs4 import BeautifulSoup # 定义 更新请求header方法 由于需要登录的网站每次都需要携带cookie 头cookie信息是csrftoken sessionid。 #因此每次请求完都需要更新请求header中的cookie信息。否则提示未登录 def update_header(s): #将CookieJar转为字典以便读取cookie信息。session会话默认是CookieJar格式。 #详细可参考这(https://blog.csdn.net/falseen/article/details/46962011) #获取请求后获取更新的csrftoken sessionid cookies = requests.utils.dict_from_cookiejar(s.cookies) #拼接成请求头中cookie的内容 cookie_str="csrftoken="+cookies["csrftoken"]+"; "+"sessionid="+cookies["sessionid"] #POST请求需要携带CSRF信息到POST数据中 csrf=cookies["csrftoken"] new_header ={ "User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36", "Accept-Encoding":"gzip, deflate", "Accept-Language":"zh-CN,zh;q=0.8", "Connection":"keep-alive", "Content-Type":"application/x-www-form-urlencoded", "Cookie":cookie_str, #更新这个内容 "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" } return new_header,csrf def login(s): print "正在请求登录页面..." login_page_url = "http://a.b.com/login/" login_html = s.get(login_page_url) #通过get请求获取csrftoken 和sessionid print "正在解析" login_url = "http://a.b.com/login/" post_header,csrf = update_header(s) #把请求信息整理出来更新登录请求的header #获取最新的包含cookie内容的header及csrf值。构建post数据 values = { 'csrfmiddlewaretoken':csrf, 'username':'name', 'password':'passwd' } #print s.headers s.headers.update(post_header) #更新session对象的请求header #print s.headers #发起post请求。 login_data = s.post(url=login_url, data=values) #print s.headers print login_data.status_code #打印登录请求状态码。 #print login_data.text #print s.headers #print s.cookies header,_=update_header(s) #登录成功后再请求其他内容,需要更新获取到的最新csrf到请求header s.headers.update(header) html = s.get("http://a.b.com/dash/screen/83/?start=-604800&stype=&end=") print html.status_code print html.content #soup = BeautifulSoup(html.content) #print soup.find_all("title") if __name__ == '__main__': with requests.Session() as s: #会话还用作前后文管理器,保证with 区块退出后会话能被关闭 login(s)
以上是通过requests实现携带csrftoken信息登录的实现。只能获取到对应的html页面,无法达到我想要的截图。
后来发现这并不是我想要的,我需要的是能打开页面,并进行截图。
3.selenium 的webdriver 及 pyvirtualdisplay Display
需要下载或安装很多东西
firefox 或者chrome 以下用的firefox
apt-get install firefox
firefox的驱动
https://github.com/mozilla/geckodriver/releases 这里可以下载各种版本。推荐最新版本。
如果运行时报错selenium.common.exceptions.InvalidArgumentException: Message: Expected [object Undefined] undefined to be a string 是版本问题。
wget https://github.com/mozilla/geckodriver/releases/download/v0.20.1/geckodriver-v0.20.1-linux64.tar.gz
wget https://github.com/mozilla/geckodriver/releases/download/v0.11.1/geckodriver-v0.11.1-linux64.tar.gz
phantomjs
wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
错误提示:
selenium.common.exceptions.WebDriverException: Message: 'geckodriver' executable needs to be in PATH.
解决方法:
以上两个压缩包解压后,将对应的执行文件cp到/usr/local/bin /usr/sbin/
继续安装python组件
pip install selenium -i http://pypi.douban.com/simple/
pip install pyvirtualdisplay -i http://pypi.douban.com/simple/
apt-get install xvfb ##Xvfb是流行的虚拟现实库,可以使很多需要图形界面的程序虚拟运行
这对firefox浏览器中文乱码问题:
sudo apt-get install ttf-wqy-microhei #文泉驿-微米黑
sudo apt-get install ttf-wqy-zenhei #文泉驿-正黑
sudo apt-get install xfonts-wqy #文泉驿-点阵宋体
flash player 下载地址 NPAPI格式的 最新版本
https://fpdownload.adobe.com/get/flashplayer/pdc/29.0.0.140/flash_player_npapi_linux.x86_64.tar.gz
打开Firefox后发现很多地方需要flashplayer插件,有时候通过自动安装显示不成功,那么有必要采取如下措施来解决:
1:下载flash_player_npapi_linux.x86_64.tar.gz文件;
2:解压tar -xzvf flash_player_npapi_linux.x86_64.tar.gz,若想解压到某个文件夹中,加上-C这个参数;3:找到libflashplayer.so所在的目录,拷贝libflashplayer.so :sudo cp libflashplayer.so /usr/lib/firefox/browser/plugins/
以上方法安装flash插件。
注:各个资源下载地址参考(https://blog.csdn.net/huilan_same/article/details/52615123)
以下方法激活flash插件。
(运行的服务器没有安装图形界面,且跑着其他服务,尝试不重启服务器,直接修改firefox配置文件来解决,最终失败。还是需要安装图形界面,然后重启后远程通过IPMI登录后打开firefox浏览器设置。设置flash “永远激活”状态,然后记录配置文件位置,在程序的webdriver启动firefox时,加载刚才那个firefox配置文件。)
好多windows下自己创建firefoxprofile的操作方法,linux 下也需要图形化界面
http://blog.163.com/wxiaoch_0904/blog/static/96091031201352134033340/
https://www.cnblogs.com/huangweiping/p/5398616.html
官网的配置操作方法:https://support.mozilla.org/zh-CN/kb/%E7%AE%A1%E7%90%86%E7%94%A8%E6%88%B7%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6
官网的配置操作方法:https://support.mozilla.org/zh-CN/kb/%E7%94%A8%E6%88%B7%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6
https://support.mozilla.org/en-US/kb/using-dedicated-profile-firefox-beta#firefox:win7:fx59
https://wiki.ubuntu.com.cn/Firefox%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6
http://blog.163.com/wxiaoch_0904/blog/static/96091031201352134033340/
图形界面的安装(推荐gdm(apt-get install gdm) 其他还有lightdm (apt-get install lightdm) 还有startx (apt-get install xinit) 安装后 我尝试通过startx /usr/bin/firefox 的方式创建初始化 firefox的用户配合文件到目录/root/.mozilla/firefox/ 然后通过修改用户个人配置的方式让webserver加载flash。但未成功。/root/.mozilla/firefox/profiles.ini 里面是用户配置文件名称 (/root/.mozilla/firefox/ryoedywd.default/prefs.js)新增user_pref("plugin.state.flash", 2); 0 关闭flash,1总是询问,2永远激活) 通过startx /usr/bin/firefox启动创建firefox配置文件出现报错:“X: user not authorized to run the X server, aborting.”
解决办法: /etc/X11/Xwrapper.config 改成 allowed_users=anybody
或者执行如下命令: dpkg-reconfigure x11-common 选择anybody
startx启动失败参考链接: https://blog.csdn.net/mountzf/article/details/52067359
配置webdriver 启动加载的个人用户配置文件。
backup_browser = webdriver.Firefox(firefox_profile="/root/.mozilla/firefox/pfinfrwz.default")
代码:
#!/usr/bin/env python # -*- coding:utf-8 -*- import time from selenium import webdriver from pyvirtualdisplay import Display import smtplib from email.mime.text import MIMEText from email.mime.image import MIMEImage from email.mime.multipart import MIMEMultipart ###email settings png_path = '/home/phenix/liyq/source_report/' _from = '' #发邮件的邮箱地址 _to = [''] #收邮件的邮箱地址 username = '' #发邮件的邮箱地址 passwd = '' #发邮箱的邮箱密码 def sendHtmlmail(From, To, Subject, Content,Png): msg = MIMEMultipart() msg['From'] = From msg['To'] = ';'.join(To) msg['Subject'] = Subject txt = MIMEText(Content, _subtype='html', _charset='utf-8') msg.attach(txt) with open(Png,'rb') as f : msgImage = MIMEImage(f.read()) msgImage.add_header('Content-ID', '<image1>') msg.attach(msgImage) smtp = smtplib.SMTP() smtp.connect('smtp.exmail.qq.com') smtp.login(username,passwd) smtp.sendmail(From, To, msg.as_string()) smtp.quit() def login(login_info): if login_info["engine"] == "PhantomJS": browser = webdriver.PhantomJS() if login_info["engine"] == "Firefox": browser = webdriver.Firefox() ## 无法截取全页面只能截屏 browser.maximize_window() browser.get(login_info["login_url"]) browser.find_element_by_id(login_info["username"]).clear() #清除用户名输入框中的内容 browser.find_element_by_id(login_info["username"]).send_keys(login_info["n"]) #输入用户名 browser.find_element_by_id(login_info["password"]).clear() #清除密码输入框中的内容 browser.find_element_by_id(login_info["password"]).send_keys(login_info["p"]) #输入密码 browser.find_element_by_xpath(login_info["button"]).click() #点击登录按钮 time.sleep(5) return browser def shot_and_mail(browser,url,shot_filename,title,hide_menu): if url["extra"]: browser.get(url["url"]) browser.find_element_by_id(url["name"]).clear() #清除用户名输入框中的内容 browser.find_element_by_id(url["name"]).send_keys(url["key"]) #输入用户名 browser.find_element_by_xpath(url["button"]).click() #点击登录按钮 time.sleep(5) else: browser.get(url["url"]) if hide_menu: browser.find_element_by_xpath("/html/body/div[1]/div/div[1]/div").click() ## 收起左边 browser.execute_script(""" (function () { var y = 0; var step = 100; window.scroll(0, 0); function f() { if (y < document.body.scrollHeight) { y += step; window.scroll(0, y); setTimeout(f, 50); } else { window.scroll(0, 0); document.title += "scroll-done"; } } setTimeout(f, 1000); })(); """) for i in xrange(30): if "scroll-done" in browser.title: break time.sleep(10) #以上代码是将浏览器从上拉到最下面,然后再拉回顶端,等待10s后然后再进行后边操作,避免页面加载不完。 # browser.save_screenshot(shot_filename) _content=""" <H1>%s</H1> <br> <img src="cid:image1"/> """ % title _subject = title png=png_path+shot_filename sendHtmlmail(_from,_to,_subject,_content,png) if __name__ == '__main__': display = Display(visible=0, size=(1366, 800)) display.start() # falcon_login_info={ # "engine":"PhantomJS", # "login_url":"http://a.b.com/login/", #登录地址 # "username":"name", # "password":"password", # "n":"", #用户名需要输入 # "p":"", #密码需要输入 # "button":"/html/body/div/div/div/div/div/form/div[2]/div/button" #登录按钮 # } # falcon_browser = login(falcon_login_info) # ##cdn回源域名带宽 # url ={"url":"http://a.b.com/dash/screen/83/?start=-604800&stype=&end=","extra":False} # shot_filename="cdn_domain_source.png" # title="cdn回源域名带宽日报" # shot_and_mail(falcon_browser,url,shot_filename,title,True) # ## CDN回源服务器带宽 # url ={"url":"http://a.b.com/dash/screen/22/?start=-604800&stype=&end=","extra":False} # shot_filename="cdn_source_bandwidth.png" # title="cdn回源服务器带宽" # shot_and_mail(falcon_browser,url,shot_filename,title,True) # ## CDN回源服务器nginx相应时间 # url ={"url":"http://a.b.com/dash/screen/22/?item=nginx&start=-604800&stype=&end=","extra":False} # shot_filename="cdn_source_nginx.png" # title="cdn回源服务器nginx响应时间" # shot_and_mail(falcon_browser,url,shot_filename,title,False) # ## VDN各机房带宽及汇总 # url ={"url":"http://a.b.com/dash/?start=-604800&end=&stype=","extra":False} # shot_filename="vdn_bandwidth.png" # title="VDN各个机房带宽及汇总" # shot_and_mail(falcon_browser,url,shot_filename,title,True) # falcon_browser.quit() # twinkle_login_info={ # "engine":"Firefox", # "login_url":"https://a.b.com/cas-server/login", #登录链接 # "username":"username", # "password":"password", # "n":"", #twinkle 用户名 # "p":"", #twinkle密码 # "button":"//*[@id=\"fm1\"]/div[3]/input[4]" #登录按钮 # } # twinkle_browser = login(twinkle_login_info) # ##唱吧带宽 # url ={"url":"http://a.b.com/charts/detail/user/","extra":True,"name":"userid","key":"216588","button":"//*[@id=\"sub_btn\"]"} # shot_filename="216588.png" # title="唱吧带宽日报" # shot_and_mail(twinkle_browser,url,shot_filename,title,False) # twinkle_browser.quit() #灾备播放 无需登录 由于phantomjs 不支持视频播放因此使用Firefox截图,但是截图只能截当前窗口,因此分两个 profile = webdriver.FirefoxProfile("/root/.mozilla/firefox/pfinfrwz.default") profile.set_preference("plugin.state.flash",2) backup_browser = webdriver.Firefox(profile) #backup_browser = webdriver.PhantomJS() #profile.set_preference("plugin.state.flash",2) url= {"url":"http://a.b.com:5160/cooper/core_backup1.html","extra":False} shot_filename="backup1.png" title="灾备播放测试" shot_and_mail(backup_browser,url,shot_filename,title,False) #backup_browser = webdriver.PhantomJS() ## 不支持视频播放 url= {"url":"http://a.b.com:5160/cooper/core_backup2.html","extra":False} shot_filename="backup2.png" title="灾备播放测试" shot_and_mail(backup_browser,url,shot_filename,title,False) backup_browser.quit() display.stop()
参考链接:http://www.cnblogs.com/leeboke/p/5013711.html
http://www.cnblogs.com/puresoul/p/4251536.html
完毕了。进一步优化代码,将所有截图放到一个页面。避免抄袭嫌疑无法审核通过,改为转载。