Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 久久91精品国产一区二区,区自拍亚洲综合图区,99精品视频在线观看re

          整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          Zabbix3.x安裝圖解教程

          Zabbix3.x安裝圖解教程

          備知識(shí):

          Zabbix3.x比較之前的2.0界面有了很大的變化,但是安裝部署過(guò)程與2.x基本完全一樣。

          1、Zabbix2.x安裝圖解教程

          http://www.osyunwei.com/archives/7984.html

          2、CentOS 7.0編譯安裝Nginx1.6.0+MySQL5.6.19+PHP5.5.14

          http://www.osyunwei.com/archives/7891.html

          3、zabbix軟件包下載

          zabbix-3.0.1.tar.gz

          http://heanet.dl.sourceforge.net/project/zabbix/ZABBIX%20Latest%20Stable/3.0.1/zabbix-3.0.1.tar.gz

          上傳zabbix-3.0.1.tar.gz到服務(wù)器/usr/local/src目錄下面

          安裝部署:

          請(qǐng)參考Zabbix2.x安裝圖解教程

          一、創(chuàng)建、導(dǎo)入zabbix數(shù)據(jù)庫(kù)

          cd /usr/local/src #進(jìn)入軟件包下載目錄

          tar zabbix-3.0.1.tar.gz #解壓

          cd /usr/local/src/zabbix-3.0.1/database/mysql #進(jìn)入mysql數(shù)據(jù)庫(kù)創(chuàng)建腳本目錄

          ls #列出文件,可以看到有schema.sql、images.sql、data.sql這三個(gè)文件

          mysql -u root -p #輸入密碼,進(jìn)入MySQL控制臺(tái)

          create database zabbix character set utf8; #創(chuàng)建數(shù)據(jù)庫(kù)zabbix,并且數(shù)據(jù)庫(kù)編碼使用utf8

          insert into mysql.user(Host,User,Password) values('localhost','zabbix',password('123456')); #新建賬戶zabbix,密碼123456

          flush privileges; #刷新系統(tǒng)授權(quán)表

          grant all on zabbix.* to 'zabbix'@'localhost' identified by '123456' with grant option; #允許賬戶zabbix能從本機(jī)連接到數(shù)據(jù)庫(kù)zabbix

          flush privileges; #再次刷新系統(tǒng)授權(quán)表

          use zabbix #進(jìn)入數(shù)據(jù)庫(kù)

          source /usr/local/src/zabbix-3.0.1/database/mysql/schema.sql #導(dǎo)入腳本文件到zabbix數(shù)據(jù)庫(kù)

          source /usr/local/src/zabbix-3.0.1/database/mysql/images.sql #導(dǎo)入腳本文件到zabbix數(shù)據(jù)庫(kù)

          source /usr/local/src/zabbix-3.0.1/database/mysql/data.sql #導(dǎo)入腳本文件到zabbix數(shù)據(jù)庫(kù)

          注意:請(qǐng)按照以上順序進(jìn)行導(dǎo)入,否則會(huì)出錯(cuò)。

          exit #退出

          或者這樣導(dǎo)入

          mysql -uzabbix -p123456 -hlocalhost zabbix < /usr/local/src/zabbix-3.0.1/database/mysql/schema.sql

          mysql -uzabbix -p123456 -hlocalhost zabbix < /usr/local/src/zabbix-3.0.1/database/mysql/images.sql

          mysql -uzabbix -p123456 -hlocalhost zabbix < /usr/local/src/zabbix-3.0.1/database/mysql/data.sql

          cd /usr/lib64/mysql #32位系統(tǒng)為/usr/lib/mysql,注意系統(tǒng)版本同,文件版本可能不一樣,這里是16.0.0

          ln -s libmysqlclient.so.16.0.0 libmysqlclient.so #添加軟連接

          ln -s libmysqlclient_r.so.16.0.0 libmysqlclient_r.so #添加軟連接

          二、安裝zabbix

          1、添加用戶:

          groupadd zabbix #創(chuàng)建用戶組zabbix

          useradd zabbix -g zabbix -s /bin/false #創(chuàng)建用戶zabbix,并且把用戶zabbix加入到用戶組zabbix中

          2、安裝依賴包 #CentOS使用yum命令安裝

          yum install net-snmp-devel curl curl-devel mysql-devel

          備注:以上軟件包如果在安裝Web環(huán)境LAMP或者LNMP時(shí)已經(jīng)安裝過(guò),此步驟可忽略

          3、安裝zabbix

          ln -s /usr/local/lib/libiconv.so.2 /usr/lib/libiconv.so.2 #添加軟連接

          /sbin/ldconfig #使配置立即生效

          cd /usr/local/src/zabbix-3.0.1 #進(jìn)入安裝目錄

          ./configure --prefix=/usr/local/zabbix --enable-server --enable-agent --with-net-snmp --with-libcurl --enable-proxy --with-mysql=/usr/bin/mysql_config #配置

          make #編譯

          make install #安裝

          ln -s /usr/local/zabbix/sbin/* /usr/local/sbin/ #添加系統(tǒng)軟連接

          ln -s /usr/local/zabbix/bin/* /usr/local/bin/ #添加系統(tǒng)軟連接

          說(shuō)明:find / -name mysql_config 查找位置,如果沒(méi)有mysql_config,需要安裝yum install mysql-devel

          4、添加zabbix服務(wù)對(duì)應(yīng)的端口

          vi /etc/services #編輯,在最后添加以下代碼

          # Zabbix

          zabbix-agent 10050/tcp # Zabbix Agent

          zabbix-agent 10050/udp # Zabbix Agent

          zabbix-trapper 10051/tcp # Zabbix Trapper

          zabbix-trapper 10051/udp # Zabbix Trapper

          :wq! #保存退出

          5、修改zabbix配置文件

          cd /usr/local/zabbix/etc

          vi /usr/local/zabbix/etc/zabbix_server.conf

          DBName=zabbix #數(shù)據(jù)庫(kù)名稱

          DBUser=zabbix #數(shù)據(jù)庫(kù)用戶名

          DBPassword=123456 #數(shù)據(jù)庫(kù)密碼

          ListenIP=localhost #數(shù)據(jù)庫(kù)ip地址

          AlertScriptsPath=/usr/local/zabbix/share/zabbix/alertscripts #zabbix運(yùn)行腳本存放目錄

          :wq! #保存退出

          vi /usr/local/zabbix/etc/zabbix_agentd.conf

          Include=/usr/local/zabbix/etc/zabbix_agentd.conf.d/

          UnsafeUserParameters=1 #啟用自定義key

          :wq! #保存退出

          6、添加開(kāi)機(jī)啟動(dòng)腳本

          cp /usr/local/src/zabbix-3.0.1/misc/init.d/fedora/core/zabbix_server /etc/rc.d/init.d/zabbix_server #服務(wù)端

          cp /usr/local/src/zabbix-3.0.1/misc/init.d/fedora/core/zabbix_agentd /etc/rc.d/init.d/zabbix_agentd #客戶端

          chmod +x /etc/rc.d/init.d/zabbix_server #添加腳本執(zhí)行權(quán)限

          chmod +x /etc/rc.d/init.d/zabbix_agentd #添加腳本執(zhí)行權(quán)限

          chkconfig zabbix_server on #添加開(kāi)機(jī)啟動(dòng)

          chkconfig zabbix_agentd on #添加開(kāi)機(jī)啟動(dòng)

          7、修改zabbix開(kāi)機(jī)啟動(dòng)腳本中的zabbix安裝目錄

          vi /etc/rc.d/init.d/zabbix_server #編輯服務(wù)端配置文件

          BASEDIR=/usr/local/zabbix/ #zabbix安裝目錄

          :wq! #保存退出

          vi /etc/rc.d/init.d/zabbix_agentd #編輯客戶端配置文件

          BASEDIR=/usr/local/zabbix/ #zabbix安裝目錄

          :wq! #保存退出

          三、配置web站點(diǎn)

          cd /usr/local/src/zabbix-3.0.1

          cp -r /usr/local/src/zabbix-3.0.1/frontends/php /usr/local/nginx/html/zabbix

          chown www.www -R /usr/local/nginx/html/zabbix

          備注:/usr/local/nginx/html為Nginx默認(rèn)站點(diǎn)目錄 www為Nginx運(yùn)行賬戶

          service zabbix_server start #啟動(dòng)zabbix服務(wù)端

          service zabbix_agentd start #啟動(dòng)zabbix客戶端

          四、修改php配置文件參數(shù)

          1、vi /etc/php.ini #編輯修改

          post_max_size=16M

          max_execution_time=300

          max_input_time=300

          :wq! #保存退出

          2、vi /usr/local/php/etc/php-fpm.conf #編輯修改

          request_terminate_timeout=300

          :wq! #保存退出

          service php-fpm reload #重啟php-fpm

          五、安裝web

          在瀏覽器中打開(kāi):

          下面是部分安裝截圖

          Next step

          系統(tǒng)運(yùn)維 www.osyunwei.com 溫馨提醒:qihang01原創(chuàng)內(nèi)容?版權(quán)所有,轉(zhuǎn)載請(qǐng)注明出處及原文鏈接

          檢查系統(tǒng)環(huán)境設(shè)置,必須全部都為ok,才能繼續(xù)

          Next step

          配置MySQL數(shù)據(jù)庫(kù)信息

          Database:MySQL

          Database host:localhost

          Database port:3306

          Database name:zabbix

          User:zabbix

          Password:123456

          Next step

          Next step

          Next step

          Finish 安裝完成

          賬號(hào):admin

          密碼:zabbix

          Sign in 登錄

          如下圖所示

          修改web界面為中文

          1、修改系統(tǒng)配置文件,讓web頁(yè)面支持簡(jiǎn)體中文顯示

          vi /usr/local/nginx/html/zabbix/include/locales.inc.php #編輯修改

          'zh_CN'=> array('name'=> _('Chinese (zh_CN)'), 'display'=> false),

          修改為

          'zh_CN'=> array('name'=> _('Chinese (zh_CN)'), 'display'=> true),

          :wq! #保存退出

          2、替換監(jiān)控圖像上系統(tǒng)默認(rèn)的字體 #默認(rèn)字體不支持中文,如果不替換,圖像上會(huì)顯示亂碼

          在Windows系統(tǒng)中的C:\Windows\Fonts目錄中復(fù)制出一個(gè)中文字體文件,例如msyh.ttf

          把字體文件msyh.ttf上傳到zabbix站點(diǎn)根目錄下fonts文件夾中

          例如:/usr/local/nginx/html/zabbix/fonts

          備份默認(rèn)的字體文件:DejaVusSans.ttf-bak

          修改msyh.ttf名稱為DejaVusSans.ttf

          最后,修改配置信息,把默認(rèn)語(yǔ)言修改為中文

          Language:Chinese(zh_CN) #簡(jiǎn)體中文

          至此,Zabbix3.x安裝圖解教程完成。

          信公眾號(hào):思快奇

          ?

          前言

          有人說(shuō)人生在世要“與時(shí)俱進(jìn)”,還有人說(shuō)”識(shí)時(shí)務(wù)者為俊杰”。然而作為金融IT從業(yè)者,卻發(fā)現(xiàn)實(shí)際并不是這樣。

          我們都知道金融系統(tǒng)瞬息萬(wàn)變,稍微有點(diǎn)風(fēng)吹草動(dòng)就會(huì)反映在市場(chǎng)上,這些通過(guò)大盤的漲跌可見(jiàn)一斑,但是后面保障金融數(shù)據(jù)穩(wěn)定呈現(xiàn)的金融信息系統(tǒng)卻猶如大山一般,任你外面互聯(lián)網(wǎng)技術(shù)如何更新?lián)Q代、風(fēng)云變幻,它卻巋然不動(dòng),當(dāng)然這里面的原因有很多,最主要的還是求“穩(wěn)”。比如銀行、券商和基金公司,里面的信息系統(tǒng)普遍較老舊,甚至充斥著大量的Windows服務(wù)器。

          近年來(lái)金融公司的互聯(lián)網(wǎng)轉(zhuǎn)型也如火如荼的進(jìn)行著,各種創(chuàng)新業(yè)務(wù)層出不窮,而這也依賴新型的架構(gòu)支撐。業(yè)務(wù)的激增帶來(lái)的是海量的數(shù)據(jù)和服務(wù),以及服務(wù)器資源的擴(kuò)容等,其中“自動(dòng)化”就顯得尤為重要。

          本著新技術(shù)的調(diào)研,以及實(shí)現(xiàn)自動(dòng)化的目標(biāo),我們引入了docker容器來(lái)管理應(yīng)用,并結(jié)合zabbix監(jiān)控部署嘗試容器化,遂成此文。

          為什么要容器化?

          很多高大上的金融公司,大部分情況下一個(gè)系統(tǒng)通常從商務(wù)立項(xiàng)到開(kāi)發(fā)實(shí)施到運(yùn)維上線僅由一個(gè)或者幾個(gè)人來(lái)負(fù)責(zé),從而形成的大大小小系統(tǒng)生態(tài)。不僅對(duì)技術(shù)人員要求較高,而且自動(dòng)化測(cè)試、自動(dòng)化運(yùn)維程度低,系統(tǒng)出現(xiàn)異常時(shí)定位問(wèn)題慢耗時(shí)久。

          通常一個(gè)服務(wù)上線是一臺(tái)PC一套應(yīng)用環(huán)境,不易復(fù)制,搭建環(huán)境麻煩。而且資源利用率低。即使利用虛擬化,后期也會(huì)由OS消耗大量的計(jì)算、存儲(chǔ)資源和物理機(jī)的運(yùn)維成本相當(dāng)。并且這種部署方式擴(kuò)容慢,遇到突發(fā)流量,疲于奔命,系統(tǒng)遷移慢且繁瑣。我們之前有遇到系統(tǒng)是window服務(wù)器的,需要擴(kuò)容20臺(tái),一臺(tái)臺(tái)系統(tǒng)通過(guò)離線電話激活,可想而知的痛苦。

          而實(shí)現(xiàn)容器化,可以做到應(yīng)用隔離,某個(gè)服務(wù)消耗資源不會(huì)占用其他應(yīng)用資源。可移植支持多種云部署公有云,私有云,混合云,多重云;可擴(kuò)展: 模塊化,插件化,可掛載,可組合。在自動(dòng)化方面表現(xiàn)尤為突出,利用dockerswarm,mesos,k8s等跨服務(wù)器的編排工具可以實(shí)現(xiàn)自動(dòng)部署,自動(dòng)重啟,自動(dòng)復(fù)制,自動(dòng)伸縮擴(kuò)展。其中docker和虛擬機(jī)對(duì)比如下:

          企業(yè)級(jí)應(yīng)用容器化,一般怎么做?

          1、部署docker應(yīng)用,省去依賴環(huán)境的配置。由依賴JVM、weblogic、Nginx等二進(jìn)制來(lái)部署的,過(guò)渡到基于docker鏡像的單主機(jī)模式使用Docker部署。鏡像倉(cāng)庫(kù)服務(wù),本地打包好上傳,服務(wù)器直接拉取即可,和yum安裝軟件一樣簡(jiǎn)單。

          2、用docker compose來(lái)管理各個(gè)應(yīng)用的容器部署,部署docker swarm集群,實(shí)現(xiàn)容器集群管理,由單機(jī)容器到集群容器

          3、通過(guò)K8s這種分布式系統(tǒng)管理平臺(tái),實(shí)現(xiàn)各容器服務(wù)的調(diào)度和管理。K8S的抽象性允許將容器化的應(yīng)用程序部署到集群,而不必專門將其綁定到單個(gè)計(jì)算機(jī)。可以實(shí)現(xiàn)自動(dòng)部署,自動(dòng)重啟,自動(dòng)復(fù)制,自動(dòng)伸縮/擴(kuò)展等智能運(yùn)維操作。

          以上三步,每一步的調(diào)升都是一個(gè)技術(shù)棧的升級(jí),千里之行始于足下,本文實(shí)現(xiàn)基于docker的zabbix監(jiān)控部署,即完成容器化戰(zhàn)略的第一步。

          基于docker的zabbix監(jiān)控部署實(shí)現(xiàn)

          zabbix是一個(gè)基于WEB界面的提供分布式系統(tǒng)監(jiān)視以及網(wǎng)絡(luò)監(jiān)視功能的企業(yè)級(jí)的開(kāi)源解決方案。通過(guò)C/S模式采集數(shù)據(jù)通過(guò)B/S模式在web端展示和配置,通過(guò)SNMP協(xié)議傳輸,而被監(jiān)控對(duì)象只需要支持SNMP協(xié)議或者運(yùn)行Zabbix-agents代理程序即可。

          既然是分布式監(jiān)控系統(tǒng),那么用分布式部署方案才能發(fā)揮其最大功效,官方通過(guò)Zabbix proxies提供有效可用的分布式監(jiān)控。zabbix proxy 可以代替 zabbix server 收集性能和可用性數(shù)據(jù),然后把數(shù)據(jù)匯報(bào)給 zabbix server,并且在一定程度上分擔(dān)了zabbix server 的壓力。架構(gòu)如下:


          假設(shè)我們有五個(gè)生產(chǎn)網(wǎng)段需要監(jiān)控,分別為第三方外聯(lián)區(qū)、DMZ、F5前置、業(yè)務(wù)網(wǎng)段、應(yīng)用網(wǎng)段。那么至少需要部署一臺(tái)zabbix-server、5臺(tái)zabbix-proxy,根據(jù)需要部署zabbix-agent若干。

          部署步驟

          參考zabbix官網(wǎng)配置建議,要監(jiān)控1000+臺(tái)服務(wù)器,以頻率1件每秒的告警頻率,歷史趨勢(shì)數(shù)據(jù)存儲(chǔ)90天,我們需要內(nèi)存4g,硬盤300G,8核CPU即可滿足server要求,而proxy只是數(shù)據(jù)轉(zhuǎn)發(fā),我們硬盤用100G也綽綽有余了,所需資源情況如下:

          一、配置環(huán)境準(zhǔn)備:

          1、因?yàn)樾枰獟煸诒镜啬夸浀絛ocker容器,所以需要關(guān)閉selinux
          #setenforce 0
          永久關(guān)閉
          vi /etc/sysconfig/selinux
          SELINUX=enforcing 改為 SELINUX=disabled
          2、關(guān)閉防火墻或者增加防火墻規(guī)則
          3、添加zabbix用戶和組,做到最小權(quán)限原則
          #groupadd zabbix
          #useradd -g zabbix zabbix
          如果普通用戶下docker不可使用將用戶加入docker組
          #groupadd docker
          #gpasswd -a zabbix docker
          重啟docker生效
          #systemctl restart docker
          4、環(huán)境準(zhǔn)備好后,情況如下:
          [zabbix@N-VM-ZABBIXSRV ~]$ docker images
          REPOSITORY TAG IMAGE ID CREATED SIZE
          [zabbix@N-VM-ZABBIXSRV ~]$ docker -v
          Docker version 1.13.1, build b2f74b2/1.13.1
          

          二、server部署

          由于我們網(wǎng)絡(luò)規(guī)則限制,這里server需要的docker鏡像是離線下載好再導(dǎo)入的,Load三個(gè)鏡像:mysql5.7(數(shù)據(jù)庫(kù))、zabbix-server(服務(wù)接口)、zabbix-web-nginx(前置頁(yè)面)



          直接啟動(dòng)相關(guān)即可

          三、proxy部署

          Proxy服務(wù)器同樣通過(guò)離線方式導(dǎo)入需要的mysql5.7(必須與server分離)、zabbix-proxy的鏡像,并啟動(dòng)服務(wù)即可,不過(guò)為了安全通訊,這里server和proxy我們使用了共享密鑰方式部署(配置注意參見(jiàn)附錄部分)



          通過(guò)簡(jiǎn)單的鏡像導(dǎo)入與啟動(dòng)即可快捷的使用到zabbix監(jiān)控服務(wù)器,只要培訓(xùn)運(yùn)維人員執(zhí)行腳本啟動(dòng)和停止就可以部署發(fā)布了,啟動(dòng)停止時(shí)間秒級(jí),這在使用docker之前是不可以想象的便捷,下圖便是添加了路由器和幾臺(tái)主機(jī)通過(guò)proxy方式接入的配置狀態(tài)。

          總結(jié)

          一種技術(shù)的選擇,就像兩地交通工具的選擇,比如從上海到北京,有汽車、火車、飛機(jī)等等,每一種方式都可以到達(dá),但是耗費(fèi)的經(jīng)歷和時(shí)間是不一樣的,當(dāng)然花費(fèi)的錢財(cái)和人力也不一樣,以前一個(gè)項(xiàng)目的上線部署需要10幾天,用docker容器化后可能只要一兩天。尤其是在擴(kuò)展方面,在server服務(wù)器上用docker可以一個(gè)腳本就再起一個(gè)server服務(wù)只不過(guò)換一個(gè)端口即可,可以用于測(cè)試或者升級(jí)亦或是升級(jí)前的回退備份,但是傳統(tǒng)方式可能需要另準(zhǔn)備一臺(tái)獨(dú)立的服務(wù)器或者虛擬機(jī)了。當(dāng)然要面實(shí)現(xiàn)信息系統(tǒng)的容器化和自動(dòng)化還有更多的事情等著我們?nèi)ヌ魬?zhàn),路漫漫其修遠(yuǎn)兮,吾將上下而求索,我們已經(jīng)邁出了這一步


          附錄1 中文亂碼問(wèn)題

          我們切換了中文語(yǔ)言后會(huì)發(fā)現(xiàn)圖形里面有不可失敗的亂碼,主要是因?yàn)閣eb的字體配置不支持引起,通過(guò)上傳中文字體文件和更改defines.inc.php配置信息即可解決:

          上傳字體文件和更改defines.inc.php配置信息

          # docker cp simkai.ttf zabbix-web-nginx-mysql:/usr/share/zabbix/assets/fonts/.
          # docker cp defines.inc.php zabbix-web-nginx-mysql:/usr/share/zabbix/include/.
          

          中文字體取的是windows自帶的楷體



          重啟服務(wù),中文亂碼問(wèn)題解決

          附錄2 Proxy配置注意事項(xiàng)



          附錄 3 zabbix相關(guān)啟動(dòng)腳本

          ------------------------------server服務(wù)-------------------
          1. 首先,啟動(dòng)空的 MySQL 服務(wù)器實(shí)例。
          # docker run --name mysql-server -t \
           -p 3306:3306 \
           -v /var/zdocker/data:/var/lib/mysql \
           -e MYSQL_DATABASE="zabbix" \
           -e MYSQL_USER="zabbix" \
           -e MYSQL_PASSWORD="zabbix" \
           -e MYSQL_ROOT_PASSWORD="root" \
           -d mysql:5.7 \
           --character-set-server=utf8 --collation-server=utf8_bin
          2. 然后,啟動(dòng) Zabbix server 實(shí)例,并將其關(guān)聯(lián)到已創(chuàng)建的 MySQL server 實(shí)例。
          # docker run --name zabbix-server-mysql -t \
           -e DB_SERVER_HOST="mysql-server" \
           -e MYSQL_DATABASE="zabbix" \
           -e MYSQL_USER="zabbix" \
           -e MYSQL_PASSWORD="zabbix" \
           -e MYSQL_ROOT_PASSWORD="root" \
           --link mysql-server:mysql \
           -p 10051:10051 \
           -d zabbix/zabbix-server-mysql:latest
          Zabbix server 實(shí)例將 10051/TCP 端口(Zabbix trapper)暴露給主機(jī)。
          3. 最后,啟動(dòng) Zabbix Web 界面,并將其關(guān)聯(lián)到已創(chuàng)建的 MySQL server 和 Zabbix server 實(shí)例。
          # docker run --name zabbix-web-nginx-mysql -t \
           -e DB_SERVER_HOST="mysql-server" \
           -e MYSQL_DATABASE="zabbix" \
           -e MYSQL_USER="zabbix" \
           -e MYSQL_PASSWORD="zabbix" \
           -e MYSQL_ROOT_PASSWORD="root" \
           --link mysql-server:mysql \
           --link zabbix-server-mysql:zabbix-server \
           -p 80:80 \
           -d zabbix/zabbix-web-nginx-mysql:latest
          ------------------------proxy服務(wù)---------------------------
          生成psk密鑰并寫入文件zabbix_proxy.psk
          #openssl rand -hex 32
          1. mysql 安裝同server
          2. proxy 安裝
          # docker run --name zabbix-proxy-mysql -t \
           -e DB_SERVER_HOST="mysql-server" \
           -e MYSQL_DATABASE="zabbix" \
           -e MYSQL_USER="zabbix" \
           -e MYSQL_PASSWORD="zabbix" \
           -e MYSQL_ROOT_PASSWORD="root" \
           -e ZBX_SERVER_HOST="HOSTIP" \
           -e ZBX_SERVER_PORT="10051" \
           -e ZBX_TLSCONNECT="psk" \
           -e ZBX_TLSPSKIDENTITY="zbxproxy" \
           -e ZBX_TLSPSKFILE="zabbix_proxy.psk" \
           -e ZBX_HOSTNAME="zbxproxy" \
           -e ZBX_CONFIGFREQUENCY="90" \
           -v /var/zdocker/enc:/var/lib/zabbix/enc \
           --link mysql-server:mysql \
           -p 10051:10051 \
           -d zabbix/zabbix-proxy-mysql:latest
          Zabbix proxy 實(shí)例將 10051/TCP 端口(Zabbix trapper)暴露給主機(jī)。
          

          參考資料:

          1、zabbix官網(wǎng)文檔

          2、docker官網(wǎng)文檔

          3、其他互聯(lián)網(wǎng)相關(guān)檢索資料

          equests 唯一的一個(gè)非轉(zhuǎn)基因的 Python HTTP 庫(kù),人類可以安全享用。

          警告:非專業(yè)使用其他 HTTP 庫(kù)會(huì)導(dǎo)致危險(xiǎn)的副作用,包括:安全缺陷癥、冗余代碼癥、重新發(fā)明輪子癥、啃文檔癥、抑郁、頭疼、甚至死亡。

          可怕吧。所以趕緊用起超級(jí)好用的Request庫(kù)。

          一、什么是Requests

          Requests是用python語(yǔ)言基于urllib編寫的,采用的是Apache2 Licensed開(kāi)源協(xié)議的HTTP庫(kù)。

          Requests 允許你發(fā)送 HTTP/1.1 請(qǐng)求,無(wú)需手工勞動(dòng)。你不需要手動(dòng)為 URL 添加查詢字串,也不需要對(duì) POST 數(shù)據(jù)進(jìn)行表單編碼。Keep-alive 和 HTTP 連接池的功能是 100% 自動(dòng)化的,一切動(dòng)力都來(lái)自于根植在 Requests 內(nèi)部的 urllib3。

          二、Requests 功能特性

          Requests 完全滿足今日 web 的需求。

          • Keep-Alive & 連接池
          • 國(guó)際化域名和 URL
          • 帶持久 Cookie 的會(huì)話
          • 瀏覽器式的 SSL 認(rèn)證
          • 自動(dòng)內(nèi)容解碼
          • 基本/摘要式的身份認(rèn)證
          • 優(yōu)雅的 key/value Cookie
          • 自動(dòng)解壓
          • Unicode 響應(yīng)體
          • HTTP(S) 代理支持
          • 文件分塊上傳
          • 流下載
          • 連接超時(shí)
          • 分塊請(qǐng)求
          • 支持 .netrc

          Requests 支持 Python 2.6—2.7以及3.3—3.7,而且能在 PyPy 下完美運(yùn)行。

          三、快速上手

          1、發(fā)送請(qǐng)求

          1.1 requests里提供個(gè)各種請(qǐng)求方式

          使用 Requests 發(fā)送網(wǎng)絡(luò)請(qǐng)求非常簡(jiǎn)單。

          一開(kāi)始要導(dǎo)入 Requests 模塊:

          import requests
          

          然后,嘗試獲取某個(gè)網(wǎng)頁(yè)。本例子中,我們來(lái)獲取 Github 的公共時(shí)間線:

          r=requests.get('https://github.com/timeline.json')
          

          現(xiàn)在,我們有一個(gè)名為 r 的 Response 對(duì)象。我們可以從這個(gè)對(duì)象中獲取所有我們想要的信息。

          Requests 簡(jiǎn)便的 API 意味著所有 HTTP 請(qǐng)求類型都是顯而易見(jiàn)的。例如,你可以這樣發(fā)送一個(gè) HTTP POST 請(qǐng)求:

          r=requests.post("http://httpbin.org/post")
          

          漂亮,對(duì)吧?那么其他 HTTP 請(qǐng)求類型:PUT,DELETE,HEAD 以及 OPTIONS 又是如何的呢?都是一樣的簡(jiǎn)單:

          r=requests.put("http://httpbin.org/put")
          r=requests.delete("http://httpbin.org/delete")
          r=requests.head("http://httpbin.org/get")
          r=requests.options("http://httpbin.org/get")
          

          都很不錯(cuò)吧,但這也僅是 Requests 的冰山一角呢。

          1.2 總體功能的一個(gè)演示

          import requests
           
          response=requests.get("https://www.baidu.com")
          print(type(response))
          print(response.status_code)
          print(type(response.text))
          print(response.text)
          print(response.cookies)
          print(response.content)
          print(response.content.decode("utf-8"))
          

          我們可以看出response使用起來(lái)確實(shí)非常方便,這里有個(gè)問(wèn)題需要注意一下:

          很多情況下的網(wǎng)站如果直接response.text會(huì)出現(xiàn)亂碼的問(wèn)題,所以這個(gè)使用response.content

          這樣返回的數(shù)據(jù)格式其實(shí)是二進(jìn)制格式,然后通過(guò)decode()轉(zhuǎn)換為utf-8,這樣就解決了通過(guò)response.text直接返回顯示亂碼的問(wèn)題。

          請(qǐng)求發(fā)出后,Requests 會(huì)基于 HTTP 頭部對(duì)響應(yīng)的編碼作出有根據(jù)的推測(cè)。當(dāng)你訪問(wèn) response.text 之時(shí),Requests 會(huì)使用其推測(cè)的文本編碼。你可以找出 Requests 使用了什么編碼,并且能夠使用 response.encoding 屬性來(lái)改變它.如:

          response=requests.get("http://www.baidu.com")
          response.encoding="utf-8"
          print(response.text)
          

          不管是通過(guò)response.content.decode("utf-8)的方式還是通過(guò)response.encoding="utf-8"的方式都可以避免亂碼的問(wèn)題發(fā)生。

          1.3 帶參數(shù)的 get 請(qǐng)求

          import requests
           
          response=requests.get("http://httpbin.org/get?name=zhaofan&age=23")
          print(response.text)
          

          如果我們想要在URL查詢字符串傳遞數(shù)據(jù),通常我們會(huì)通過(guò) httpbin.org/get?key=val 方式傳遞。Requests模塊允許使用params關(guān)鍵字傳遞參數(shù),以一個(gè)字典來(lái)傳遞這些參數(shù),例子如下:

          import requests
          data={
           "name":"zhaofan",
           "age":22
          }
          response=requests.get("http://httpbin.org/get",params=data)
          print(response.url)
          print(response.text)
          

          上述兩種的結(jié)果是相同的,通過(guò)params參數(shù)傳遞一個(gè)字典內(nèi)容,從而直接構(gòu)造url。

          注意:第二種方式通過(guò)字典的方式的時(shí)候,如果字典中的參數(shù)為None則不會(huì)添加到url上。

          1.4 解析 json

          Requests 中也有一個(gè)內(nèi)置的 JSON 解碼器,助你處理 JSON 數(shù)據(jù):

          import requests
          import json
           
          response=requests.get("http://httpbin.org/get")
          print(type(response.text))
          print(response.json())
          print(json.loads(response.text))
          print(type(response.json()))
          

          從結(jié)果可以看出requests里面集成的json其實(shí)就是執(zhí)行了json.loads()方法,兩者的結(jié)果是一樣的。

          如果 JSON 解碼失敗。r.json() 就會(huì)拋出一個(gè)異常。例如,響應(yīng)內(nèi)容是 401 (Unauthorized),嘗試訪問(wèn) r.json() 將會(huì)拋出 ValueError: No JSON object could be decoded 異常。

          需要注意的是,成功調(diào)用 r.json() 并不意味著響應(yīng)的成功。有的服務(wù)器會(huì)在失敗的響應(yīng)中包含一個(gè) JSON 對(duì)象(比如 HTTP 500 的錯(cuò)誤細(xì)節(jié))。這種 JSON 會(huì)被解碼返回。要檢查請(qǐng)求是否成功,請(qǐng)使用 r.raise_for_status() 或者檢查 r.status_code 是否和你的期望相同。

          1.5 添加 headers

          和前面我們將urllib模塊的時(shí)候一樣,我們同樣可以定制headers的信息,如當(dāng)我們直接通過(guò)requests請(qǐng)求知乎網(wǎng)站的時(shí)候,默認(rèn)是無(wú)法訪問(wèn)的。

          import requests
          response=requests.get("https://www.zhihu.com")
          print(response.text)
          

          因?yàn)樵L問(wèn)知乎需要頭部信息,這個(gè)時(shí)候我們?cè)诠雀铻g覽器里輸入chrome://version,就可以看到用戶代理,將用戶代理添加到頭部信息。

          如果你想為請(qǐng)求添加 HTTP 頭部,只要簡(jiǎn)單地傳遞一個(gè) dict 給 headers 參數(shù)就可以了。

          import requests
          headers={
           
           "User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
          }
          response=requests.get("https://www.zhihu.com",headers=headers)
           
          print(response.text)
          

          這樣就可以正常的訪問(wèn)知乎了。

          注意: 定制 header 的優(yōu)先級(jí)低于某些特定的信息源,例如:

          • 如果在 .netrc 中設(shè)置了用戶認(rèn)證信息,使用 headers=設(shè)置的授權(quán)就不會(huì)生效。而如果設(shè)置了 auth=參數(shù),``.netrc`` 的設(shè)置就無(wú)效了。
          • 如果被重定向到別的主機(jī),授權(quán) header 就會(huì)被刪除。
          • 代理授權(quán) header 會(huì)被 URL 中提供的代理身份覆蓋掉。
          • 在我們能判斷內(nèi)容長(zhǎng)度的情況下,header 的 Content-Length 會(huì)被改寫。

          更進(jìn)一步講,Requests 不會(huì)基于定制 header 的具體情況改變自己的行為。只不過(guò)在最后的請(qǐng)求中,所有的 header 信息都會(huì)被傳遞進(jìn)去。

          注意: 所有的 header 值必須是 string、bytestring 或者 unicode。盡管傳遞 unicode header 也是允許的,但不建議這樣做。

          2、傳遞 URL 參數(shù)

          你也許經(jīng)常想為 URL 的查詢字符串(query string)傳遞某種數(shù)據(jù)。如果你是手工構(gòu)建 URL,那么數(shù)據(jù)會(huì)以鍵/值對(duì)的形式置于 URL 中,跟在一個(gè)問(wèn)號(hào)的后面。例如, httpbin.org/get?key=val。 Requests 允許你使用 params 關(guān)鍵字參數(shù),以一個(gè)字符串字典來(lái)提供這些參數(shù)。舉例來(lái)說(shuō),如果你想傳遞 key1=value1 和 key2=value2 到 httpbin.org/get ,那么你可以使用如下代碼:

          payload={'key1': 'value1', 'key2': 'value2'}
          r=requests.get("http://httpbin.org/get", params=payload)
          

          通過(guò)打印輸出該 URL,你能看到 URL 已被正確編碼:

          print(r.url)
          http://httpbin.org/get?key2=value2&key1=value1
          

          注意字典里值為 None 的鍵都不會(huì)被添加到 URL 的查詢字符串里。

          你還可以將一個(gè)列表作為值傳入:

          payload={'key1': 'value1', 'key2': ['value2', 'value3']}
           
          r=requests.get('http://httpbin.org/get', params=payload)
          print(r.url)
          http://httpbin.org/get?key1=value1&key2=value2&key2=value3
          

          3、響應(yīng)內(nèi)容

          我們能讀取服務(wù)器響應(yīng)的內(nèi)容。再次以 GitHub 時(shí)間線為例:

          import requests
          r=requests.get('https://github.com/timeline.json')
          r.text
          u'[{"repository":{"open_issues":0,"url":"https://github.com/...
          

          Requests 會(huì)自動(dòng)解碼來(lái)自服務(wù)器的內(nèi)容。大多數(shù) unicode 字符集都能被無(wú)縫地解碼。

          請(qǐng)求發(fā)出后,Requests 會(huì)基于 HTTP 頭部對(duì)響應(yīng)的編碼作出有根據(jù)的推測(cè)。當(dāng)你訪問(wèn) r.text 之時(shí),Requests 會(huì)使用其推測(cè)的文本編碼。你可以找出 Requests 使用了什么編碼,并且能夠使用 r.encoding 屬性來(lái)改變它:

          r.encoding
          r.encoding='ISO-8859-1'
          

          如果你改變了編碼,每當(dāng)你訪問(wèn) r.text ,Request 都將會(huì)使用 r.encoding 的新值。你可能希望在使用特殊邏輯計(jì)算出文本的編碼的情況下來(lái)修改編碼。比如 HTTP 和 XML 自身可以指定編碼。這樣的話,你應(yīng)該使用 r.content 來(lái)找到編碼,然后設(shè)置 r.encoding 為相應(yīng)的編碼。這樣就能使用正確的編碼解析 r.text 了。

          在你需要的情況下,Requests 也可以使用定制的編碼。如果你創(chuàng)建了自己的編碼,并使用 codecs 模塊進(jìn)行注冊(cè),你就可以輕松地使用這個(gè)解碼器名稱作為 r.encoding 的值, 然后由 Requests 來(lái)為你處理編碼。

          4、二進(jìn)制響應(yīng)內(nèi)容

          你也能以字節(jié)的方式訪問(wèn)請(qǐng)求響應(yīng)體,對(duì)于非文本請(qǐng)求:

           r.content
          b'[{"repository":{"open_issues":0,"url":"https://github.com/...
          

          Requests 會(huì)自動(dòng)為你解碼 gzip 和 deflate 傳輸編碼的響應(yīng)數(shù)據(jù)。

          例如,以請(qǐng)求返回的二進(jìn)制數(shù)據(jù)創(chuàng)建一張圖片,你可以使用如下代碼:

          from PIL import Image
          from io import BytesIO
           
          i=Image.open(BytesIO(r.content))
          

          5、原始響應(yīng)內(nèi)容

          在罕見(jiàn)的情況下,你可能想獲取來(lái)自服務(wù)器的原始套接字響應(yīng),那么你可以訪問(wèn) r.raw。 如果你確實(shí)想這么干,那請(qǐng)你確保在初始請(qǐng)求中設(shè)置了 stream=True。具體你可以這么做:

          r=requests.get('https://github.com/timeline.json', stream=True)
          r.raw
          <requests.packages.urllib3.response.HTTPResponse object at 0x101194810>
          r.raw.read(10)
          '\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'
          

          但一般情況下,你應(yīng)該以下面的模式將文本流保存到文件:

          with open(filename, 'wb') as fd:
           for chunk in r.iter_content(chunk_size):
           fd.write(chunk)
          

          使用 Response.iter_content 將會(huì)處理大量你直接使用 Response.raw 不得不處理的。 當(dāng)流下載時(shí),上面是優(yōu)先推薦的獲取內(nèi)容方式。 Note that chunk_size can be freely adjusted to a number that may better fit your use cases.

          6、更加復(fù)雜的 POST 請(qǐng)求

          通常,你想要發(fā)送一些編碼為表單形式的數(shù)據(jù)——非常像一個(gè) HTML 表單。要實(shí)現(xiàn)這個(gè),只需簡(jiǎn)單地傳遞一個(gè)字典給 data 參數(shù)。你的數(shù)據(jù)字典在發(fā)出請(qǐng)求時(shí)會(huì)自動(dòng)編碼為表單形式:

          >>> payload={'key1': 'value1', 'key2': 'value2'}
           
          >>> r=requests.post("http://httpbin.org/post", data=payload)
          >>> print(r.text)
          {
           ...
           "form": {
           "key2": "value2",
           "key1": "value1"
           },
           ...
          }
          

          你還可以為 data 參數(shù)傳入一個(gè)元組列表。在表單中多個(gè)元素使用同一 key 的時(shí)候,這種方式尤其有效:

          >>> payload=(('key1', 'value1'), ('key1', 'value2'))
          >>> r=requests.post('http://httpbin.org/post', data=payload)
          >>> print(r.text)
          {
           ...
           "form": {
           "key1": [
           "value1",
           "value2"
           ]
           },
           ...
          }
          

          很多時(shí)候你想要發(fā)送的數(shù)據(jù)并非編碼為表單形式的。如果你傳遞一個(gè) string 而不是一個(gè) dict,那么數(shù)據(jù)會(huì)被直接發(fā)布出去。

          例如,Github API v3 接受編碼為 JSON 的 POST/PATCH 數(shù)據(jù):

          >>> import json
           
          >>> url='https://api.github.com/some/endpoint'
          >>> payload={'some': 'data'}
           
          >>> r=requests.post(url, data=json.dumps(payload))
          

          此處除了可以自行對(duì) dict 進(jìn)行編碼,你還可以使用 json 參數(shù)直接傳遞,然后它就會(huì)被自動(dòng)編碼。這是 2.4.2 版的新加功能:

          >>> url='https://api.github.com/some/endpoint'
          >>> payload={'some': 'data'}
           
          >>> r=requests.post(url, json=payload)
          

          7、POST一個(gè)多部分編碼(Multipart-Encoded)的文件

          Requests 使得上傳多部分編碼文件變得很簡(jiǎn)單:

          >>> url='http://httpbin.org/post'
          >>> files={'file': open('report.xls', 'rb')}
           
          >>> r=requests.post(url, files=files)
          >>> r.text
          {
           ...
           "files": {
           "file": "<censored...binary...data>"
           },
           ...
          }
          

          你可以顯式地設(shè)置文件名,文件類型和請(qǐng)求頭:

          >>> url='http://httpbin.org/post'
          >>> files={'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}
           
          >>> r=requests.post(url, files=files)
          >>> r.text
          {
           ...
           "files": {
           "file": "<censored...binary...data>"
           },
           ...
          }
          

          如果你想,你也可以發(fā)送作為文件來(lái)接收的字符串:

          >>> url='http://httpbin.org/post'
          >>> files={'file': ('report.csv', 'some,data,to,send\nanother,row,to,send\n')}
           
          >>> r=requests.post(url, files=files)
          >>> r.text
          {
           ...
           "files": {
           "file": "some,data,to,send\\nanother,row,to,send\\n"
           },
           ...
          }
          

          如果你發(fā)送一個(gè)非常大的文件作為 multipart/form-data 請(qǐng)求,你可能希望將請(qǐng)求做成數(shù)據(jù)流。默認(rèn)下 requests 不支持, 但有個(gè)第三方包 requests-toolbelt 是支持的。你可以閱讀 toolbelt 文檔 來(lái)了解使用方法。

          警告

          我們強(qiáng)烈建議你用二進(jìn)制模式(binary mode)打開(kāi)文件。這是因?yàn)?Requests 可能會(huì)試圖為你提供 Content-Length header,在它這樣做的時(shí)候,這個(gè)值會(huì)被設(shè)為文件的字節(jié)數(shù)(bytes)。如果用文本模式(text mode)打開(kāi)文件,就可能會(huì)發(fā)生錯(cuò)誤。

          8、響應(yīng)狀態(tài)碼

          我們可以檢測(cè)響應(yīng)狀態(tài)碼:

          >>> r=requests.get('http://httpbin.org/get')
          >>> r.status_code
          200
          

          為方便引用,Requests還附帶了一個(gè)內(nèi)置的狀態(tài)碼查詢對(duì)象:

          >>> r.status_code==requests.codes.ok
          True
          

          如果發(fā)送了一個(gè)錯(cuò)誤請(qǐng)求(一個(gè) 4XX 客戶端錯(cuò)誤,或者 5XX 服務(wù)器錯(cuò)誤響應(yīng)),我們可以通過(guò) Response.raise_for_status() 來(lái)拋出異常:

          >>> bad_r=requests.get('http://httpbin.org/status/404')
          >>> bad_r.status_code
          404
           
          >>> bad_r.raise_for_status()
          Traceback (most recent call last):
           File "requests/models.py", line 832, in raise_for_status
           raise http_error
          requests.exceptions.HTTPError: 404 Client Error
          

          但是,由于我們的例子中 r 的 status_code 是 200 ,當(dāng)我們調(diào)用 raise_for_status() 時(shí),得到的是:

          >>> r.raise_for_status()
          None
          

          9、響應(yīng)頭

          我們可以查看以一個(gè) Python 字典形式展示的服務(wù)器響應(yīng)頭:

          >>> r.headers
          {
           'content-encoding': 'gzip',
           'transfer-encoding': 'chunked',
           'connection': 'close',
           'server': 'nginx/1.0.4',
           'x-runtime': '148ms',
           'etag': '"e1ca502697e5c9317743dc078f67693f"',
           'content-type': 'application/json'
          }
          

          但是這個(gè)字典比較特殊:它是僅為 HTTP 頭部而生的。根據(jù) RFC 2616, HTTP 頭部是大小寫不敏感的。

          因此,我們可以使用任意大寫形式來(lái)訪問(wèn)這些響應(yīng)頭字段:

          >>> r.headers['Content-Type']
          'application/json'
           
          >>> r.headers.get('content-type')
          'application/json'
          

          它還有一個(gè)特殊點(diǎn),那就是服務(wù)器可以多次接受同一 header,每次都使用不同的值。但 Requests 會(huì)將它們合并,這樣它們就可以用一個(gè)映射來(lái)表示出來(lái),參見(jiàn) RFC 7230:

          A recipient MAY combine multiple header fields with the same field name into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field value to the combined field value in order, separated by a comma.

          接收者可以合并多個(gè)相同名稱的 header 欄位,把它們合為一個(gè) "field-name: field-value" 配對(duì),將每個(gè)后續(xù)的欄位值依次追加到合并的欄位值中,用逗號(hào)隔開(kāi)即可,這樣做不會(huì)改變信息的語(yǔ)義。

          10、Cookie

          如果某個(gè)響應(yīng)中包含一些 cookie,你可以快速訪問(wèn)它們:

          >>> url='http://example.com/some/cookie/setting/url'
          >>> r=requests.get(url)
           
          >>> r.cookies['example_cookie_name']
          'example_cookie_value'
          

          要想發(fā)送你的cookies到服務(wù)器,可以使用 cookies 參數(shù):

          >>> url='http://httpbin.org/cookies'
          >>> cookies=dict(cookies_are='working')
           
          >>> r=requests.get(url, cookies=cookies)
          >>> r.text
          '{"cookies": {"cookies_are": "working"}}'
          

          Cookie 的返回對(duì)象為 RequestsCookieJar,它的行為和字典類似,但界面更為完整,適合跨域名跨路徑使用。你還可以把 Cookie Jar 傳到 Requests 中:

          >>> jar=requests.cookies.RequestsCookieJar()
          >>> jar.set('tasty_cookie', 'yum', domain='httpbin.org', path='/cookies')
          >>> jar.set('gross_cookie', 'blech', domain='httpbin.org', path='/elsewhere')
          >>> url='http://httpbin.org/cookies'
          >>> r=requests.get(url, cookies=jar)
          >>> r.text
          '{"cookies": {"tasty_cookie": "yum"}}'
          

          11、重定向與請(qǐng)求歷史

          默認(rèn)情況下,除了 HEAD, Requests 會(huì)自動(dòng)處理所有重定向。

          可以使用響應(yīng)對(duì)象的 history 方法來(lái)追蹤重定向。

          Response.history 是一個(gè) Response 對(duì)象的列表,為了完成請(qǐng)求而創(chuàng)建了這些對(duì)象。這個(gè)對(duì)象列表按照從最老到最近的請(qǐng)求進(jìn)行排序。

          例如,Github 將所有的 HTTP 請(qǐng)求重定向到 HTTPS:

          >>> r=requests.get('http://github.com')
           
          >>> r.url
          'https://github.com/'
           
          >>> r.status_code
          200
           
          >>> r.history
          [<Response [301]>]
          

          如果你使用的是GET、OPTIONS、POST、PUT、PATCH 或者 DELETE,那么你可以通過(guò) allow_redirects 參數(shù)禁用重定向處理:

          >>> r=requests.get('http://github.com', allow_redirects=False)
          >>> r.status_code
          301
          >>> r.history
          []
          

          如果你使用了 HEAD,你也可以啟用重定向:

          >>> r=requests.head('http://github.com', allow_redirects=True)
          >>> r.url
          'https://github.com/'
          >>> r.history
          [<Response [301]>]
          

          12、超時(shí)

          你可以告訴 requests 在經(jīng)過(guò)以 timeout 參數(shù)設(shè)定的秒數(shù)時(shí)間之后停止等待響應(yīng)。基本上所有的生產(chǎn)代碼都應(yīng)該使用這一參數(shù)。如果不使用,你的程序可能會(huì)永遠(yuǎn)失去響應(yīng):

          >>> requests.get('http://github.com', timeout=0.001)
          Traceback (most recent call last):
           File "<stdin>", line 1, in <module>
          requests.exceptions.Timeout: HTTPConnectionPool(host='github.com', port=80): Request timed out. (timeout=0.001)
          

          注意

          timeout 僅對(duì)連接過(guò)程有效,與響應(yīng)體的下載無(wú)關(guān)。 timeout 并不是整個(gè)下載響應(yīng)的時(shí)間限制,而是如果服務(wù)器在 timeout 秒內(nèi)沒(méi)有應(yīng)答,將會(huì)引發(fā)一個(gè)異常(更精確地說(shuō),是在 timeout 秒內(nèi)沒(méi)有從基礎(chǔ)套接字上接收到任何字節(jié)的數(shù)據(jù)時(shí))If no timeout is specified explicitly, requests do not time out.

          13、錯(cuò)誤與異常

          遇到網(wǎng)絡(luò)問(wèn)題(如:DNS 查詢失敗、拒絕連接等)時(shí),Requests 會(huì)拋出一個(gè) ConnectionError 異常。

          如果 HTTP 請(qǐng)求返回了不成功的狀態(tài)碼, Response.raise_for_status() 會(huì)拋出一個(gè) HTTPError 異常。

          若請(qǐng)求超時(shí),則拋出一個(gè) Timeout 異常。

          若請(qǐng)求超過(guò)了設(shè)定的最大重定向次數(shù),則會(huì)拋出一個(gè) TooManyRedirects 異常。

          所有Requests顯式拋出的異常都繼承自 requests.exceptions.RequestException

          四、高級(jí)用法

          1、會(huì)話對(duì)象

          會(huì)話對(duì)象讓你能夠跨請(qǐng)求保持某些參數(shù)。它也會(huì)在同一個(gè) Session 實(shí)例發(fā)出的所有請(qǐng)求之間保持 cookie, 期間使用 urllib3 的 connection pooling 功能。所以如果你向同一主機(jī)發(fā)送多個(gè)請(qǐng)求,底層的 TCP 連接將會(huì)被重用,從而帶來(lái)顯著的性能提升。 (參見(jiàn) HTTP persistent connection).

          會(huì)話對(duì)象具有主要的 Requests API 的所有方法。

          我們來(lái)跨請(qǐng)求保持一些 cookie:

          s=requests.Session()
           
          s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
          r=s.get("http://httpbin.org/cookies")
           
          print(r.text)
          # '{"cookies": {"sessioncookie": "123456789"}}'
          

          會(huì)話也可用來(lái)為請(qǐng)求方法提供缺省數(shù)據(jù)。這是通過(guò)為會(huì)話對(duì)象的屬性提供數(shù)據(jù)來(lái)實(shí)現(xiàn)的:

          s=requests.Session()
          s.auth=('user', 'pass')
          s.headers.update({'x-test': 'true'})
           
          # both 'x-test' and 'x-test2' are sent
          s.get('http://httpbin.org/headers', headers={'x-test2': 'true'})
          

          任何你傳遞給請(qǐng)求方法的字典都會(huì)與已設(shè)置會(huì)話層數(shù)據(jù)合并。方法層的參數(shù)覆蓋會(huì)話的參數(shù)。

          不過(guò)需要注意,就算使用了會(huì)話,方法級(jí)別的參數(shù)也不會(huì)被跨請(qǐng)求保持。下面的例子只會(huì)和第一個(gè)請(qǐng)求發(fā)送 cookie ,而非第二個(gè):

          s=requests.Session()
           
          r=s.get('http://httpbin.org/cookies', cookies={'from-my': 'browser'})
          print(r.text)
          # '{"cookies": {"from-my": "browser"}}'
           
          r=s.get('http://httpbin.org/cookies')
          print(r.text)
          # '{"cookies": {}}'
          

          如果你要手動(dòng)為會(huì)話添加 cookie,就使用 Cookie utility 函數(shù) 來(lái)操縱 Session.cookies。

          會(huì)話還可以用作前后文管理器:

          with requests.Session() as s:
           s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
          

          這樣就能確保 with 區(qū)塊退出后會(huì)話能被關(guān)閉,即使發(fā)生了異常也一樣。

          從字典參數(shù)中移除一個(gè)值:有時(shí)你會(huì)想省略字典參數(shù)中一些會(huì)話層的鍵。要做到這一點(diǎn),你只需簡(jiǎn)單地在方法層參數(shù)中將那個(gè)鍵的值設(shè)置為 None ,那個(gè)鍵就會(huì)被自動(dòng)省略掉。

          包含在一個(gè)會(huì)話中的所有數(shù)據(jù)你都可以直接使用。學(xué)習(xí)更多細(xì)節(jié)請(qǐng)閱讀 會(huì)話 API 文檔。

          2、請(qǐng)求與響應(yīng)對(duì)象

          任何時(shí)候進(jìn)行了類似 requests.get() 的調(diào)用,你都在做兩件主要的事情。其一,你在構(gòu)建一個(gè) Request 對(duì)象, 該對(duì)象將被發(fā)送到某個(gè)服務(wù)器請(qǐng)求或查詢一些資源。其二,一旦 requests 得到一個(gè)從服務(wù)器返回的響應(yīng)就會(huì)產(chǎn)生一個(gè) Response 對(duì)象。該響應(yīng)對(duì)象包含服務(wù)器返回的所有信息,也包含你原來(lái)創(chuàng)建的 Request 對(duì)象。如下是一個(gè)簡(jiǎn)單的請(qǐng)求,從 Wikipedia 的服務(wù)器得到一些非常重要的信息:

          >>> r=requests.get('http://en.wikipedia.org/wiki/Monty_Python')
          

          如果想訪問(wèn)服務(wù)器返回給我們的響應(yīng)頭部信息,可以這樣做:

          >>> r.headers
          {'Content-Length': '74016', 'Content-language': 'en', 'X-Powered-By': 'HHVM/3.18.6-dev', 'X-Cache-Status': 'hit-front', 'Last-Modified': 'Sun, 18 Mar 2018 03:21:10 GMT', 'X-Client-IP': '58.22.60.34', 'Link': '</static/images/project-logos/enwiki.png>;rel=preload;as=image;media=not all and (min-resolution: 1.5dppx),</static/images/project-logos/enwiki-1.5x.png>;rel=preload;as=image;media=(min-resolution: 1.5dppx) and (max-resolution: 1.999999dppx),</static/images/project-logos/enwiki-2x.png>;rel=preload;as=image;media=(min-resolution: 2dppx)', 'Date': 'Mon, 26 Mar 2018 07:59:49 GMT', 'Accept-Ranges': 'bytes', 'X-Varnish': '344560760 788283452, 149384905 105598013, 1070294656 1052310325, 958221504 648703599', 'X-Cache': 'cp1065 hit/9, cp2007 hit/5, cp4032 hit/1, cp4029 hit/40', 'Set-Cookie': 'GeoIP=CN:FJ:Xiamen:24.48:118.08:v4; Path=/; secure; Domain=.wikipedia.org', 'Age': '114692', 'Strict-Transport-Security': 'max-age=106384710; includeSubDomains; preload', 'Server': 'mw1261.eqiad.wmnet', 'Connection': 'keep-alive', 'P3P': 'CP="This is not a P3P policy! See https://en.wikipedia.org/wiki/Special:CentralAutoLogin/P3P for more info."', 'Via': '1.1 varnish (Varnish/5.1), 1.1 varnish (Varnish/5.1), 1.1 varnish (Varnish/5.1), 1.1 varnish (Varnish/5.1)', 'X-Analytics': 'ns=0;page_id=18942;WMF-Last-Access=26-Mar-2018;WMF-Last-Access-Global=26-Mar-2018;https=1', 'X-Content-Type-Options': 'nosniff', 'Content-Encoding': 'gzip', 'Vary': 'Accept-Encoding,Cookie,Authorization', 'X-UA-Compatible': 'IE=Edge', 'Cache-Control': 'private, s-maxage=0, max-age=0, must-revalidate', 'Content-Type': 'text/html; charset=UTF-8', 'Backend-Timing': 'D=117879 t=1521768700105575'}
          

          然而,如果想得到發(fā)送到服務(wù)器的請(qǐng)求的頭部,我們可以簡(jiǎn)單地訪問(wèn)該請(qǐng)求,然后是該請(qǐng)求的頭部:

          >>> r.request.headers
          {'Connection': 'keep-alive', 'Cookie': 'WMF-Last-Access-Global=26-Mar-2018; WMF-Last-Access=26-Mar-2018', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'python-requests/2.18.4'}
          

          3、準(zhǔn)備的請(qǐng)求(Prepared Request)

          當(dāng)你從 API 或者會(huì)話調(diào)用中收到一個(gè) Response 對(duì)象時(shí),request 屬性其實(shí)是使用了 PreparedRequest。有時(shí)在發(fā)送請(qǐng)求之前,你需要對(duì) body 或者 header (或者別的什么東西)做一些額外處理,下面演示了一個(gè)簡(jiǎn)單的做法:

          from requests import Request, Session
           
          s=Session()
          req=Request('GET', url,
           data=data,
           headers=header
          )
          prepped=req.prepare()
           
          # do something with prepped.body
          # do something with prepped.headers
           
          resp=s.send(prepped,
           stream=stream,
           verify=verify,
           proxies=proxies,
           cert=cert,
           timeout=timeout
          )
           
          print(resp.status_code)
          

          由于你沒(méi)有對(duì) Request 對(duì)象做什么特殊事情,你立即準(zhǔn)備和修改了 PreparedRequest 對(duì)象,然后把它和別的參數(shù)一起發(fā)送到 requests.* 或者 Session.*。

          然而,上述代碼會(huì)失去 Requests Session 對(duì)象的一些優(yōu)勢(shì), 尤其 Session 級(jí)別的狀態(tài),例如 cookie 就不會(huì)被應(yīng)用到你的請(qǐng)求上去。要獲取一個(gè)帶有狀態(tài)的 PreparedRequest, 請(qǐng)用 Session.prepare_request() 取代 Request.prepare() 的調(diào)用,如下所示:

          from requests import Request, Session
           
          s=Session()
          req=Request('GET', url,
           data=data
           headers=headers
          )
           
          prepped=s.prepare_request(req)
           
          # do something with prepped.body
          # do something with prepped.headers
           
          resp=s.send(prepped,
           stream=stream,
           verify=verify,
           proxies=proxies,
           cert=cert,
           timeout=timeout
          )
           
          print(resp.status_code)
          

          4、SSL 證書驗(yàn)證

          Requests 可以為 HTTPS 請(qǐng)求驗(yàn)證 SSL 證書,就像 web 瀏覽器一樣。SSL 驗(yàn)證默認(rèn)是開(kāi)啟的,如果證書驗(yàn)證失敗,Requests 會(huì)拋出 SSLError:

          >>> requests.get('https://requestb.in')
          requests.exceptions.SSLError: hostname 'requestb.in' doesn't match either of '*.herokuapp.com', 'herokuapp.com'
          

          在該域名上我沒(méi)有設(shè)置 SSL,所以失敗了。但 Github 設(shè)置了 SSL:

          >>> requests.get('https://github.com', verify=True)
          <Response [200]>
          

          你可以為 verify 傳入 CA_BUNDLE 文件的路徑,或者包含可信任 CA 證書文件的文件夾路徑:

          >>> requests.get('https://github.com', verify='/path/to/certfile')
          

          或者將其保持在會(huì)話中:

          s=requests.Session()
          s.verify='/path/to/certfile'
          

          注解:如果 verify 設(shè)為文件夾路徑,文件夾必須通過(guò) OpenSSL 提供的 c_rehash 工具處理。

          你還可以通過(guò) REQUESTS_CA_BUNDLE 環(huán)境變量定義可信任 CA 列表。

          如果你將 verify 設(shè)置為 False,Requests 也能忽略對(duì) SSL 證書的驗(yàn)證。

          >>> requests.get('https://kennethreitz.org', verify=False)
          <Response [200]>
          

          默認(rèn)情況下, verify 是設(shè)置為 True 的。選項(xiàng) verify 僅應(yīng)用于主機(jī)證書。

          # 對(duì)于私有證書,你也可以傳遞一個(gè) CA_BUNDLE 文件的路徑給 verify。你也可以設(shè)置 # REQUEST_CA_BUNDLE 環(huán)境變量。

          5、客戶端證書

          你也可以指定一個(gè)本地證書用作客戶端證書,可以是單個(gè)文件(包含密鑰和證書)或一個(gè)包含兩個(gè)文件路徑的元組:

          >>> requests.get('https://kennethreitz.org', cert=('/path/client.cert', '/path/client.key'))
          <Response [200]>
          

          或者保持在會(huì)話中:

          s=requests.Session()
          s.cert='/path/client.cert'
          

          如果你指定了一個(gè)錯(cuò)誤路徑或一個(gè)無(wú)效的證書:

          >>> requests.get('https://kennethreitz.org', cert='/wrong_path/client.pem')
          SSLError: [Errno 336265225] _ssl.c:347: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib
          

          警告:本地證書的私有 key 必須是解密狀態(tài)。目前,Requests 不支持使用加密的 key。

          6、CA 證書

          Requests 默認(rèn)附帶了一套它信任的根證書,來(lái)自于 Mozilla trust store。然而它們?cè)诿看?Requests 更新時(shí)才會(huì)更新。這意味著如果你固定使用某一版本的 Requests,你的證書有可能已經(jīng) 太舊了。

          從 Requests 2.4.0 版之后,如果系統(tǒng)中裝了 certifi 包,Requests 會(huì)試圖使用它里邊的 證書。這樣用戶就可以在不修改代碼的情況下更新他們的可信任證書。

          為了安全起見(jiàn),我們建議你經(jīng)常更新 certifi!

          7、響應(yīng)體內(nèi)容工作流

          默認(rèn)情況下,當(dāng)你進(jìn)行網(wǎng)絡(luò)請(qǐng)求后,響應(yīng)體會(huì)立即被下載。你可以通過(guò) stream 參數(shù)覆蓋這個(gè)行為,推遲下載響應(yīng)體直到訪問(wèn) Response.content 屬性:

          tarball_url='https://github.com/kennethreitz/requests/tarball/master'
          r=requests.get(tarball_url, stream=True)
          

          此時(shí)僅有響應(yīng)頭被下載下來(lái)了,連接保持打開(kāi)狀態(tài),因此允許我們根據(jù)條件獲取內(nèi)容:

          if int(r.headers['content-length']) < TOO_LONG:
           content=r.content
           ...
          

          你可以進(jìn)一步使用 Response.iter_content 和 Response.iter_lines 方法來(lái)控制工作流,或者以 Response.raw 從底層 urllib3 的 urllib3.HTTPResponse <urllib3.response.HTTPResponse 讀取未解碼的響應(yīng)體。

          如果你在請(qǐng)求中把 stream 設(shè)為 True,Requests 無(wú)法將連接釋放回連接池,除非你消耗了所有的數(shù)據(jù),或者調(diào)用了 Response.close。 這樣會(huì)帶來(lái)連接效率低下的問(wèn)題。如果你發(fā)現(xiàn)你在使用 stream=True 的同時(shí)還在部分讀取請(qǐng)求的 body(或者完全沒(méi)有讀取 body),那么你就應(yīng)該考慮使用 with 語(yǔ)句發(fā)送請(qǐng)求,這樣可以保證請(qǐng)求一定會(huì)被關(guān)閉:

          with requests.get('http://httpbin.org/get', stream=True) as r:
           # 在此處理響應(yīng)。
          

          8、保持活動(dòng)狀態(tài)(持久連接)

          好消息——?dú)w功于 urllib3,同一會(huì)話內(nèi)的持久連接是完全自動(dòng)處理的!同一會(huì)話內(nèi)你發(fā)出的任何請(qǐng)求都會(huì)自動(dòng)復(fù)用恰當(dāng)?shù)倪B接!

          注意:只有所有的響應(yīng)體數(shù)據(jù)被讀取完畢連接才會(huì)被釋放為連接池;所以確保將 stream 設(shè)置為 False 或讀取 Response 對(duì)象的 content 屬性。

          9、流式上傳

          Requests支持流式上傳,這允許你發(fā)送大的數(shù)據(jù)流或文件而無(wú)需先把它們讀入內(nèi)存。要使用流式上傳,僅需為你的請(qǐng)求體提供一個(gè)類文件對(duì)象即可:

          with open('massive-body') as f:
           requests.post('http://some.url/streamed', data=f)
          

          警告:我們強(qiáng)烈建議你用二進(jìn)制模式(binary mode)打開(kāi)文件。這是因?yàn)?requests 可能會(huì)為你提供 header 中的 Content-Length,在這種情況下該值會(huì)被設(shè)為文件的字節(jié)數(shù)。如果你用文本模式打開(kāi)文件,就可能碰到錯(cuò)誤。

          10、塊編碼請(qǐng)求

          對(duì)于出去和進(jìn)來(lái)的請(qǐng)求,Requests 也支持分塊傳輸編碼。要發(fā)送一個(gè)塊編碼的請(qǐng)求,僅需為你的請(qǐng)求體提供一個(gè)生成器(或任意沒(méi)有具體長(zhǎng)度的迭代器):

          def gen():
           yield 'hi'
           yield 'there'
           
          requests.post('http://some.url/chunked', data=gen())
          

          對(duì)于分塊的編碼請(qǐng)求,我們最好使用 Response.iter_content() 對(duì)其數(shù)據(jù)進(jìn)行迭代。在理想情況下,你的 request 會(huì)設(shè)置 stream=True,這樣你就可以通過(guò)調(diào)用 iter_content 并將分塊大小參數(shù)設(shè)為 None,從而進(jìn)行分塊的迭代。如果你要設(shè)置分塊的最大體積,你可以把分塊大小參數(shù)設(shè)為任意整數(shù)。

          11、POST 多個(gè)分塊編碼的文件

          你可以在一個(gè)請(qǐng)求中發(fā)送多個(gè)文件。例如,假設(shè)你要上傳多個(gè)圖像文件到一個(gè) HTML 表單,使用一個(gè)多文件 field 叫做 "images":

          <input type="file" name="images" multiple="true" required="true"/>
          

          要實(shí)現(xiàn),只要把文件設(shè)到一個(gè)元組的列表中,其中元組結(jié)構(gòu)為 (form_field_name, file_info):

          >>> url='http://httpbin.org/post'
          >>> multiple_files=[
           ('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
           ('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]
          >>> r=requests.post(url, files=multiple_files)
          >>> r.text
          {
           ...
           'files': {'images': 'data:image/png;base64,iVBORw ....'}
           'Content-Type': 'multipart/form-data; boundary=3131623adb2043caaeb5538cc7aa0b3a',
           ...
          }
          

          12、事件掛鉤

          Requests有一個(gè)鉤子系統(tǒng),你可以用來(lái)操控部分請(qǐng)求過(guò)程,或信號(hào)事件處理。

          可用的鉤子:

          response:
          從一個(gè)請(qǐng)求產(chǎn)生的響應(yīng)
          

          你可以通過(guò)傳遞一個(gè) {hook_name: callback_function} 字典給 hooks 請(qǐng)求參數(shù)為每個(gè)請(qǐng)求分配一個(gè)鉤子函數(shù):

          hooks=dict(response=print_url)
          

          callback_function 會(huì)接受一個(gè)數(shù)據(jù)塊作為它的第一個(gè)參數(shù)。

          def print_url(r, *args, **kwargs):
           print(r.url)
          

          若執(zhí)行你的回調(diào)函數(shù)期間發(fā)生錯(cuò)誤,系統(tǒng)會(huì)給出一個(gè)警告。

          若回調(diào)函數(shù)返回一個(gè)值,默認(rèn)以該值替換傳進(jìn)來(lái)的數(shù)據(jù)。若函數(shù)未返回任何東西,也沒(méi)有什么其他的影響。

          我們來(lái)在運(yùn)行期間打印一些請(qǐng)求方法的參數(shù):

          >>> requests.get('http://httpbin.org', hooks=dict(response=print_url))
          http://httpbin.org
          <Response [200]>
          

          13、自定義身份驗(yàn)證

          Requests 允許你使用自己指定的身份驗(yàn)證機(jī)制。

          任何傳遞給請(qǐng)求方法的 auth 參數(shù)的可調(diào)用對(duì)象,在請(qǐng)求發(fā)出之前都有機(jī)會(huì)修改請(qǐng)求。

          自定義的身份驗(yàn)證機(jī)制是作為 requests.auth.AuthBase 的子類來(lái)實(shí)現(xiàn)的,也非常容易定義。Requests 在 requests.auth 中提供了兩種常見(jiàn)的的身份驗(yàn)證方案: HTTPBasicAuth 和 HTTPDigestAuth 。

          假設(shè)我們有一個(gè)web服務(wù),僅在 X-Pizza 頭被設(shè)置為一個(gè)密碼值的情況下才會(huì)有響應(yīng)。雖然這不太可能,但就以它為例好了。

          from requests.auth import AuthBase
           
          class PizzaAuth(AuthBase): 
           """Attaches HTTP Pizza Authentication to the given Request object."""
           def __init__(self, username):
           # setup any auth-related data here
           self.username=username
           
           def __call__(self, r):
           # modify and return the request
           r.headers['X-Pizza']=self.username
           return r
          

          然后就可以使用我們的PizzaAuth來(lái)進(jìn)行網(wǎng)絡(luò)請(qǐng)求:

          >>> requests.get('http://pizzabin.org/admin', auth=PizzaAuth('kenneth'))
          <Response [200]>
          

          14、流式請(qǐng)求

          使用 Response.iter_lines() 你可以很方便地對(duì)流式 API (例如 Twitter 的流式 API ) 進(jìn)行迭代。簡(jiǎn)單地設(shè)置 stream 為 True 便可以使用 iter_lines 對(duì)相應(yīng)進(jìn)行迭代:

          import json
          import requests
           
          r=requests.get('http://httpbin.org/stream/20', stream=True)
           
          for line in r.iter_lines():
           
           # filter out keep-alive new lines
           if line:
           decoded_line=line.decode('utf-8')
           print(json.loads(decoded_line))
          

          當(dāng)使用 decode_unicode=True 在 Response.iter_lines() 或 Response.iter_content() 中時(shí),你需要提供一個(gè)回退編碼方式,以防服務(wù)器沒(méi)有提供默認(rèn)回退編碼,從而導(dǎo)致錯(cuò)誤:

          r=requests.get('http://httpbin.org/stream/20', stream=True)
           
          if r.encoding is None:
           r.encoding='utf-8'
           
          for line in r.iter_lines(decode_unicode=True):
           if line:
           print(json.loads(line))
          

          警告:iter_lines 不保證重進(jìn)入時(shí)的安全性。多次調(diào)用該方法會(huì)導(dǎo)致部分收到的數(shù)據(jù)丟失。如果你要在多處調(diào)用它,就應(yīng)該使用生成的迭代器對(duì)象:

          lines=r.iter_lines()
          # 保存第一行以供后面使用,或者直接跳過(guò)
           
          first_line=next(lines)
           
          for line in lines:
           print(line)
          

          15、代理

          如果需要使用代理,你可以通過(guò)為任意請(qǐng)求方法提供 proxies 參數(shù)來(lái)配置單個(gè)請(qǐng)求:

          import requests
           
          proxies={
           "http": "http://10.10.1.10:3128",
           "https": "http://10.10.1.10:1080",
          }
           
          requests.get("http://example.org", proxies=proxies)
          

          你也可以通過(guò)環(huán)境變量 HTTP_PROXY 和 HTTPS_PROXY 來(lái)配置代理。

          $ export HTTP_PROXY="http://10.10.1.10:3128"
          $ export HTTPS_PROXY="http://10.10.1.10:1080"
           
          $ python
          >>> import requests
          >>> requests.get("http://example.org")
          

          若你的代理需要使用HTTP Basic Auth,可以使用 http://user:password@host/ 語(yǔ)法:

          proxies={
           "http": "http://user:pass@10.10.1.10:3128/",
          }
          

          要為某個(gè)特定的連接方式或者主機(jī)設(shè)置代理,使用 scheme://hostname 作為 key, 它會(huì)針對(duì)指定的主機(jī)和連接方式進(jìn)行匹配。

          proxies={'http://10.20.1.128': 'http://10.10.1.10:5323'}
          

          注意,代理 URL 必須包含連接方式。

          16、SOCKS

          2.10.0 新版功能.

          除了基本的 HTTP 代理,Request 還支持 SOCKS 協(xié)議的代理。這是一個(gè)可選功能,若要使用, 你需要安裝第三方庫(kù)。

          你可以用 pip 獲取依賴:

          $ pip install requests[socks]
          

          安裝好依賴以后,使用 SOCKS 代理和使用 HTTP 代理一樣簡(jiǎn)單:

          proxies={
           'http': 'socks5://user:pass@host:port',
           'https': 'socks5://user:pass@host:port'
          }
          

          17、合規(guī)性

          Requests 符合所有相關(guān)的規(guī)范和 RFC,這樣不會(huì)為用戶造成不必要的困難。但這種對(duì)規(guī)范的考慮導(dǎo)致一些行為對(duì)于不熟悉相關(guān)規(guī)范的人來(lái)說(shuō)看似有點(diǎn)奇怪。

          18、編碼方式

          當(dāng)你收到一個(gè)響應(yīng)時(shí),Requests 會(huì)猜測(cè)響應(yīng)的編碼方式,用于在你調(diào)用 Response.text 方法時(shí)對(duì)響應(yīng)進(jìn)行解碼。Requests 首先在 HTTP 頭部檢測(cè)是否存在指定的編碼方式,如果不存在,則會(huì)使用 charade 來(lái)嘗試猜測(cè)編碼方式。

          只有當(dāng) HTTP 頭部不存在明確指定的字符集,并且 Content-Type 頭部字段包含 text 值之時(shí), Requests 才不去猜測(cè)編碼方式。在這種情況下, RFC 2616 指定默認(rèn)字符集必須是 ISO-8859-1 。Requests 遵從這一規(guī)范。如果你需要一種不同的編碼方式,你可以手動(dòng)設(shè)置 Response.encoding 屬性,或使用原始的 Response.content。

          19、HTTP動(dòng)詞

          Requests 提供了幾乎所有HTTP動(dòng)詞的功能:GET、OPTIONS、HEAD、POST、PUT、PATCH、DELETE。以下內(nèi)容為使用 Requests 中的這些動(dòng)詞以及 Github API 提供了詳細(xì)示例。

          我將從最常使用的動(dòng)詞 GET 開(kāi)始。HTTP GET 是一個(gè)冪等方法,從給定的 URL 返回一個(gè)資源。因而,當(dāng)你試圖從一個(gè) web 位置獲取數(shù)據(jù)之時(shí),你應(yīng)該使用這個(gè)動(dòng)詞。一個(gè)使用示例是嘗試從 Github 上獲取關(guān)于一個(gè)特定 commit 的信息。假設(shè)我們想獲取 Requests 的 commit a050faf 的信息。我們可以這樣去做:

          >>> import requests
          >>> r=requests.get('https://api.github.com/repos/requests/requests/git/commits/a050faf084662f3a352dd1a941f2c7c9f886d4ad')
          

          我們應(yīng)該確認(rèn) GitHub 是否正確響應(yīng)。如果正確響應(yīng),我們想弄清響應(yīng)內(nèi)容是什么類型的。像這樣去做:

          >>> if (r.status_code==requests.codes.ok):
          ... print r.headers['content-type']
          ...
          application/json; charset=utf-8
          

          可見(jiàn),GitHub 返回了 JSON 數(shù)據(jù),非常好,這樣就可以使用 r.json 方法把這個(gè)返回的數(shù)據(jù)解析成 Python 對(duì)象。

          >>> commit_data=r.json()
           
          >>> print commit_data.keys()
          [u'committer', u'author', u'url', u'tree', u'sha', u'parents', u'message']
           
          >>> print commit_data[u'committer']
          {u'date': u'2012-05-10T11:10:50-07:00', u'email': u'me@kennethreitz.com', u'name': u'Kenneth Reitz'}
           
          >>> print commit_data[u'message']
          makin' history
          

          到目前為止,一切都非常簡(jiǎn)單。嗯,我們來(lái)研究一下 GitHub 的 API。我們可以去看看文檔,但如果使用 Requests 來(lái)研究也許會(huì)更有意思一點(diǎn)。我們可以借助 Requests 的 OPTIONS 動(dòng)詞來(lái)看看我們剛使用過(guò)的 url 支持哪些 HTTP 方法。

          >>> verbs=requests.options(r.url)
          >>> verbs.status_code
          500
          

          額,這是怎么回事?毫無(wú)幫助嘛!原來(lái) GitHub,與許多 API 提供方一樣,實(shí)際上并未實(shí)現(xiàn) OPTIONS 方法。這是一個(gè)惱人的疏忽,但沒(méi)關(guān)系,那我們可以使用枯燥的文檔。然而,如果 GitHub 正確實(shí)現(xiàn)了 OPTIONS,那么服務(wù)器應(yīng)該在響應(yīng)頭中返回允許用戶使用的 HTTP 方法,例如:

          >>> verbs=requests.options('http://a-good-website.com/api/cats')
          >>> print verbs.headers['allow']
          GET,HEAD,POST,OPTIONS
          

          轉(zhuǎn)而去查看文檔,我們看到對(duì)于提交信息,另一個(gè)允許的方法是 POST,它會(huì)創(chuàng)建一個(gè)新的提交。由于我們正在使用 Requests 代碼庫(kù),我們應(yīng)盡可能避免對(duì)它發(fā)送笨拙的 POST。作為替代,我們來(lái)玩玩 GitHub 的 Issue 特性。

          本篇文檔是回應(yīng) Issue #482 而添加的。鑒于該問(wèn)題已經(jīng)存在,我們就以它為例。先獲取它。

          >>> r=requests.get('https://api.github.com/requests/kennethreitz/requests/issues/482')
          >>> r.status_code
          200
           
          >>> issue=json.loads(r.text)
           
          >>> print(issue[u'title'])
          Feature any http verb in docs
           
          >>> print(issue[u'comments'])
          3
          

          Cool,有 3 個(gè)評(píng)論。我們來(lái)看一下最后一個(gè)評(píng)論。

          >>> r=requests.get(r.url + u'/comments')
          >>> r.status_code
          200
          >>> comments=r.json()
          >>> print comments[0].keys()
          [u'body', u'url', u'created_at', u'updated_at', u'user', u'id']
          >>> print comments[2][u'body']
          Probably in the "advanced" section
          

          嗯,那看起來(lái)似乎是個(gè)愚蠢之處。我們發(fā)表個(gè)評(píng)論來(lái)告訴這個(gè)評(píng)論者他自己的愚蠢。那么,這個(gè)評(píng)論者是誰(shuí)呢?

          >>> print comments[2][u'user'][u'login']
          kennethreitz
          

          好,我們來(lái)告訴這個(gè)叫 Kenneth 的家伙,這個(gè)例子應(yīng)該放在快速上手指南中。根據(jù) GitHub API 文檔,其方法是 POST 到該話題。我們來(lái)試試看。

          >>> body=json.dumps({u"body": u"Sounds great! I'll get right on it!"})
          >>> url=u"https://api.github.com/repos/requests/requests/issues/482/comments"
           
          >>> r=requests.post(url=url, data=body)
          >>> r.status_code
          404
          

          額,這有點(diǎn)古怪哈。可能我們需要驗(yàn)證身份。那就有點(diǎn)糾結(jié)了,對(duì)吧?不對(duì)。Requests 簡(jiǎn)化了多種身份驗(yàn)證形式的使用,包括非常常見(jiàn)的 Basic Auth。

          >>> from requests.auth import HTTPBasicAuth
          >>> auth=HTTPBasicAuth('fake@example.com', 'not_a_real_password')
           
          >>> r=requests.post(url=url, data=body, auth=auth)
          >>> r.status_code
          201
           
          >>> content=r.json()
          >>> print(content[u'body'])
          Sounds great! I'll get right on it.
          

          太棒了!噢,不!我原本是想說(shuō)等我一會(huì),因?yàn)槲业萌ノ刮业呢垺H绻夷軌蚓庉嬤@條評(píng)論那就好了!幸運(yùn)的是,GitHub 允許我們使用另一個(gè) HTTP 動(dòng)詞 PATCH 來(lái)編輯評(píng)論。我們來(lái)試試。

          >>> print(content[u"id"])
          5804413
           
          >>> body=json.dumps({u"body": u"Sounds great! I'll get right on it once I feed my cat."})
          >>> url=u"https://api.github.com/repos/requests/requests/issues/comments/5804413"
           
          >>> r=requests.patch(url=url, data=body, auth=auth)
          >>> r.status_code
          200
          

          非常好。現(xiàn)在,我們來(lái)折磨一下這個(gè)叫 Kenneth 的家伙,我決定要讓他急得團(tuán)團(tuán)轉(zhuǎn),也不告訴他是我在搗蛋。這意味著我想刪除這條評(píng)論。GitHub 允許我們使用完全名副其實(shí)的 DELETE 方法來(lái)刪除評(píng)論。我們來(lái)清除該評(píng)論。

          >>> r=requests.delete(url=url, auth=auth)
          >>> r.status_code
          204
          >>> r.headers['status']
          '204 No Content'
          

          很好。不見(jiàn)了。最后一件我想知道的事情是我已經(jīng)使用了多少限額(ratelimit)。查查看,GitHub 在響應(yīng)頭部發(fā)送這個(gè)信息,因此不必下載整個(gè)網(wǎng)頁(yè),我將使用一個(gè) HEAD 請(qǐng)求來(lái)獲取響應(yīng)頭。

          >>> r=requests.head(url=url, auth=auth)
          >>> print r.headers
          ...
          'x-ratelimit-remaining': '4995'
          'x-ratelimit-limit': '5000'
          ...
          

          很好。是時(shí)候?qū)憘€(gè) Python 程序以各種刺激的方式濫用 GitHub 的 API,還可以使用 4995 次呢。

          20、定制動(dòng)詞

          有時(shí)候你會(huì)碰到一些服務(wù)器,處于某些原因,它們?cè)试S或者要求用戶使用上述 HTTP 動(dòng)詞之外的定制動(dòng)詞。比如說(shuō) WEBDAV 服務(wù)器會(huì)要求你使用 MKCOL 方法。別擔(dān)心,Requests 一樣可以搞定它們。你可以使用內(nèi)建的 .request 方法,例如:

          >>> r=requests.request('MKCOL', url, data=data)
          >>> r.status_code
          200 # Assuming your call was correct
          

          這樣你就可以使用服務(wù)器要求的任意方法動(dòng)詞了。

          21、響應(yīng)頭鏈接字段

          許多 HTTP API 都有響應(yīng)頭鏈接字段的特性,它們使得 API 能夠更好地自我描述和自我顯露。

          GitHub 在 API 中為 分頁(yè) 使用這些特性,例如:

          >>> url='https://api.github.com/users/kennethreitz/repos?page=1&per_page=10'
          >>> r=requests.head(url=url)
          >>> r.headers['link']
          '<https://api.github.com/users/kennethreitz/repos?page=2&per_page=10>; rel="next", <https://api.github.com/users/kennethreitz/repos?page=6&per_page=10>; rel="last"'
          

          Requests 會(huì)自動(dòng)解析這些響應(yīng)頭鏈接字段,并使得它們非常易于使用:

          >>> r.links["next"]
          {'url': 'https://api.github.com/users/kennethreitz/repos?page=2&per_page=10', 'rel': 'next'}
           
          >>> r.links["last"]
          {'url': 'https://api.github.com/users/kennethreitz/repos?page=7&per_page=10', 'rel': 'last'}
          

          22、傳輸適配器

          從 v1.0.0 以后,Requests 的內(nèi)部采用了模塊化設(shè)計(jì)。部分原因是為了實(shí)現(xiàn)傳輸適配器(Transport Adapter),你可以看看關(guān)于它的最早描述。傳輸適配器提供了一個(gè)機(jī)制,讓你可以為 HTTP 服務(wù)定義交互方法。尤其是它允許你應(yīng)用服務(wù)前的配置。

          Requests 自帶了一個(gè)傳輸適配器,也就是 HTTPAdapter。 這個(gè)適配器使用了強(qiáng)大的 urllib3,為 Requests 提供了默認(rèn)的 HTTP 和 HTTPS 交互。每當(dāng) Session 被初始化,就會(huì)有適配器附著在 Session 上,其中一個(gè)供 HTTP 使用,另一個(gè)供 HTTPS 使用。

          Request 允許用戶創(chuàng)建和使用他們自己的傳輸適配器,實(shí)現(xiàn)他們需要的特殊功能。創(chuàng)建好以后,傳輸適配器可以被加載到一個(gè)會(huì)話對(duì)象上,附帶著一個(gè)說(shuō)明,告訴會(huì)話適配器應(yīng)該應(yīng)用在哪個(gè) web 服務(wù)上。

          >>> s=requests.Session()
          >>> s.mount('http://www.github.com', MyAdapter())
          

          這個(gè) mount 調(diào)用會(huì)注冊(cè)一個(gè)傳輸適配器的特定實(shí)例到一個(gè)前綴上面。加載以后,任何使用該會(huì)話的 HTTP 請(qǐng)求,只要其 URL 是以給定的前綴開(kāi)頭,該傳輸適配器就會(huì)被使用到。

          傳輸適配器的眾多實(shí)現(xiàn)細(xì)節(jié)不在本文檔的覆蓋范圍內(nèi),不過(guò)你可以看看接下來(lái)這個(gè)簡(jiǎn)單的 SSL 用例。更多的用法,你也許該考慮為 BaseAdapter 創(chuàng)建子類。

          23、示例: 指定的 SSL 版本

          Requests 開(kāi)發(fā)團(tuán)隊(duì)刻意指定了內(nèi)部庫(kù)(urllib3)的默認(rèn) SSL 版本。一般情況下這樣做沒(méi)有問(wèn)題,不過(guò)是不是你可能會(huì)需要連接到一個(gè)服務(wù)節(jié)點(diǎn),而該節(jié)點(diǎn)使用了和默認(rèn)不同的 SSL 版本。

          你可以使用傳輸適配器解決這個(gè)問(wèn)題,通過(guò)利用 HTTPAdapter 現(xiàn)有的大部分實(shí)現(xiàn),再加上一個(gè) ssl_version 參數(shù)并將它傳遞到 urllib3 中。我們會(huì)創(chuàng)建一個(gè)傳輸適配器,用來(lái)告訴 urllib3 讓它使用 SSLv3:

          import ssl
           
          from requests.adapters import HTTPAdapter
          from requests.packages.urllib3.poolmanager import PoolManager
           
           
          class Ssl3HttpAdapter(HTTPAdapter):
           """"Transport adapter" that allows us to use SSLv3."""
           
           def init_poolmanager(self, connections, maxsize, block=False):
           self.poolmanager=PoolManager(num_pools=connections,
           maxsize=maxsize,
           block=block,
           ssl_version=ssl.PROTOCOL_SSLv3)
          

          24、阻塞和非阻塞

          使用默認(rèn)的傳輸適配器,Requests 不提供任何形式的非阻塞 IO。 Response.content 屬性會(huì)阻塞,直到整個(gè)響應(yīng)下載完成。如果你需要更多精細(xì)控制,該庫(kù)的數(shù)據(jù)流功能(見(jiàn) 流式請(qǐng)求) 允許你每次接受少量的一部分響應(yīng),不過(guò)這些調(diào)用依然是阻塞式的。

          如果你對(duì)于阻塞式 IO 有所顧慮,還有很多項(xiàng)目可以供你使用,它們結(jié)合了 Requests 和 Python 的某個(gè)異步框架。典型的優(yōu)秀例子是 grequests 和 requests-futures。

          25、Header 排序

          在某些特殊情況下你也許需要按照次序來(lái)提供 header,如果你向 headers 關(guān)鍵字參數(shù)傳入一個(gè) OrderedDict,就可以向提供一個(gè)帶排序的 header。然而,Requests 使用的默認(rèn) header 的次序會(huì)被優(yōu)先選擇,這意味著如果你在 headers 關(guān)鍵字參數(shù)中覆蓋了默認(rèn) header,和關(guān)鍵字參數(shù)中別的 header 相比,它們也許看上去會(huì)是次序錯(cuò)誤的。

          如果這個(gè)對(duì)你來(lái)說(shuō)是個(gè)問(wèn)題,那么用戶應(yīng)該考慮在 Session 對(duì)象上面設(shè)置默認(rèn) header,只要將 Session 設(shè)為一個(gè)定制的 OrderedDict 即可。這樣就會(huì)讓它成為優(yōu)選的次序。

          26、超時(shí)(timeout)

          為防止服務(wù)器不能及時(shí)響應(yīng),大部分發(fā)至外部服務(wù)器的請(qǐng)求都應(yīng)該帶著 timeout 參數(shù)。在默認(rèn)情況下,除非顯式指定了 timeout 值,requests 是不會(huì)自動(dòng)進(jìn)行超時(shí)處理的。如果沒(méi)有 timeout,你的代碼可能會(huì)掛起若干分鐘甚至更長(zhǎng)時(shí)間。

          連接超時(shí)指的是在你的客戶端實(shí)現(xiàn)到遠(yuǎn)端機(jī)器端口的連接時(shí)(對(duì)應(yīng)的是`connect()`_),Request 會(huì)等待的秒數(shù)。一個(gè)很好的實(shí)踐方法是把連接超時(shí)設(shè)為比 3 的倍數(shù)略大的一個(gè)數(shù)值,因?yàn)?TCP 數(shù)據(jù)包重傳窗口 (TCP packet retransmission window) 的默認(rèn)大小是 3。

          一旦你的客戶端連接到了服務(wù)器并且發(fā)送了 HTTP 請(qǐng)求,讀取超時(shí)指的就是客戶端等待服務(wù)器發(fā)送請(qǐng)求的時(shí)間。(特定地,它指的是客戶端要等待服務(wù)器發(fā)送字節(jié)之間的時(shí)間。在 99.9% 的情況下這指的是服務(wù)器發(fā)送第一個(gè)字節(jié)之前的時(shí)間)。

          如果你制訂了一個(gè)單一的值作為 timeout,如下所示:

          r=requests.get('https://github.com', timeout=5)
          

          這一 timeout 值將會(huì)用作 connect 和 read 二者的 timeout。如果要分別制定,就傳入一個(gè)元組:

          r=requests.get('https://github.com', timeout=(3.05, 27))
          

          如果遠(yuǎn)端服務(wù)器很慢,你可以讓 Request 永遠(yuǎn)等待,傳入一個(gè) None 作為 timeout 值,然后就沖咖啡去吧。


          主站蜘蛛池模板: 亚洲av永久无码一区二区三区| 亚洲一区在线视频| 精品一区二区久久久久久久网精| 午夜一区二区在线观看| 无码人妻一区二区三区在线水卜樱| 男女久久久国产一区二区三区| 亚洲高清偷拍一区二区三区| 中文乱码人妻系列一区二区| 亚洲高清美女一区二区三区 | 日韩精品无码一区二区三区| 日本一区二区三区在线视频| 91国偷自产一区二区三区| 亚洲熟妇av一区二区三区| 在线观看国产一区二区三区| 国产精品无码一区二区三区不卡| 99久久无码一区人妻a黑| 精品无码日韩一区二区三区不卡 | 97人妻无码一区二区精品免费 | 亚洲av综合av一区| 国产在线观看精品一区二区三区91| 亚洲AV无码一区二区三区在线| 精品乱人伦一区二区三区| 中文字幕永久一区二区三区在线观看| 日本精品一区二区三区视频| 欧美亚洲精品一区二区| 亚洲国产福利精品一区二区| 91秒拍国产福利一区| 精品少妇ay一区二区三区| 97av麻豆蜜桃一区二区| 99精品国产高清一区二区麻豆| 色噜噜狠狠一区二区三区| 国产成人精品第一区二区| 国内精品一区二区三区东京| 无码人妻aⅴ一区二区三区| 国产亚洲福利精品一区二区| 区三区激情福利综合中文字幕在线一区亚洲视频1 | 无码精品黑人一区二区三区| 骚片AV蜜桃精品一区| 中文字幕一区二区三区精彩视频| 亚洲制服丝袜一区二区三区 | 免费人妻精品一区二区三区|