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这个参数;以上方法安装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', '')
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="""
%s
""" % 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
完毕了。进一步优化代码,将所有截图放到一个页面。避免抄袭嫌疑无法审核通过,改为转载。