分類
方法

python selenium 常用命令記錄

記錄一些常用命令。

from selenium import webdriver
#等待
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import TimeoutException
#鍵盤
from selenium.webdriver.common.keys import Keys
#select元素
from selenium.webdriver.support.ui import Select

##配置並開啟火狐
firefox_profile = webdriver.FirefoxProfile()
#語言設置為zh-CN,en-US
firefox_profile.set_preference('intl.accept_languages','zh-CN')
#UA設置為iphone6 plus
firefox_profile.set_preference("general.useragent.override", "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1")
#2關閉瀏覽器圖片
firefox_profile.set_preference('permissions.default.image', 2)
driver = webdriver.Firefox(firefox_profile=firefox_profile)  
#窗口大小
driver.set_window_size(414,736) 
#窗口最大化,可解決一些元素因窗口太小為顯示而無法點擊的情況
driver.maximize_window()
#頁面超時
driver.set_page_load_timeout(50)

##給火狐設置 http 或 socks 代理
firefox_profile = webdriver.FirefoxProfile()
proxy_ip = "127.0.0.1"
proxy_port = 18409
firefox_profile.set_preference("network.proxy.type", 1)
#http代理需要設置下面四行
firefox_profile.set_preference("network.proxy.http", str(proxy_ip))
firefox_profile.set_preference("network.proxy.http_port", int(proxy_port))
firefox_profile.set_preference("network.proxy.ssl", str(proxy_ip))
firefox_profile.set_preference("network.proxy.ssl_port", int(proxy_port))
#socks 代理只需設置下面兩行
firefox_profile.set_preference("network.proxy.socks", str(proxy_ip))
firefox_profile.set_preference("network.proxy.socks_port", int(proxy_port))
#可選
firefox_profile.set_preference("network.http.use-cache", False)
#可選
firefox_profile.update_preferences()
driver = webdriver.Firefox(firefox_profile=firefox_profile)
#在無界面模式下運行 headless
from selenium.webdriver.firefox.options import Options as FirefoxOptions
options = FirefoxOptions()
options.add_argument("--headless")
driver = webdriver.Firefox(firefox_profile=firefox_profile,options=options)

##driver的完整初始化參數
webdriver.Firefox(firefox_profile=None, firefox_binary=None,
capabilities=None, proxy=None,
executable_path=DEFAULT_EXECUTABLE_PATH, options=None,
service_log_path=DEFAULT_SERVICE_LOG_PATH,
service_args=None, service=None, desired_capabilities=None,
log_path=DEFAULT_LOG_PATH, keep_alive=True)
#https://github.com/SeleniumHQ/selenium/blob/trunk/py/selenium/webdriver/firefox/webdriver.py#L44
##頁面操作
#打開頁面
try:
    driver.get("https://reportaproblem.apple.com")
except:
    try:
        #長時間沒加載完頁面時,可能是卡在了某個資源,按下Esc停止等待
        driver.find_element_by_xpath('//body').send_keys(Keys.ESCAPE)
    except:
        return 'fail'

#有時鏈接會打開新窗口,切換到新窗口
driver.switch_to_window(driver.window_handles[-1])
#當前頁面鏈接
driver.current_url
#當前頁面標題
driver.title

#等待元素出現
try:
    WebDriverWait(driver, 60).until(lambda the_driver: the_driver.find_element_by_xpath("//iframe[@id='aid-auth-widget-iFrame']").is_displayed())
except:
    pass
##定位元素
#frame
driver.find_element_by_xpath("//iframe[@id='aid-auth-widget-iFrame']")
#ID
driver.find_element_by_id("appleId")
#根據屬性定位元素
captchaInput = driver.find_element_by_xpath("//input[@placeholder='键入图中的字符']")
#獲取輸入框中的值
inputValue = captchaInput.get_attribute('value')
#向輸入框中寫入字符
captchaInput.send_keys("你好")
#清空輸入框
captchaInput.clear()
#按下Tab鍵
driver.find_element_by_xpath('//body').send_keys(Keys.TAB)

capDivImg=driver.find_element_by_xpath("//div[@class='form-cell']//img")
#獲取圖片的鏈接
imgSrc=capDivImg.get_attribute('src')

#點擊包含“繼續”的按鈕
driver.find_element_by_xpath("//button[contains(text(),'继续')]").click()
#根據CSS定位button
driver.find_element_by_xpath("//button[@class='button button-primary last nav-action']")

#點擊值為“步行”的選項
driver.find_element_by_xpath("//option[text()='步行']").click()

#定位一組元素
labels = driver.find_elements_by_css_selector("label.labelClass")
answerInputs = driver.find_elements_by_xpath("//input[@placeholder='答案']")
questions = []
for label in labels:
    questions.append( label.get_attribute('innerHTML') )

#等待包含特定字符的元素
WebDriverWait(driver, 3).until(lambda the_driver: the_driver
           .find_element_by_xpath("//p[@class='subtitle content-item tk-label'][contains(text(),'已超时')]")
           .is_displayed())

#獲取select元素
typeS = Select(driver.find_element_by_id("searchDropdownBox"))
#根據值來選中select元素
typeS.select_by_visible_text('行山')
#獲取元素顯示的文字
driver.find_element_by_xpath("//tr[@class='updateblock']//td[@class='timer']").get_attribute("innerText")
driver.find_element_by_xpath("//tr[@class='updateblock']//td[@class='timer']").get_attribute("innerHTML")

本文更新於 2021/12/24。

分類
程序

使用xtrabackup備份mysql數據庫

本文主要記錄下使用percona xtrabackup 2.4來備份mysql數據。最終效果是實現mysql所在主機定時進行全量備份和增量備份並自動刪除舊備份文件。另有一台數據存儲機,定時通過ssh抓取各個mysql主機上的備份文件,保存更長時間後刪除舊文件。

用到的軟件和技術有:xtrabackup(免費的mysql備份程序),qpress(xtrabackup壓縮需要的依賴,據說壓縮比很高),python3.5(ssh的遠程抓取,因為我不會bash)。

mkdir -p /root/42/script
cd /root/42/script
#安裝qpress
wget http://www.quicklz.com/qpress-11-linux-x64.tar
tar xf qpress-11-linux-x64.tar
mv qpress /usr/local/bin/
#centos6安裝xtrabackup
yum install http://www.percona.com/downloads/percona-release/redhat/0.1-4/percona-release-0.1-4.noarch.rpm
yum install libev -y
yum install percona-xtrabackup-24 -y
#新建backup.sh(來源未知)內容如下:
#!/bin/bash

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
 
BACKUP_BASE_DIR="/data/backup/xtrabackup"
INC_BASE_LIST="${BACKUP_BASE_DIR}/inc_list.txt"
XTRABACKUP_PATH="/usr/bin/innobackupex"
 
MYSQL_CNF="/etc/my.cnf"
MYSQL_HOSTNAME=127.0.0.1
MYSQL_USERNAME=root
MYSQL_PASSWORD=""
 
LOCK_FILE="/tmp/innobackupex.lock"
THREAD=3
 
mkdir -p ${BACKUP_BASE_DIR}
CURRENT_BACKUP_PATH="${BACKUP_BASE_DIR}/$(date +%F_%H-%M)"
[[ -d ${CURRENT_BACKUP_PATH} ]] && CURRENT_BACKUP_PATH="${BACKUP_BASE_DIR}/$(date +%F_%H-%M-%S)"
 
print_help(){
    echo "--------------------------------------------------------------"
    echo "Usage: $0 full | inc | help               "
    echo "--------------------------------------------------------------"
    exit 1
}
 
[[ $# -lt 1 || "$1" == "help" ]] && print_help
 
[[ -f "$LOCK_FILE" ]] && echo -e "Usage: rm -f $LOCK_FILE\nUsage: chattr -i $LOCK_FILE && rm -f $LOCK_FILE" && exit 1
 
FullBackup(){
    touch $LOCK_FILE
    chattr +i $LOCK_FILE
    local rc=0
    ${XTRABACKUP_PATH} \
    --defaults-file=${MYSQL_CNF} \
    --user=${MYSQL_USERNAME} \
    --password=${MYSQL_PASSWORD} \
    --host=${MYSQL_HOSTNAME} \
    --compress \
    --compress-threads=${THREAD} \
    --parallel=${THREAD} \
    --no-timestamp ${CURRENT_BACKUP_PATH} > ${CURRENT_BACKUP_PATH}_full.log 2>&1
    grep ".*\ completed\ OK\!" ${CURRENT_BACKUP_PATH}_full.log > /dev/null 2>&1
    if [ $? -ne 0 ];then
        rc=1
        [[ -d ${CURRENT_BACKUP_PATH} && $(pwd) != "/" ]] && rm -rf ${CURRENT_BACKUP_PATH}
    else
        echo "NULL|${CURRENT_BACKUP_PATH}|full" >> ${INC_BASE_LIST}
        [[ -d ${CURRENT_BACKUP_PATH} && $(pwd) != "/" ]] && chattr +i ${CURRENT_BACKUP_PATH} || rc=1
    fi
    chattr -i ${LOCK_FILE}
    rm -f $LOCK_FILE
    chattr +a ${INC_BASE_LIST}
    return $rc
}
 
IncBackup(){
    touch $LOCK_FILE
    chattr +i $LOCK_FILE
    local rc=0
    PREV_BACKUP_DIR=$(sed '/^$/d' ${INC_BASE_LIST} | tail -1 | awk -F '|' '{print $2}')
    ${XTRABACKUP_PATH} \
    --defaults-file=${MYSQL_CNF} \
    --user=${MYSQL_USERNAME} \
    --password=${MYSQL_PASSWORD} \
    --host=${MYSQL_HOSTNAME} \
    --compress \
    --compress-threads=${THREAD} \
    --no-timestamp --incremental ${CURRENT_BACKUP_PATH} \
    --incremental-basedir=${PREV_BACKUP_DIR} > ${CURRENT_BACKUP_PATH}_inc.log 2>&1
    grep ".*\ completed\ OK\!" ${CURRENT_BACKUP_PATH}_inc.log > /dev/null 2>&1
    if [ $? -ne 0 ];then
        rc=1
        [[ -d ${CURRENT_BACKUP_PATH} && $(pwd) != "/" ]] && rm -rf ${CURRENT_BACKUP_PATH}
    else
        echo "${PREV_BACKUP_DIR}|${CURRENT_BACKUP_PATH}|inc" >> ${INC_BASE_LIST}
        [[ -d ${CURRENT_BACKUP_PATH} && $(pwd) != "/" ]] && chattr +i ${CURRENT_BACKUP_PATH} || rc=1
    fi
    chattr -i ${LOCK_FILE}
    rm -f $LOCK_FILE
    chattr +a ${INC_BASE_LIST}
    return $rc
}
 
## 全量備份
if [ "$1" == "full" ];then
    FullBackup
fi
 
## 增量備份
if [ "$1" == "inc" ];then
    ## 若全量備份不存在,則執行全量備份
    if [[ ! -f ${INC_BASE_LIST} || $(sed '/^$/d' ${INC_BASE_LIST} | wc -l) -eq 0 ]];then
        FullBackup
    else
        IncBackup
    fi
fi
 
## 刪除22天前的備份
if [[ -d ${BACKUP_BASE_DIR} && $(pwd) != "/" ]];then
    find ${BACKUP_BASE_DIR} -name "$(date -d '22 days ago' +'%F')_*" | xargs chattr -i
    find ${BACKUP_BASE_DIR} -name "$(date -d '22 days ago' +'%F')_*" | xargs rm -rf
fi

#可能需要修改backup.sh中的如下參數
BACKUP_BASE_DIR="/data/backup/xtrabackup"
XTRABACKUP_PATH="/usr/bin/innobackupex"
 
MYSQL_CNF="/etc/my.cnf"
MYSQL_HOSTNAME=127.0.0.1
MYSQL_USERNAME=root
MYSQL_PASSWORD=""
#給腳本添加執行權限
chmod 755 /root/42/script/backup.sh
#执行一次全量备份
/root/42/script/backup.sh full
#如果沒有錯誤信息,就可以看到BACKUP_BASE_DIR下生成了備份文件
#檢查下cron是否啟動
service crond status
#如果未啟動則將cron設置為開機啟動並手動啟動下
chkconfig crond on
service crond start
#添加定時任務
crontab -e
#在底部新增內容
## 每周六凌晨3:30一次全量备份
## 每周二、四、日的凌晨3:30点执行增量备份
30 3 * * 6 /root/42/script/backup.sh full
30 3 * * 2,4,7 /root/42/script/backup.sh inc

本文更新於 2017/09/25。

分類
网站

黑屏

我的這塊戴爾S2340Mc屏,黑色時完全就是一面鏡子!為了當鏡子用,我需要一塊黑色。另外div中height設1000%是不行,參考height: 100% not working

浮動無邊黑屏

#!/usr/bin/python3
# -*- coding: utf8 -*-

#dnf install python3-matplotlib
#pip install matplotlib,fire

#指定起始坐標xy、寬度、高度和顏色,來畫一個填充好的矩形
#為了遮擋盜版電影頂部和底部的賭城廣告

import fire,matplotlib

def drawRectangle(x='0',y='0',width='400',length='400',color='black'):
    #"640x400+0+200"
    conf = str(width) + 'x' + str(length) + '+' + str(x) + '+' + str(y)
    # make sure Tk backend is used
    matplotlib.use("TkAgg")  
    import matplotlib.pyplot as plt
    # turn navigation toolbar off
    plt.rcParams['toolbar'] = 'None'
    plt.rcParams['figure.facecolor'] = color
    # create a figure and subplot
    fig, ax = plt.subplots(figsize=(2,2))
    #remove margins
    fig.subplots_adjust(0,0,1,1)
    # turn axes off
    ax.axis("off")
    # show image
    # im = plt.imread("black.png")
    # ax.imshow(im)
    
    # remove window frame
    fig.canvas.manager.window.overrideredirect(1)
    plt.get_current_fig_manager().window.wm_geometry(conf)
    plt.show()
    
#drawRectangle('10','980')

if __name__ == '__main__':
    fire.Fire(drawRectangle)
    
#默認在屏幕左上角生成一個400*400的黑屏
python drawRectangle.py
#在左下角(0,980)生成一個128*72的紅屏
python drawRectangle.py 0 980 128 72 red

本文更新於 2018/07/23。

分類
程序

Flask簡易搭建

最近用python寫了個小服務,既然都用python寫了,不如順便用python的服務器來運行,簡單搜索後決定用Flask+uwsgi+nginx來實現。virtualenv的安裝就不多說了。

#新建一個python3虛擬環境emailApp
mkdir pythons
cd pythons
virtualenv --python=/usr/local/bin/python3.5 emailApp
source emailApp/bin/activate
#安裝uwsgi和Flask
pip install uwsgi Flask
cd emailApp
#新建emailApp1.py
#!/root/42/pythons/emailApp/bin/python
# -*- coding: utf8 -*-

from flask import Flask,request
import json

app = Flask(__name__)

def getTS():
    TS={}

    nowTS=int(time.time())
    TS['当前时间戳']=str(nowTS)
    localTimeString=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(nowTS)))
    TS['服務器時間']=str(localTimeString)
    gmtTimeString=time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(nowTS)))
    TS['GMT時間']=str(gmtTimeString)
    localTSToday=int(time.mktime(time.strptime(localTimeString[:10], '%Y-%m-%d')))
    TS['服務器今天時間戳']=str(localTSToday)
    print('服務器今天時間戳'+str(localTSToday))
    TS['GMT今天時間戳']=str(localTSToday+time.timezone)

    return TS

@app.route('/')
def hello_world():
    return 'Good luck!'

@app.route('/taskCms/service/getTS')
def checkTS():
    TS = getTS()


    return json.dump(TS)
            
if __name__ == '__main__':
#     app.debug = True
#     app.run(host='0.0.0.0',port=8080)
    app.run()
#此時執行
python emailApp1.py
#即可在本地http://127.0.0.1:5000/訪問到服務了。
#Ctrl+C關閉測試,新建nginx站點配置文件emailApp.conf
#nginx站點配置通常在/etc/nginx/conf.d
server {
        listen 8042;
        server_name 127.0.0.1;
        charset utf-8;

        location /  { try_files $uri @yourapplication; }
        location @yourapplication {
                include uwsgi_params;
                uwsgi_pass 127.0.0.1:3031;
        }
}
#測試nginx配置文件是否有誤
nginx -t
#重新加載nginx
nginx -s reload
#此時訪問你的ip加端口號8042,出現502 Bad Gateway則證明nginx已配置好
#若出現訪問超時則可能是有防火牆阻擋
#接下來在項目目錄下新建config.ini作為uwsgi的配置文件
[uwsgi]
socket = 127.0.0.1:3031
chdir = /root/42/pythons/emailApp
master = true
binary-path = /root/42/pythons/emailApp/bin/uwsgi
virtualenv = /root/42/pythons/emailApp
module = emailApp1:app
processes = 2
threads = 4
#使用uwsgi運行Flask程序
/root/42/pythons/emailApp/bin/uwsgi --ini /root/42/pythons/emailApp/config.ini
#如果遇到uwsgi: error while loading shared libraries: libpcre.so.1可嘗試
ln -s /usr/local/lib/libpcre.so.1 /lib64
#正常的話此時應該能通過8042訪問到服務
#開機啟動我使用的centos6自帶的Upstart
nano /etc/init/uwsgi.conf
# simple uWSGI script

description "uwsgi tiny instance"
start on runlevel [2345]
stop on runlevel [06]

respawn

exec /root/42/pythons/emailApp/bin/uwsgi --ini /root/42/pythons/emailApp/config.ini

最後可以通過screen執行uwsgi,然後退出服務器。這樣就完成了一個簡單Flask項目的搭建。Flask就是簡單快速。

如果是通過Upstart自動啟動的,可以通過initctl reload uwsgi和initctl restart uwsgi來重啟uwsgi。


Connection reset by peer鏈接被中斷

過了幾天發現接口不穩定,有時能正常返回數據,有時出現Connection reset by peer鏈接被中斷。從firebug里看發現數據返回有時是先返回個0,就是什麼也沒有然後真是數據才回來,這是瀏覽器已經報錯了。此時可嘗試在uwsgi配置中增加buffer-size=65535和post-buffering = 1。以及在nginx的conf中設置

http{
    ...
    keepalive_timeout  0;

    uwsgi_read_timeout 86400;
    uwsgi_send_timeout 86400;
    ....

}

本文更新於 2017/03/09。

分類
程序

Ubuntu16給python3.5安裝OpenCV3.2

過程略繁瑣,參考了Install OpenCV 3.0 and Python 3.4+ on Ubuntu。安裝完成可在python中import cv2.

#安裝依賴及工具
sudo apt-get install build-essential cmake git pkg-config
sudo apt-get install libjpeg8-dev libtiff4-dev libjasper-dev libpng12-dev
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
sudo apt-get install libgtk2.0-dev
sudo apt-get install libatlas-base-dev gfortran
sudo apt-get install python3.5-dev

由於我已經有python3.5的virtualenv了,所以這里就不再說了,可以参考pip3为python3安装模块

#啓動python3.5的環境
source ~/pythons/p35/bin/activate
#安装numpy
pip install numpy -i https://pypi.douban.com/simple/
#下載並解壓OpenCV,github我克隆不下拉
cd ~
wget -O opencv.zip https://github.com/Itseez/opencv/archive/3.2.0.zip
unzip opencv.zip
wget -O opencv_contrib.zip https://github.com/Itseez/opencv_contrib/archive/3.2.0.zip
unzip opencv_contrib.zip
cd ~/opencv-3.2.0
mkdir build
cd build
#cmake中間如有終端,可參考錯誤提示直接從web下載相關文件放於提示位置
cmake -D CMAKE_BUILD_TYPE=RELEASE \
    -D CMAKE_INSTALL_PREFIX=/usr/local \
    -D INSTALL_PYTHON_EXAMPLES=ON \
    -D INSTALL_C_EXAMPLES=OFF \
    -D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib-3.2.0/modules \
    -D PYTHON_EXECUTABLE=~/pythons/p35/bin/python \
    -D BUILD_EXAMPLES=ON ..
#成功執行後要留意python3的環境是否正確應有類似如下字樣
--   Python 3:
--     Interpreter:                 /home/42/pythons/p35/bin/python3 (ver 3.5.2)
--     Libraries:                   /usr/lib/x86_64-linux-gnu/libpython3.5m.so (ver 3.5.2)
--     numpy:                       /home/42/pythons/p35/lib/python3.5/site-packages/numpy/core/include (ver 1.12.0)
--     packages path:               lib/python3.5/site-packages
-- 
--   Python (for build):            /home/42/pythons/p35/bin/python3
#然後就可以編譯了
make -j$(nproc)
#編譯完成後執行安裝
sudo make install
sudo ldconfig
#查看是否安裝成功
ls -l /usr/local/lib/python3.5/site-packages/ | grep cv2
#成功的話應該會有文件出現類似
-rw-r--r-- 1 root staff 3550256 2月  17 20:36 cv2.cpython-35m-x86_64-linux-gnu.so
#把cv2關聯到python環境裏
cd ~/pythons/p35/lib/python3.5/site-packages/
ln -s /usr/local/lib/python3.5/site-packages/cv2.cpython-35m-x86_64-linux-gnu.so cv2.so
#查看是否可用
python
>>> import cv2
>>> cv2.__version__
'3.2.0'
分類
Linux

Linux硬盤滿

如果重啟後無法進入桌面環境,很可能是硬盤滿了,此時按Ctrl+Alt+F2進入命令行模式。

#查看磁盤空間剩餘情況
df -hl
#如果確實是磁盤可用空間不足
#則查看是那個文件夾里有大文件,一般都是/tmp
cd /tmp
#以文件夾大小排序,顯示最大的15個
du -hsx * | sort -rh | head -15

釋放出200M空間就差不多可以進桌面環境了。

在頻繁使用selenium調用火狐的時候,/tmp中會出現打量類似tmpzujczqpd的文件夾,可以使用下面代碼進行刪除。

import glob,shutil
def rmFirefoxTmpFile():
    usage = shutil.disk_usage('/tmp')
    #如果磁盤可用空間小於1G則執行刪除
    if usage.free<1024*1024*1024*1:
        #火狐產生的文件夾大概長這樣
        files = glob.glob('/tmp/tmp????????')
    
        for f in files:
            #刪除最後修改時間10個小時以前的文件夾
            if time.time() - os.path.getmtime(f)>10*60*60 :
                shutil.rmtree(f,True)
            

Fedora即使硬盤滿了,也不會無法進入桌面環境,但是桌面和軟件會出現異樣。首先是一些桌面控件比如網速計恢復了默認設置,其次會發現火狐的書籤都不見了,當然也不能在文件管理器中新建文件。一旦出現上述情況,不要去修改這些出了問題的東西,而是應該去釋放硬盤空間並重啟,這樣書籤和控件配置多半都能找回來。但如果修改了,就有很大可能丟失的風險。當然了,如果有定期備份那是最安全的了。

本文更新於 2017/09/21。

分類
程序

matplotlib安裝使用

matplotlib是知名的繪圖庫,當我們需要製作圖表時就要使用它了。

#安裝matplotlib
pip install matplotlib
#使用matplotlib繪製一條直線並顯示
import matplotlib.pyplot as p
p.plot(range(20),range(20))
p.show()

如果matplotlib沒有顯示出圖像,而只顯示了[],很有可能是~/.matplotlib/matplotlibrc文件中的backend值設置不當,可嘗試修改為TkAgg或template。參考:matplotlib does not show my drawings although I call pyplot.show()。我用了virtualenv,matplotlibrc文件位於pythons/p3/lib/python3.5/site-packages/matplotlib/mpl-data/matplotlibrc。