1. 程式人生 > 其它 >移動端H5知識[系列] - “百變”盒模型

移動端H5知識[系列] - “百變”盒模型

requests介紹

#介紹:使用requests可以模擬瀏覽器的請求,比起之前用到的urllib,requests模組的api更加便捷(本質就是封裝了urllib3)

#注意:requests庫傳送請求將網頁內容下載下來以後,並不會執行js程式碼,這需要我們自己分析目標站點然後發起新的request請求

#安裝:pip3 install requests

#各種請求方式:常用的就是requests.get()和requests.post()
>>> import requests
>>> r = requests.get('https://api.github.com/events
') >>> r = requests.post('http://httpbin.org/post', data = {'key':'value'}) >>> r = requests.put('http://httpbin.org/put', data = {'key':'value'}) >>> r = requests.delete('http://httpbin.org/delete') >>> r = requests.head('http://httpbin.org/get') >>> r = requests.options('
http://httpbin.org/get') # 建議在正式學習requests前,先熟悉下HTTP協議

  官網連結:http://docs.python-requests.org/en/master/

基於GET請求

  1、基本請求

import requests
response=requests.get('http://dig.chouti.com/')
print(response.text)

  2、帶引數的GET請求->params

#在請求頭內將自己偽裝成瀏覽器,否則百度不會正常返回頁面內容
import requests
response=requests.get('https://www.baidu.com/s?wd=python&pn=1
', headers={ 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36', }) print(response.text) #如果查詢關鍵詞是中文或者有其他特殊符號,則不得不進行url編碼 from urllib.parse import urlencode wd='lqz老師' encode_res=urlencode({'k':wd},encoding='utf-8') keyword=encode_res.split('=')[1] print(keyword) # 然後拼接成url url='https://www.baidu.com/s?wd=%s&pn=1' %keyword response=requests.get(url, headers={ 'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36', }) res1=response.text
#上述操作可以用requests模組的一個params引數搞定,本質還是呼叫urlencode
from urllib.parse import urlencode
wd='lqz老師'
pn=1

response=requests.get('https://www.baidu.com/s',
                      params={
                          'wd':wd,
                          'pn':pn
                      },
                      headers={
                        'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36',
                      })
res2=response.text

#驗證結果,開啟a.html與b.html頁面內容一樣
with open('a.html','w',encoding='utf-8') as f:
    f.write(res1) 
with open('b.html', 'w', encoding='utf-8') as f:
    f.write(res2)

  3、帶引數的GET請求->headers

#通常我們在傳送請求時都需要帶上請求頭,請求頭是將自身偽裝成瀏覽器的關鍵,常見的有用的請求頭如下
Host
Referer #大型網站通常都會根據該引數判斷請求的來源
User-Agent #客戶端
Cookie #Cookie資訊雖然包含在請求頭裡,但requests模組有單獨的引數來處理他,headers={}內就不要放它了
#新增headers(瀏覽器會識別請求頭,不加可能會被拒絕訪問,比如訪問https://www.zhihu.com/explore)
import requests
response=requests.get('https://www.zhihu.com/explore')
response.status_code #500



#自己定製headers
headers={
    'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36',

}
respone=requests.get('https://www.zhihu.com/explore',
                     headers=headers)
print(respone.status_code) #200

  4、帶引數的GET請求->cookies

#登入github,然後從瀏覽器中獲取cookies,以後就可以直接拿著cookie登入了,無需輸入使用者名稱密碼


import requests

Cookies={   'user_session':'wGMHFJKgDcmRIVvcA14_Wrt_3xaUyJNsBnPbYzEL6L0bHcfc',
}

response=requests.get('https://github.com/settings/emails',
             cookies=Cookies) #github對請求頭沒有什麼限制,我們無需定製user-agent,對於其他網站可能還需要定製

print('[email protected]' in response.text) #True

  5、url編碼和解碼

    urlencode

from urllib.parse import urlencode

d = {'name': '彭于晏', 'age': 18}
res = urlencode(d)
print(res)

# 結果
# name=%E5%BD%AD%E4%BA%8E%E6%99%8F&age=18

    單獨對中文編碼和解碼

from urllib.parse import quote, unquote
# 編碼
# name='彭于晏'
# res=quote(name)
# print(res)
# 結果%E5%BD%AD%E4%BA%8E%E6%99%8F

# 解碼
s='%E5%BD%AD%E4%BA%8E%E6%99%8F'
print(unquote(s))
# 結果 彭于晏

基於POST請求

  1、介紹

#GET請求
HTTP預設的請求方法就是GET
     * 沒有請求體
     * 資料必須在1K之內!
     * GET請求資料會暴露在瀏覽器的位址列中

GET請求常用的操作:
       1. 在瀏覽器的位址列中直接給出URL,那麼就一定是GET請求
       2. 點選頁面上的超連結也一定是GET請求
       3. 提交表單時,表單預設使用GET請求,但可以設定為POST

#POST請求
(1). 資料不會出現在位址列中
(2). 資料的大小沒有上限
(3). 有請求體
(4). 請求體中如果存在中文,會使用URL編碼!

#!!!requests.post()用法與requests.get()完全一致,特殊的是requests.post()有一個data引數,用來存放請求體資料

  2、傳送post請求,模擬瀏覽器的登入行為

  對於登入來說,應該輸錯使用者名稱或密碼然後分析抓包流程,用腦子想一想,輸對了瀏覽器就跳轉了,還分析個毛線,累死你也找不到包

'''
一 目標站點分析
    瀏覽器輸入https://github.com/login
    然後輸入錯誤的賬號密碼,抓包
    發現登入行為是post提交到:https://github.com/session
    而且請求頭包含cookie
    而且請求體包含:
        commit:Sign in
        utf8:✓
        authenticity_token:lbI8IJCwGslZS8qJPnof5e7ZkCoSoMn6jmDTsL1r/m06NLyIbw7vCrpwrFAPzHMep3Tmf/TSJVoXWrvDZaVwxQ==
        login:egonlin
        password:123



二 流程分析
    先GET:https://github.com/login拿到初始cookie與authenticity_token
    返回POST:https://github.com/session, 帶上初始cookie,帶上請求體(authenticity_token,使用者名稱,密碼等)
    最後拿到登入cookie

```
ps:如果密碼時密文形式,則可以先輸錯賬號,輸對密碼,然後到瀏覽器中拿到加密後的密碼,github的密碼是明文
```

'''

import requests
import re

#第一次請求
r1=requests.get('https://github.com/login')
r1_cookie=r1.cookies.get_dict() #拿到初始cookie(未被授權)
authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #從頁面中拿到CSRF TOKEN

#第二次請求:帶著初始cookie和TOKEN傳送POST請求給登入頁面,帶上賬號密碼
data={
    'commit':'Sign in',
    'utf8':'',
    'authenticity_token':authenticity_token,
    'login':'[email protected]',
    'password':'alex3714'
}
r2=requests.post('https://github.com/session',
             data=data,
             cookies=r1_cookie
             )

login_cookie=r2.cookies.get_dict()

#第三次請求:以後的登入,拿著login_cookie就可以,比如訪問一些個人配置
r3=requests.get('https://github.com/settings/emails',
                cookies=login_cookie)

print('[email protected]' in r3.text) #True
import requests
import re

session=requests.session()
#第一次請求
r1=session.get('https://github.com/login')
authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #從頁面中拿到CSRF TOKEN

#第二次請求
data={
    'commit':'Sign in',
    'utf8':'',
    'authenticity_token':authenticity_token,
    'login':'[email protected]',
    'password':'alex3714'
}
r2=session.post('https://github.com/session',
             data=data,
             )

#第三次請求
r3=session.get('https://github.com/settings/emails')

print('[email protected]' in r3.text) #True

  3、補充

requests.post(url='xxxxxxxx',
              data={'xxx':'yyy'}) #沒有指定請求頭,#預設的請求頭:application/x-www-form-urlencoed

#如果我們自定義請求頭是application/json,並且用data傳值, 則服務端取不到值
requests.post(url='',
              data={'':1,},
              headers={
                  'content-type':'application/json'
              })

requests.post(url='',
              json={'':1,},
              ) #預設的請求頭:application/json

響應Response

  1、response屬性

import requests
respone=requests.get('http://www.jianshu.com')
# respone屬性
print(respone.text)  # 返回響應體的文字內容
print(respone.content)# 返回響應體的二進位制內容

print(respone.status_code)# 響應狀態碼
print(respone.headers)# 響應頭
print(respone.cookies)# 響應的cookie
print(respone.cookies.get_dict())# 響應的cookie轉成字典
print(respone.cookies.items())

print(respone.url) # 請求地址
print(respone.history) # 瞭解---》如果有重定向,列表,放著重定向之前的地址

print(respone.encoding) # 頁面的編碼方式:utf-8   gbk
# response.iter_content()  # content迭代取出content二進位制內容,一般用它存檔案

  2、編碼問題

#編碼問題
import requests
response=requests.get('http://www.autohome.com/news')
# response.encoding='gbk' #汽車之家網站返回的頁面內容為gb2312編碼的,而requests的預設編碼為ISO-8859-1,如果不設定成gbk則中文亂碼
print(response.text)

  3、獲取二進位制資料

import requests

response=requests.get('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1509868306530&di=712e4ef3ab258b36e9f4b48e85a81c9d&imgtype=0&src=http%3A%2F%2Fc.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F11385343fbf2b211e1fb58a1c08065380dd78e0c.jpg')

with open('a.jpg','wb') as f:
    f.write(response.content)
#stream引數:一點一點的取,比如下載視訊時,如果視訊100G,用response.content然後一下子寫到檔案中是不合理的

import requests

response=requests.get('https://gss3.baidu.com/6LZ0ej3k1Qd3ote6lo7D0j9wehsv/tieba-smallvideo-transcode/1767502_56ec685f9c7ec542eeaf6eac93a65dc7_6fe25cd1347c_3.mp4',
                      stream=True)

with open('b.mp4','wb') as f:
    for line in response.iter_content():
        f.write(line)

  4、解析json

#解析json
import requests
response=requests.get('http://httpbin.org/get')

import json
res1=json.loads(response.text) #太麻煩

res2=response.json() #直接獲取json資料

print(res1 == res2) #True

  5、Redirection and History

By default Requests will perform location redirection for all verbs except HEAD.

We can use the history property of the Response object to track redirection.

The Response.history list contains the Response objects that were created in order to complete the request. The list is sorted from the oldest to the most recent response.

For example, GitHub redirects all HTTP requests to HTTPS:

>>> r = requests.get('http://github.com')

>>> r.url
'https://github.com/'

>>> r.status_code
200

>>> r.history
[<Response [301]>]
If you're using GET, OPTIONS, POST, PUT, PATCH or DELETE, you can disable redirection handling with the allow_redirects parameter:

>>> r = requests.get('http://github.com', allow_redirects=False)

>>> r.status_code
301

>>> r.history
[]
If you're using HEAD, you can enable redirection as well:

>>> r = requests.head('http://github.com', allow_redirects=True)

>>> r.url
'https://github.com/'

>>> r.history
[<Response [301]>]
import requests
import re

#第一次請求
r1=requests.get('https://github.com/login')
r1_cookie=r1.cookies.get_dict() #拿到初始cookie(未被授權)
authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #從頁面中拿到CSRF TOKEN

#第二次請求:帶著初始cookie和TOKEN傳送POST請求給登入頁面,帶上賬號密碼
data={
    'commit':'Sign in',
    'utf8':'',
    'authenticity_token':authenticity_token,
    'login':'[email protected]',
    'password':'alex3714'
}





#測試一:沒有指定allow_redirects=False,則響應頭中出現Location就跳轉到新頁面,r2代表新頁面的response
r2=requests.post('https://github.com/session',
             data=data,
             cookies=r1_cookie
             )

print(r2.status_code) #200
print(r2.url) #看到的是跳轉後的頁面
print(r2.history) #看到的是跳轉前的response
print(r2.history[0].text) #看到的是跳轉前的response.text

#測試二:指定allow_redirects=False,則響應頭中即便出現Location也不會跳轉到新頁面,r2代表的仍然是老頁面的response
r2=requests.post('https://github.com/session',
             data=data,
             cookies=r1_cookie,
             allow_redirects=False
             )

print(r2.status_code) #302
print(r2.url) #看到的是跳轉前的頁面https://github.com/session
print(r2.history) #[]

高階用法

  1、SSL Cert Verification

#證書驗證(大部分網站都是https)
import requests
respone=requests.get('https://www.12306.cn') #如果是ssl請求,首先檢查證書是否合法,不合法則報錯,程式終端



#改進1:去掉報錯,但是會報警告
import requests
respone=requests.get('https://www.12306.cn',verify=False) #不驗證證書,報警告,返回200
print(respone.status_code)

#改進2:去掉報錯,並且去掉警報資訊
import requests
from requests.packages import urllib3
urllib3.disable_warnings() #關閉警告
respone=requests.get('https://www.12306.cn',verify=False)
print(respone.status_code)

#改進3:加上證書
#很多網站都是https,但是不用證書也可以訪問,大多數情況都是可以攜帶也可以不攜帶證書
#知乎\百度等都是可帶可不帶
#有硬性要求的,則必須帶,比如對於定向的使用者,拿到證書後才有許可權訪問某個特定網站
import requests
respone=requests.get('https://www.12306.cn',
                     cert=('/path/server.crt',
                           '/path/key'))
print(respone.status_code)

  2、使用代理

#官網連結: http://docs.python-requests.org/en/master/user/advanced/#proxies

#代理設定:先發送請求給代理,然後由代理幫忙傳送(封ip是常見的事情)
import requests
proxies={
    'http':'http://egon:123@localhost:9743',#帶使用者名稱密碼的代理,@符號前是使用者名稱與密碼
    'http':'http://localhost:9743',
    'https':'https://localhost:9743',
}
respone=requests.get('https://www.12306.cn',
                     proxies=proxies)

print(respone.status_code)



#支援socks代理,安裝:pip install requests[socks]
import requests
proxies = {
    'http': 'socks5://user:pass@host:port',
    'https': 'socks5://user:pass@host:port'
}
respone=requests.get('https://www.12306.cn',
                     proxies=proxies)

print(respone.status_code)

  3、超時設定

#超時設定
#兩種超時:float or tuple
#timeout=0.1 #代表接收資料的超時時間
#timeout=(0.1,0.2)#0.1代表連結超時  0.2代表接收資料的超時時間

import requests
respone=requests.get('https://www.baidu.com',
                     timeout=0.0001)

  4、認證設定

#官網連結:http://docs.python-requests.org/en/master/user/authentication/

#認證設定:登陸網站是,彈出一個框,要求你輸入使用者名稱密碼(與alter很類似),此時是無法獲取html的
# 但本質原理是拼接成請求頭髮送
#         r.headers['Authorization'] = _basic_auth_str(self.username, self.password)
# 一般的網站都不用預設的加密方式,都是自己寫
# 那麼我們就需要按照網站的加密方式,自己寫一個類似於_basic_auth_str的方法
# 得到加密字串後新增到請求頭
#         r.headers['Authorization'] =func('.....')

#看一看預設的加密方式吧,通常網站都不會用預設的加密設定
import requests
from requests.auth import HTTPBasicAuth
r=requests.get('xxx',auth=HTTPBasicAuth('user','password'))
print(r.status_code)

#HTTPBasicAuth可以簡寫為如下格式
import requests
r=requests.get('xxx',auth=('user','password'))
print(r.status_code)

  5、異常處理

#異常處理
import requests
from requests.exceptions import * #可以檢視requests.exceptions獲取異常型別

try:
    r=requests.get('http://www.baidu.com',timeout=0.00001)
except ReadTimeout:
    print('===:')
# except ConnectionError: #網路不通
#     print('-----')
# except Timeout:
#     print('aaaaa')

except RequestException:
    print('Error')

  6、上傳檔案

import requests
files={'file':open('a.jpg','rb')}
respone=requests.post('http://httpbin.org/post',files=files)
print(respone.status_code)