Python+Requests接口測試教程(2):requests


開講前,告訴大家requests有他自己的官方文檔:http://cn.python-requests.org/zh_CN/latest/

 

2.1 發get請求

前言
requests模塊,也就是老污龜,為啥叫它老污龜呢,因為這個官網上的logo就是這只污龜,接下來就是學習它了。
環境准備(小編環境):
python:2.7.12
pycharm:5.0.4
requests:2.13.0
(這學本篇之前,先要有一定的python基礎,因為后面都是直接用python寫代碼了,小編主要以講接口為主,python基礎東西就自己去補了)
 
一、環境安裝

1.用pip安裝requests模塊
>>pip install requests

二、get請求

1.導入requests后,用get方法就能直接訪問url地址,如:http://www.cnblogs.com/yoyoketang/,看起來是不是很酷
2.這里的r也就是response,請求后的返回值,可以調用response里的status_code方法查看狀態碼
3.狀態碼200只能說明這個接口訪問的服務器地址是對的,並不能說明功能OK,一般要查看響應的內容,r.text是返回文本信息

三、params
1.再發一個帶參數的get請求,如在博客園搜索:yoyoketang,url地址為:http://zzk.cnblogs.com/s/blogpost?Keywords=yoyoketang
2.請求參數:Keywords=yoyoketang,可以以字典的形式傳參:{"Keywords": "yoyoketang"}
3.多個參數格式:{"key1": "value1", "key2": "value2", "key3": "value3"}

四、content
1.百度首頁如果用r.text會發現獲取到的內容有亂碼,因為百度首頁響應內容是gzip壓縮的(非text文本)

 

 2.如果是在fiddler工具亂碼,是可以點擊后解碼的,在代碼里面可以用r.content這個方法,content會自動解碼 gzip 和deflate壓縮

五、response
1.response的返回內容還有其它更多信息

-- r.status_code     #響應狀態碼
-- r.content           #字節方式的響應體,會自動為你解碼 gzip 和 deflate 壓縮
-- r.headers          #以字典對象存儲服務器響應頭,但是這個字典比較特殊,字典鍵不區分大小寫,若鍵不存在則返回None
-- r.json()             #Requests中內置的JSON解碼器
-- r.url                  # 獲取url
-- r.encoding         # 編碼格式
-- r.cookies           # 獲取cookie
-- r.raw                #返回原始響應體
-- r.text               #字符串方式的響應體,會自動根據響應頭部的字符編碼進行解碼
-- r.raise_for_status() #失敗請求(非200響應)拋出異常

2.2 發post請求(json)

前言
發送post的請求參考例子很簡單,實際遇到的情況卻是很復雜的,首先第一個post請求肯定是登錄了,但登錄是最難處理的。登錄問題解決了,后面都簡單了。
 
一、查看官方文檔
1.學習一個新的模塊,其實不用去百度什么的,直接用help函數就能查看相關注釋和案例內容。
>>import requests
>>help(requests)

 

2.查看python發送get和post請求的案例
       >>> import requests
       >>> r = requests.get('https://www.python.org')
       >>> r.status_code
       200

       >>> 'Python is a programming language' in r.content
       True
    
    ... or POST:
    
       >>> payload = dict(key1='value1', key2='value2')
       >>> r = requests.post('http://httpbin.org/post', data=payload)
       >>> print(r.text)
       {
         ...
         "form": {
           "key2": "value2",

           "key1": "value1"
         },
         ...
       }
 
二、發送post請求
1.用上面給的案例,做個簡單修改,發個post請求
2.payload參數是字典類型,傳到如下圖的form里

三、json
1.post的body是json類型,也可以用json參數傳入。
2.先導入json模塊,用dumps方法轉化成json格式。

3.返回結果,傳到data里。

四、headers
1.以博客園為例,模擬登陸,實際的情況要比上面講的幾個基本內容要復雜很多,一般登陸涉及安全性方面,登陸會比較復雜

2.這里需添加請求頭headers,可以用fiddler抓包

3.將請求頭寫成字典格式

headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0",
            "Accept": "application/json, text/javascript, */*; q=0.01",
            "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
            "Accept-Encoding": "gzip, deflate, br",
            "Content-Type": "application/json; charset=utf-8",
            "X-Requested-With": "XMLHttpRequest",
            "Cookie": "xxx.............",    # 此處cookie省略了
            "Connection": "keep-alive"
            }

五、登陸博客園
1.由於這里是https請求,直接發送請求會報錯誤:SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)
2.可以加個參數:verify=False,表示忽略對 SSL 證書的驗證

3.這里請求參數payload是json格式的,用json參數傳
4.紅色注釋那兩行可以不用寫
5.最后結果是json格式,可以直接用r.json返回json數據:{u'success': True}

六、參考代碼

# coding:utf-8
import requests
url = "https://passport.cnblogs.com/user/signin"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0",
            "Accept": "application/json, text/javascript, */*; q=0.01",
            "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
            "Accept-Encoding": "gzip, deflate, br",
            "Content-Type": "application/json; charset=utf-8",
            # "VerificationToken": "",
            "X-Requested-With": "XMLHttpRequest",
            # "Referer": "",  
            "Content-Length": "385",
            "Cookie": "xxx..."# 此處省略
            "Connection": "keep-alive"
            }
payload = {"input1":"xxx",
                 "input2":"xxx",
                 "remember":True}
r = requests.post(url, json=payload, headers=headers,verify=False)
print r.json()

2.3 發post請求(data)

前言:
前面登錄博客園的是傳json參數,有些登錄不是傳json的,如jenkins的登錄,本篇以jenkins登錄為案例,傳data參數。
 
一、登錄jenkins抓包
1.登錄jenkins,輸入賬號和密碼

2.fiddler抓包

 

3.這個body參數並不是json格式,是key=value格式,也就是前面介紹post請求四種數據類型里面的第二種

二、請求頭部
1.上面抓包已經知道body的數據類型了,那么頭部里面Content-Type類型也需要填寫對應的參數類型

 

三、實現登錄
1、登錄代碼如下:

 

# coding:utf-8
import requests
# 先打開登錄首頁,獲取部分cookie
url = "http://localhost:8080/jenkins/j_acegi_security_check"
headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0"
           }  # get方法其它加個ser-Agent就可以了
d = {"from": "",
     "j_password": "f7bcd85ebab14e2fbb6d76cc99bc5c6a",
     "j_username": "admin",
     "Jenkins-Crumb": "e677c237181756818cbbccd4296d44f1",
     "json": {"j_username": "admin",
              "j_password": "f7bcd85ebab14e2fbb6d76cc99bc5c6a",
              "remember_me": True,
              "from": "",
              "Jenkins-Crumb": "e677c237181756818cbbccd4296d44f1"},
     "remember_me": "on",
     "Submit": u"登錄"
     }
s = requests.session()
r = s.post(url, headers=headers, data=d)
print r.content

2.打印結果

四、判斷登錄是否成功
1.首先這個登錄接口有重定向,看左邊會話框302,那登錄成功的結果看最后一個200就行

2.返回的結果並不是跟博客園一樣的json格式,返回的是一個html頁面
 
五、判斷登錄成功
1.判斷登錄成功,可以抓取頁面上的關鍵元素,比如:賬號名稱admin,注銷按鈕

2.通過正則表達式提出這2個關鍵字

六、參考代碼

# coding:utf-8
import requests
# 先打開登錄首頁,獲取部分cookie
url = "http://localhost:8080/jenkins/j_acegi_security_check"
headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0"
           }  # get方法其它加個ser-Agent就可以了
d = {"from": "",
     "j_password": "f7bcd85ebab14e2fbb6d76cc99bc5c6a",
     "j_username": "admin",
     "Jenkins-Crumb": "e677c237181756818cbbccd4296d44f1",
     "json": {"j_username": "admin",
              "j_password": "f7bcd85ebab14e2fbb6d76cc99bc5c6a",
              "remember_me": True,
              "from": "",
              "Jenkins-Crumb": "e677c237181756818cbbccd4296d44f1"},
     "remember_me": "on",
     "Submit": u"登錄"
     }
s = requests.session()
r = s.post(url, headers=headers, data=d)
# 正則表達式提取賬號和登錄按鈕
import re
t = re.findall(r'<b>(.+?)</b>', r.content)   # 用python3的這里r.content需要解碼
print t[0]
print t[1]

2.4 data和json傻傻分不清

前言
在發post請求的時候,有時候body部分要傳data參數,有時候body部分又要傳json參數,那么問題來了:到底什么時候該傳json,什么時候該傳data?
 
一、識別json參數
1.在前面1.8章節講過,post請求的body通常有四種類型,最常見的就是json格式的了,這個還是很好識別的

2.用抓包工具查看,首先點開Raw去查看body部分,如下圖這種,參數最外面是大括號{   }包起來的,這種已經確診為json格式了。

 

 3.再一次確認,可以點開Json這一項查看,點開之后可以看到這里的幾組參數是json解析后的(記住它的樣子)

4.這時候,就可以用前面2.2講的傳json參數

二、識別data參數
1.data參數也就是這種格式:key1=value1&key2=value2...這種格式很明顯沒有大括號

點開Raw查看,跟上面的json區別還是很大的

2.因為這個是非json的,所以點開Json這個菜單是不會有解析的數據的,這種數據在WebForms里面查看

3.可以看到這種參數顯示在Body部分,左邊的Name這項就是key值,右邊的Value就是對應的value值,像這種參數轉化從python的字典格式就行了

4.這一種發post時候就傳data參數就可以了,格式如下:

s = requests.session()
r = s.post(url, headers=headers, data=d)     # 這里的d就是上一步的字典格式的參數

現在能分得清data參數和json參數的不?

2.5 發https請求(ssl)

前言
本來最新的requests庫V2.13.0是支持https請求的,但是一般寫腳本時候,我們會用抓包工具fiddler,這時候會 報:requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)
小編環境:
python:2.7.12
requests:2.13.0
fiddler:v4.6.2.0
 
一、SSL問題
1.不啟用fiddler,直接發https請求,不會有SSL問題(也就是說不想看到SSL問題,關掉fiddler就行)

2.啟動fiddler抓包,會出現這個錯誤:requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590)

二、verify參數設置
1.Requests的請求默認verify=True
2.如果你將 verify設置為 False,Requests 也能忽略對 SSL 證書的驗證
3.但是依然會出現兩行Warning,可以不用管

三、忽略Warning
1.有些小伙伴有強迫症看到紅色的心里就發慌,這里加兩行代碼可以忽略掉警告,眼不見為凈!

2.參考代碼:

# coding:utf-8
import requests
# 禁用安全請求警告
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
url = "https://passport.cnblogs.com/user/signin"
headers = {
     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0"
          }
r = requests.get(url, headers=headers, verify=False)
print(r.status_code)

2.6 session關聯接口

前言
上一篇模擬登錄博客園,但這只是第一步,一般登錄后,還會有其它的操作,如發帖,評論等,這時候如何保持會話呢?
 
一、session簡介
1.查看幫助文檔,貼了一部分,后面省略了

>>import requests
>>help(requests.session())
class Session(SessionRedirectMixin)
 |  A Requests session.
 |  
 |  Provides cookie persistence, connection-pooling, and configuration.
 |  
 |  Basic Usage::
 |  
 |    >>> import requests
 |    >>> s = requests.Session()
 |    >>> s.get('http://httpbin.org/get')
 |    <Response [200]>
 |  
 |  Or as a context manager::
 |  
 |    >>> with requests.Session() as s:
 |    >>>     s.get('http://httpbin.org/get')
 |    <Response [200]>

二、使用session登錄
1.使用session登錄只需在上一篇基礎上稍做修改

# coding:utf-8
import requests
url = "https://passport.cnblogs.com/user/signin"
headers = {
                  #頭部信息已省略
                   }
payload = {"input1":"xxx",
                "input2":"xxx",
                "remember":True}
# r = requests.post(url, json=payload, headers=headers,verify=False)
# 修改后如下
s = requests.session()
r = s.post(url, json=payload, headers=headers,verify=False)
print r.json()

三、保存編輯
1.先打開我的隨筆,手動輸入內容后,打開fiddler抓包

2.把body的參數內容寫成字典格式,有幾個空的參數不是必填的,可以去掉

body = {"__VIEWSTATE": "",
        "__VIEWSTATEGENERATOR":"FE27D343",
        "Editor$Edit$txbTitle":"這是我的標題:上海-悠悠",
        "Editor$Edit$EditorBody":"<p>這里是中文內容:http://www.cnblogs.com/yoyoketang/</p>",
        "Editor$Edit$Advanced$ckbPublished":"on",
        "Editor$Edit$Advanced$chkDisplayHomePage":"on",
        "Editor$Edit$Advanced$chkComments":"on",
        "Editor$Edit$Advanced$chkMainSyndication":"on",
        "Editor$Edit$lkbDraft":"存為草稿",
         }

3.用上面的session繼續發送post請求

4.執行后,查看我的草稿箱就多了一條新增的了

四、參考代碼

# coding:utf-8
import requests
url = "https://passport.cnblogs.com/user/signin"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0",
            "Accept": "application/json, text/javascript, */*; q=0.01",
            "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
            "Accept-Encoding": "gzip, deflate, br",
            "Content-Type": "application/json; charset=utf-8",
            # "VerificationToken": "xxx...",  # 已省略
            "X-Requested-With": "XMLHttpRequest",
            # "Referer": 
"https://passport.cnblogs.com/user/signin?ReturnUrl=http%3a%2f%2fmsg.cnblogs.com%2fsend%2f%e4%b8%8a%e6%b5%b7-%e6%82%a0%e6%82%a0",
            "Content-Length": "385",
            "Cookie": "xxx.....",   # 已省略
            "Connection": "keep-alive"
            }
#  登錄的參數
payload = {"input1":"xxx",
           "input2":"xxx",
           "remember":True}
s = requests.session()
r = s.post(url, json=payload, headers=headers,verify=False)
print r.json()
# 保存草稿箱
url2= "https://i.cnblogs.com/EditPosts.aspx?opt=1"
body = {"__VIEWSTATE": "",
        "__VIEWSTATEGENERATOR":"FE27D343",
        "Editor$Edit$txbTitle":"這是我的標題:上海-悠悠",
        "Editor$Edit$EditorBody":"<p>這里是中文內容:http://www.cnblogs.com/yoyoketang/</p>",
        "Editor$Edit$Advanced$ckbPublished":"on",
        "Editor$Edit$Advanced$chkDisplayHomePage":"on",
        "Editor$Edit$Advanced$chkComments":"on",
        "Editor$Edit$Advanced$chkMainSyndication":"on",
        "Editor$Edit$lkbDraft":"存為草稿",
         }
r2 = s.post(url2, data=body, verify=False)
print r.content

這里我是用保存草稿箱寫的案例,小伙伴們可以試下自動發帖
(備注:別使用太頻繁了哦,小心封號嘿嘿!!!)

2.7 cookie繞過驗證碼登錄

前言
有些登錄的接口會有驗證碼:短信驗證碼,圖形驗證碼等,這種登錄的話驗證碼參數可以從后台獲取的(或者查數據庫最直接)。
獲取不到也沒關系,可以通過添加cookie的方式繞過驗證碼。
(注意:並不是所有的登錄都是用cookie來保持登錄的,有些是2.11章節講的token)
一、抓登錄cookie
1.如博客園登錄后會生成一個已登錄狀態的cookie,那么只需要直接把這個值添加到cookies里面就可以了。
2.可以先手動登錄一次,然后抓取這個cookie,這里就需要用抓包工具fiddler了

3.先打開博客園登錄界面,手動輸入賬號和密碼(勾選下次自動登錄)

4.打開fiddler抓包工具,刷新下登錄首頁,就是登錄前的cookie了

5.登錄成功后,再查看cookie變化,發現多了兩組參數,多的這兩組參數就是我們想要的,copy出來,一會有用

二、cookie組成結構
1.用抓包工具fidller只能看到cookie的name和value兩個參數,實際上cookie還有其它參數
2.以下是一個完整的cookie組成結構

cookie ={u'domain': u'.cnblogs.com',
            u'name': u'.CNBlogsCookie',
            u'value': u'xxxx',
            u'expiry': 1491887887,
            u'path': u'/',
            u'httpOnly': True,
            u'secure': False}

name:cookie的名稱
value:cookie對應的值,動態生成的
domain:服務器域名
expiry:Cookie有效終止日期
path:Path屬性定義了Web服務器上哪些路徑下的頁面可獲取服務器設置的Cookie
httpOnly:防腳本攻擊
secure:在Cookie中標記該變量,表明只有當瀏覽器和Web Server之間的通信協議為加密認證協議時,
瀏覽器才向服務器提交相應的Cookie。當前這種協議只有一種,即為HTTPS。

三、添加cookie
1.往session里面添加cookie可以用以下方式
2.set里面參數按括號里面的參數格式

coo = requests.cookies.RequestsCookieJar()  
coo.set('cookie-name''cookie-value', path='/', domain='.xxx.com')  
s.cookies.update(c) 

3.於是添加登錄的cookie,把第一步fiddler抓到的內容填進去就可以了

c = requests.cookies.RequestsCookieJar()
c.set('.CNBlogsCookie', 'xxx')
c.set('.Cnblogs.AspNetCore.Cookies','xxx')
s.cookies.update(c)
print(s.cookies)

四、參考代碼

1.由於登錄時候是多加2個cookie,我們可以先用get方法打開登錄首頁,獲取部分cookie
2.再把登錄需要的cookie添加到session里
3.添加成功后,隨便編輯正文和標題保存到草稿箱

 # coding:utf-8
import requests
# 先打開登錄首頁,獲取部分cookie
url = "https://passport.cnblogs.com/user/signin"
headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0"
           }  # get方法其它加個ser-Agent就可以了
s = requests.session()
r = s.get(url, headers=headers,verify=False)
print s.cookies
# 添加登錄需要的兩個cookie
c = requests.cookies.RequestsCookieJar()
c.set('.CNBlogsCookie', 'xxx'# 填上面抓包內容
c.set('.Cnblogs.AspNetCore.Cookies','xxx'# 填上面抓包內容
s.cookies.update(c)
print s.cookies
# 登錄成功后保存編輯內容
url2= "https://i.cnblogs.com/EditPosts.aspx?opt=1"
body = {"__VIEWSTATE": "",
        "__VIEWSTATEGENERATOR":"FE27D343",
        "Editor$Edit$txbTitle":"這是繞過登錄的標題:上海-悠悠",
        "Editor$Edit$EditorBody":"<p>這里是中文內容:http://www.cnblogs.com/yoyoketang/</p>",
        "Editor$Edit$Advanced$ckbPublished":"on",
        "Editor$Edit$Advanced$chkDisplayHomePage":"on",
        "Editor$Edit$Advanced$chkComments":"on",
        "Editor$Edit$Advanced$chkMainSyndication":"on",
        "Editor$Edit$lkbDraft":"存為草稿",
         }
r2 = s.post(url2, data=body, verify=False)
print r.content

2.8 json數據處理

前言
有些post的請求參數是json格式的,這個前面第二篇post請求里面提到過,需要導入json模塊處理。
一般常見的接口返回數據也是json格式的,我們在做判斷時候,往往只需要提取其中幾個關鍵的參數就行,這時候就需要json來解析返回的數據了。
一、json模塊簡介
1.Json簡介:Json,全名 JavaScript Object Notation,是一種輕量級的數據交換格式,常用於http請求中
2.可以用help(json),查看對應的源碼注釋內容:

Encoding basic Python object hierarchies::
        >>> import json
        >>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
        '["foo", {"bar": ["baz", null, 1.0, 2]}]'
        >>> print json.dumps("\"foo\bar")
        "\"foo\bar"
        >>> print json.dumps(u'\u1234')
        "\u1234"
        >>> print json.dumps('\\')
        "\\"
        >>> print json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)
        {"a": 0, "b": 0, "c": 0}
        >>> from StringIO import StringIO
        >>> io = StringIO()
        >>> json.dump(['streaming API'], io)
        >>> io.getvalue()
        '["streaming API"]'

二、Encode(python->json)
1.首先說下為什么要encode,python里面bool值是True和False,json里面bool值是true和false,並且區分大小寫,這就尷尬了,明明都是bool值。
在python里面寫的代碼,傳到json里,肯定識別不了,所以需要把python的代碼經過encode后成為json可識別的數據類型。
2.舉個簡單例子,下圖中dict類型經過json.dumps()后變成str,True變成了true,False變成了fasle

3.以下對應關系表是從json模塊的源碼里面爬出來的.python的數據類,經過encode成json的數據類型,對應的表如下:

     |  | Python            | JSON          |
     |  +===================+===============+
     |  | dict              | object        |
     |  +-------------------+---------------+
     |  | list, tuple       | array         |
     |  +-------------------+---------------+
     |  | str, unicode      | string        |
     |  +-------------------+---------------+
     |  | int, long, float  | number        |
     |  +-------------------+---------------+
     |  | True              | true          |
     |  +-------------------+---------------+
     |  | False             | false         |
     |  +-------------------+---------------+
     |  | None              | null          |
     |  +-------------------+---------------+

三、decode(json->python)
1.以第三篇的登錄成功結果:{"success":true}為例,我們其實最想知道的是success這個字段返回的是True還是False
2.如果以content字節輸出,返回的是一個字符串:{"success":true},這樣獲取后面那個結果就不方便了
3.如果經過json解碼后,返回的就是一個字典:{u'success': True},這樣獲取后面那個結果,就用字典的方式去取值:result2["success"]

4.同樣json數據轉化成python可識別的數據,對應的表關系如下

     |  +---------------+-------------------+
     |  | JSON          | Python            |
     |  +===============+===================+
     |  | object        | dict              |
     |  +---------------+-------------------+
     |  | array         | list              |
     |  +---------------+-------------------+
     |  | string        | unicode           |
     |  +---------------+-------------------+
     |  | number (int)  | int, long         |
     |  +---------------+-------------------+
     |  | number (real) | float             |
     |  +---------------+-------------------+
     |  | true          | True              |
     |  +---------------+-------------------+
     |  | false         | False             |
     |  +---------------+-------------------+
     |  | null          | None              |
     |  +---------------+-------------------+

四、案例分析
1.比如打開快遞網:http://www.kuaidi.com/,搜索某個單號,判斷它的狀態是不是已簽收

2. 實現代碼如下

五、參考代碼:

# coding:utf-8
import requests
url = "http://www.kuaidi.com/index-ajaxselectcourierinfo-1202247993797-yunda.html"
headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0"
           }  # get方法其它加個User-Agent就可以了
s = requests.session()
r = s.get(url, headers=headers,verify=False)
result = r.json()
data = result["data"]   # 獲取data里面內容
print data
print data[0]         # 獲取data里最上面的那個
get_result = data[0]['context'# 獲取已簽收狀態
print get_result
if u"已簽收" in get_result:
    print "快遞單已簽收成功"
else:
    print "未簽收"

2.9 重定向Location

前言
某屌絲男A鼓起勇氣向女神B打電話表白,女神B是個心機婊覺得屌絲男A是好人,不想直接拒絕於是設置呼叫轉移給閨蜜C了,最終屌絲男A和女神閨蜜C表白成功了,這種場景其實就是重定向了。
 
一、重定向
1. (Redirect)就是通過各種方法將各種網絡請求重新定個方向轉到其它位置,從地址A跳轉到地址B了。
2.重定向狀態碼:
--301 redirect: 301 代表永久性轉移(Permanently Moved)
--302 redirect: 302 代表暫時性轉移(Temporarily Moved )

3.舉個簡單的場景案例,先登錄博客園打開我的博客首頁,進我的隨筆編輯界面,記住這個地址:https://i.cnblogs.com/EditPosts.aspx?opt=1
4.退出博客園登錄,把剛才我的隨筆這個地址輸入瀏覽器回車,抓包會看到這個請求狀態碼是302,瀏覽器地址欄瞬間刷新跳到登錄首頁去了

 

 

二、禁止重定向(allow_redirects)
1.用get方法請求:https://i.cnblogs.com/EditPosts.aspx?opt=1
2.打印狀態碼是200,這是因為requets庫自動處理了重定向請求了

3.自動處理重定向地址后,我們就獲取不到重定向后的url了,就無法走下一步,這里我們可以設置一個參數禁止重定向:allow_redirects=False

(allow_redirects=True是啟動重定向),然后就可以看到status_code是302了

三、獲取重定向后地址
1.在第一個請求后,服務器會下發一個新的請求鏈接,在response的headers里,如下抓包:Location

2.用腳本去獲取Location地址

四、參考代碼:

# coding:utf-8
import requests
# 請求頭
headers = {
     "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0"
          }
s = requests.session()
# 打開我的隨筆
r = s.get('https://i.cnblogs.com/EditPosts.aspx?opt=1',
          headers=headers,
          allow_redirects=True,
          verify=False)
# 打印狀態碼,自動處理重定向請求
print r.status_code
new_url = r.headers["Location"]
print new_url

2.10 參數關聯

前言
我們用自動化發帖之后,要想接着對這篇帖子操作,那就需要用參數關聯了,發帖之后會有一個帖子的id,獲取到這個id,繼續操作傳這個帖子id就可以了
 
一、刪除草稿箱
1.我們前面講過登錄后保存草稿箱,那可以繼續接着操作:刪除剛才保存的草稿

2.用fiddler抓包,抓到刪除帖子的請求,從抓包結果可以看出,傳的json參數是postId

3.這個postId哪里來的呢?可以看上個請求url地址

4.也就是說保存草稿箱成功之后,重定向一個url地址,里面帶有postId這個參數。那接下來我們提取出來就可以了
 
二、提取參數
1.我們需要的參數postId是在保存成功后url地址,這時候從url地址提出對應的參數值就行了,先獲取保存成功后url

2.通過正則提取需要的字符串,這個參數值前面(postid=)和后面(&)字符串都是固定的
3.這里正則提出來的是list類型,取第一個值就可以是字符串了(注意:每次保存需要修改內容,不能重復)

三,傳參
1.刪除草稿箱的json參數傳上面取到的參數:{"postId": postid[0]}

2.json數據類型post里面填json就行,會自動轉json
3.接着前面的保存草稿箱操作,就可以刪除成功了

四、參考代碼

# coding:utf-8
import requests
url = "https://passport.cnblogs.com/user/signin"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0",
           "Accept": "application/json, text/javascript, */*; q=0.01",
           "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
           "Accept-Encoding": "gzip, deflate, br",
           "Content-Type": "application/json; charset=utf-8",
           "X-Requested-With": "XMLHttpRequest",
           "Content-Length": "385",
           "Cookie": "xxx已省略",
           "Connection": "keep-alive"
           }
payload = {
    "input1": "xxx",
    "input2": "xxx",
    "remember": True}
# 第一步:session登錄
s = requests.session()
r = s.post(url, json=payload, headers=headers, verify=False)
print r.json()
# 第二步:保存草稿
url2 = "https://i.cnblogs.com/EditPosts.aspx?opt=1"
body = {"__VIEWSTATE": "",
        "__VIEWSTATEGENERATOR": "FE27D343",
        "Editor$Edit$txbTitle": "這是我的標題:上海-悠悠",
        "Editor$Edit$EditorBody": "<p>這里是中文內容:http://www.cnblogs.com/yoyoketang/</p>",
        "Editor$Edit$Advanced$ckbPublished": "on",
        "Editor$Edit$Advanced$chkDisplayHomePage": "on",
        "Editor$Edit$Advanced$chkComments": "on",
        "Editor$Edit$Advanced$chkMainSyndication": "on",
        "Editor$Edit$lkbDraft": "存為草稿",
        }
r2 = s.post(url2, data=body, verify=False)
# 獲取當前url地址
print r2.url
# 第三步:正則提取需要的參數值
import re
postid = re.findall(r"postid=(.+?)&", r2.url)
print postid  # 這里是list
# 提取為字符串
print postid[0]
# 第四步:刪除草稿箱
url3 = "https://i.cnblogs.com/post/delete"
json3 = {"postId": postid[0]}
r3 = s.post(url3, json=json3, verify=False)
print r3.json()

2.11 token登錄

前言
有些登錄不是用cookie來驗證的,是用token參數來判斷是否登錄。
token傳參有兩種一種是放在請求頭里,本質上是跟cookie是一樣的,只是換個單詞而已;另外一種是在url請求參數里,這種更直觀。
 
一、登錄返回token
1.如下圖的這個登錄,無cookies

2.但是登錄成功后有返回token

二、請求頭帶token
1.登錄成功后繼續操作其它頁面,發現post請求的請求頭,都會帶token參數

2.這種請求其實比cookie更簡單,直接把登錄后的token放到頭部就行

三、token關聯

1.用腳本實現登錄,獲取token參數,獲取后傳參到請求頭就可以了
2.如果登錄有驗證碼,前面的腳本登錄步驟就省略了,自己手動登錄后獲取token

# coding:utf-8
import requests
header = {   # 登錄抓包獲取的頭部
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0",
        "Accept": "*/*",
        "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
        "Accept-Encoding": "gzip, deflate",
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        "X-Requested-With": "XMLHttpRequest",
        "Content-Length": "423",
        "Connection": "keep-alive"
        }
body = {"key1": "value1",
        "key2": "value2"# 這里賬號密碼就是抓包的數據
s = requests.session()
login_url = "http://xxx.login"   # 自己找帶token網址
login_ret = s.post(login_url, headers=header, data=body)
# 這里token在返回的json里,可以直接提取
token = login_ret.json()["token"]
# 這是登錄后發的一個post請求
post_url = "http://xxx"
# 添加token到請求頭
header["token"] = token
# 如果這個post請求的頭部其它參數變了,也可以直接更新
header["Content-Length"]="9"
body1 = {
         "key": "value"
         }
post_ret = s.post(post_url, headers=header, data=body1)
print post_ret.content

2.12登錄案例分析(csrfToken)

前言:
有些網站的登錄方式跟前面講的博客園cookies登錄和token登錄會不一樣,把csrfToken放到cookies里,登錄前后cookies是沒有任何變化的,這種情況下如何繞過前端的驗證碼登錄呢?
 
一、登錄前后對比
1.如果登錄頁面有圖形驗證碼,這種我們一般都是繞過登錄的方式,如下圖通過抓包分析,首先不輸入密碼,抓包
(由於這個是別人公司內部網站,所以網址不能公開,僅提供解決問題的思路)

2.在登錄頁面輸入賬號和密碼手動登錄后,抓包信息如下

 

3.抓包后cookies信息在登錄前后沒任何變化,這里主要有三個參數:
--businessUsername:這個是賬號名稱
--JSESSIONID: 這個是一串字符串,主要看這個會不會變(一般有有效期)copy出來就行
--csrfToken: 這個是一串字符串,主要看這個會不會變(一般有有效期)copy出來就行

二、get請求
1.像這種登錄方式的get請求,請求頭部cookie沒任何變化,這種可以直接忽略登錄,不用管登錄過程,直接發請求就行

2.代碼實現

# coding:utf-8
import requests
# 優惠券列表
url = 'http://xxx/xxx/coupon/list'
h = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
"Accept-Encoding": "gzip, deflate",
"Cookie": "csrfToken=xxx(復制抓包的信息); JSESSIONID=xxx(復制抓包的信息); businessUsername=(用戶名)",
"Connection": "keep-alive"
}
r = requests.get(url, headers=h)
print r.content

三、post請求遇到的坑
1.post請求其實也可以忽略登錄的過程,直接抓包把cookie里的三個參數(businessUsername、JSESSIONID、csrfToken)加到頭部也是可以的。

2.但是這里遇到一個坑:用Composer發請求,重定向回到登錄頁了

3.主要原因:重定向的請求,cookie參數丟失了

四、重定向
1.解決上面問題,其實很簡單,把重定向禁用(具體看2.8重定向Location這篇)后的鏈接獲取到,重新發個get請求,頭部帶上cookies的三個參數就行了

# coding:utf-8
import requests
# 主要是post請求后重定向,cookie丟失,所以回到登錄頁面了
# 解決辦法,禁止重定向,獲取重定向的url后,重新發重定向的url地址請求就行了
# 三個主要參數
csrfToken = '獲取到的csrftoken,一般有有效期的'
jsessionId = '獲取到的jsessionid'
userName = '用戶名'
url = 'http://xxx/xxxx/update'
h1 = {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
    "Accept-Encoding": "gzip, deflate",
    "Cookie": "csrfToken=%s; JSESSIONID=%s; businessUsername=%s" % (csrfToken, jsessionId, userName),
    "Connection": "keep-alive",
    "Content-Type": "application/x-www-form-urlencoded",
    "Content-Length": "115"
    }
body = {"instantMessageId":"56",
        "name": u"哈哈1",
        "order": "",
        "csrfToken": csrfToken,
        "type": "qq",
        "account": "1001"}
s = requests.session()
r1 = s.post(url, headers=h1, data=body, allow_redirects=False)
print r1.status_code
# 獲取重定向的url地址
redirect_url = r1.headers["Location"]
print redirect_url
h2 = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0",
"Accept":
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
"Accept-Encoding": "gzip, deflate",
"Cookie": "csrfToken=%s; JSESSIONID=%s; businessUsername=%s" % (csrfToken, jsessionId, userName),
"Connection": "keep-alive"
}
r2 = s.get(redirect_url, headers=h2)
print r2.content


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM