開講前,告訴大家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