1. 程式人生 > 實用技巧 >requests高階操作

requests高階操作

requests的Cookie處理

有時相關的需求會讓我們去爬取基於某些使用者的相關使用者資訊,例如爬取張三人人網賬戶中的個人身份資訊、好友賬號資訊等。

那麼這個時候,我們就需要對當前使用者進行登入操作,登入成功後爬取其使用者的相關使用者資訊。

在瀏覽器中我們可以很便捷的進行使用者登入操作,但是使用requests模組如何進行模擬瀏覽器行為的登入操作呢?

以爬取人人網的個人資訊為例

需求:對人人網進行模擬登入

    - 點選登入按鈕之後會發起一個post請求
- post請求中會攜帶登入之前錄入的相關的登入資訊(使用者名稱,密碼,驗證碼......)
- 驗證碼:每次請求都會變化

如果直接用requests發起請求,你會發現頁面並沒有拿到資料
沒有請求到對應頁面資料的原因:
http/https協議特性:無狀態儲存,即每一次請求之間都是獨立的。發起的第二次基於個人主頁頁面請求的時候,伺服器端並不知道該此請求是基於登入狀態下的請求。
因此就要通過會話跟蹤技術,即Cookie、Session,來讓伺服器知道使用者的狀態資訊。

無狀態HTTP

HTTP的無狀態指的是http協議對事物處理是沒有記憶能力的,也就是說伺服器不知道客戶端是什麼狀態。

當我們向伺服器傳送請求後,伺服器解析此請求,然後返回對應的響應,伺服器負責完成這個過程,而且這個過程是完全獨立的,伺服器不會記錄前後狀態的變化,也就是缺少狀態記錄。

這就意味著如果後續需要處理前面的資訊,則必須重傳,這導致需要額外傳遞一些前面的重複請求,才能獲取後續響應,然而這種效果顯然不是我們想要的。

為了保持前後狀態,我們肯定不能將前面的請求全部重傳一次,這太浪費資源了,對於這種需要使用者登入頁面來說,更是棘手。


這時兩個保持http連線狀態的技術出現了,分別是會話和cookie。會話在服務端,用來儲存使用者的會話資訊。

cookie在客戶端,有了cookie,瀏覽器在下次訪問網頁時會自動附帶上cookie傳送給伺服器,伺服器識別cookie並鑑定出是哪個使用者,然後在判斷出使用者的相關狀態,然後返回對應的響應。


會話:會話(物件)是用來儲存特定使用者進行會話所需的屬性及配置資訊的。


cookie:指的是某些網站為了辨別使用者身份、進行會話跟蹤而儲存在使用者本地終端上的資料。


會話維持:當客戶端第一次請求伺服器時,伺服器會返回一個響應物件,響應頭中帶有Set-Cookie欄位,cookie會被客戶端進行儲存,該欄位表明伺服器已經為該客戶端使用者建立了一個會話物件,用來儲存該使用者的相關屬性機器配置資訊。當瀏覽器下一次再請求該網站時,瀏覽器會把cookie放到請求頭中一起提交給伺服器,cookie中攜帶了對應會話的ID資訊,伺服器會檢查該cookie即可找到對應的會話是什麼,然後再判斷會話來以此辨別使用者狀態。


形象案例:當iphone使用者第一次向iphone的售後客服打電話諮詢相關問題時,售後客服會針對當前使用者建立一個唯一的“問題描述”,用來記錄當前使用者的iphone產品出現的相關問題,然後當用戶闡述清楚問題後,售後客服就會將問題記錄在所謂的“問題描述”中,並將“問題描述”的唯一編號通過簡訊告訴該使用者。這樣的好處就是,下次該使用者的產品再次出現問題向售後電話諮詢時,提供了“問題描述”的唯一編碼後,就不需要在將該產品之前的問題再次進行描述了。此案例中,“問題描述”就相當於是會話,“問題描述”的唯一編碼就是會話ID,簡訊就是cookie。

cookie:用來讓伺服器端記錄客戶端的相關狀態

1 . 手動處理:通過抓包工具獲取cookie值,將該值封裝到headers中。(不建議)
   2 . 自動處理:
- cookie值的來源是哪裡?
- 模擬登入post請求後,由伺服器端建立。
session會話物件:
- 作用:
1.可以進行請求的傳送。
2.如果請求過程中產生了cookie,則該cookie會被自動儲存/攜帶在該session物件中。
- 建立一個session物件:session = requests.Session()
- 使用session物件進行模擬登入post請求的傳送(cookie就會被儲存在session中)
- session物件對個人主頁對應的get請求進行傳送(攜帶了cookie)

流程分析
1.進入個人頁面,開啟抓包工具,找到含登陸資訊的包,找到應該請求的url,以及對應攜帶的引數。

2. 登陸成功後,向個人中心的url傳送請求,抓取對應的資料。

程式碼實現
驗證碼識別平臺 rec_code.py
import json
import requests
import base64
from io import BytesIO
from PIL import Image
from sys import version_info


def base64_api(uname, pwd,  img):
    img = img.convert('RGB')
    buffered = BytesIO()
    img.save(buffered, format="JPEG")
    if version_info.major >= 3:
        b64 = str(base64.b64encode(buffered.getvalue()), encoding='utf-8')
    else:
        b64 = str(base64.b64encode(buffered.getvalue()))
    data = {"username": uname, "password": pwd, "image": b64}
    result = json.loads(requests.post("http://api.ttshitu.com/base64", json=data).text)
    if result['success']:
        return result["data"]["result"]
    else:
        return result["message"]
    return ""


if __name__ == "__main__":
    img_path = "C:/Users/Administrator/Desktop/file.jpg"
    img = Image.open(img_path)
    result = base64_api(uname='你的賬號', pwd='你的密碼', img=img)
    print(result)

爬蟲檔案

import requests
from lxml import etree
from PIL import Image
from requests_highlevel import rec_code
url = 'http://www.renren.com/SysHome.do'
session = requests.Session()
# Cookie讓伺服器儲存客戶端的相關狀態
# session物件可以傳送請求 如果請求過程中產生了Cookie 會儲存在session物件中
# 則用session傳送請求就可以自動攜帶cookie
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36',
}
# 將驗證碼圖片下載到本地 page_text
= requests.get(url=url, headers=headers).text tree = etree.HTML(page_text) img_src = tree.xpath('//*[@id="verifyPic_login"]/@src')[0] img_data = requests.get(url=img_src,headers=headers).content with open('./code.jpg','wb') as f: f.write(img_data) # 利用三方平臺識別驗證碼 img_path = "code.jpg" img = Image.open(img_path)
result
= rec_code.base64_api(uname='Mrterrific', pwd='WQ2017617sxy', img=img) post_url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=2020501933720' data= { "email": "使用者名稱", "password": "密碼", "icode": result, "origURL":"http://www.renren.com/home", "domain": "renren.com", "key_id": "1", "captcha_type": "web_login", "f": "http%3A%2F%2Fwww.renren.com%2F974608874%2Fnewsfeed%2Fphoto" } response = session.post(url=post_url,data=data,headers=headers) print(response.status_code) homr_url = 'http://www.renren.com/974608874' home_text = session.get(url=url,headers=headers).text # http無狀態儲存 session攜帶了Cookie with open('home.html','w',encoding='utf-8') as f: f.write(home_text)

代理IP操作

我們在做爬蟲的過程中經常會遇到這樣的情況,最初爬蟲正常執行,正常抓取資料,一切看起來都是那麼美好,然而一杯茶的功夫可能就會出現錯誤,比如403,

這時開啟網頁一看,可能會看到“您的IP訪問頻率太高”這樣的提示。出現這種現象的原因是網站採取了一些反爬措施。

比如,伺服器會檢測某個IP在單位時間內請求的次數,如果超過了某個閾值,就會直接拒絕服務,返回一些錯誤資訊,這種情況可以稱為封IP。

既然伺服器檢測的是某個IP單位時間的請求次數,那麼藉助某種方式來偽裝我們的IP,讓伺服器識別不出是由我們本機發起的請求,不就可以成功防止封IP了嗎?一種有效的方式就是使用代理。

什麼是代理?

代理實際上指的就是代理伺服器,它的功能就是代理網路使用者去取得網路資訊。形象的說,它是網路資訊的中轉站。

在我們正常請求一個網站時,是傳送了請求給Web伺服器,Web伺服器把響應傳回我們。如果設定了代理伺服器,實際上就是在本機和伺服器之間搭建了一個橋樑,

此時本機不是直接向Web伺服器發起請求,而是向代理伺服器發出請求,請求會發送給代理伺服器,然後代理伺服器再發送給Web伺服器,接著由代理伺服器再把Web伺服器返回的響應轉發給本機。

這樣我們同樣可以正常訪問網頁,但這個過程中Web伺服器識別出的真實IP就不再是我們本機的IP了,就成功實現了IP偽裝,這就是代理的基本原理。

代理的作用

突破自身IP訪問的限制,訪問一些平時不能訪問的站點。

隱藏真實IP,免受攻擊,防止自身IP被封鎖。

相關代理網站

快代理

西祠代理

www.goubanjia.com

代理ip的型別
- http:應用到http協議對應的url中
- https:應用到https協議對應的url中

代理ip的匿名度
- 透明:伺服器知道該次請求使用了代理,也知道請求對應的真實ip
- 匿名:知道使用了代理,不知道真實ip
- 高匿:不知道使用了代理,更不知道真實的ip

import requests
import random
if __name__ == "__main__":
    #不同瀏覽器的UA
    header_list = [
        # 遨遊
        {"user-agent": "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Maxthon 2.0)"},
        # 火狐
        {"user-agent": "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"},
        # 谷歌
        {
            "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11"}
    ]
    #不同的代理IP
    proxy_list = [
        {"http": "112.115.57.20:3128"},
        {'http': '121.41.171.223:3128'}
    ]
    #隨機獲取UA和代理IP
    header = random.choice(header_list)
    proxy = random.choice(proxy_list)
    url = 'http://www.baidu.com/s?ie=UTF-8&wd=ip'
    #引數3:設定代理
    response = requests.get(url=url,headers=header,proxies=proxy)
    response.encoding = 'utf-8'
    with open('daili.html', 'wb') as fp:
        fp.write(response.content)