如何用 Python 爬取需要登錄的網站?

最近我必須執行一項從一個需要登錄的網站上爬取一些網頁的操作。它沒有我想象中那麼簡單,因此我決定爲它寫一個輔助教程。

在本教程中,我們將從我們的bitbucket賬戶中爬取一個項目列表。

教程中的代碼可以從我的 Github 中找到。

我們將會按照以下步驟進行:

  • 提取登錄需要的詳細信息
  • 執行站點登錄
  • 爬取所需要的數據

在本教程中,我使用了以下包(可以在 requirements.txt 中找到):

requests

lxml

步驟一:研究該網站

打開登錄頁面

進入以下頁面 “bitbucket.org/account/signin”。你會看到如下圖所示的頁面(執行註銷,以防你已經登錄)

仔細研究那些我們需要提取的詳細信息,以供登錄之用

在這一部分,我們會創建一個字典來保存執行登錄的詳細信息:

1. 右擊 “Username or email” 字段,選擇“查看元素”。我們將使用 “name” 屬性爲 “username” 的輸入框的值。“username”將會是 key 值,我們的用戶名/電子郵箱就是對應的 value 值(在其他的網站上這些 key 值可能是 “email”,“ user_name”,“ login”,等等)。

2. 右擊 “Password” 字段,選擇“查看元素”。在腳本中我們需要使用 “name” 屬性爲 “password” 的輸入框的值。“password” 將是字典的 key 值,我們輸入的密碼將是對應的 value 值(在其他網站key值可能是 “userpassword”,“loginpassword”,“pwd”,等等)。

3. 在源代碼頁面中,查找一個名爲 “csrfmiddlewaretoken” 的隱藏輸入標籤。“csrfmiddlewaretoken” 將是 key 值,而對應的 value 值將是這個隱藏的輸入值(在其他網站上這個 value 值可能是一個名爲 “csrftoken”,“ authenticationtoken” 的隱藏輸入值)。列如:“Vy00PE3Ra6aISwKBrPn72SFml00IcUV8”。

最後我們將會得到一個類似這樣的字典:

payload = {

"username": "<USER NAME>",

"password": "<PASSWORD>",

"csrfmiddlewaretoken": "<CSRF_TOKEN>"

}

請記住,這是這個網站的一個具體案例。雖然這個登錄表單很簡單,但其他網站可能需要我們檢查瀏覽器的請求日誌,並找到登錄步驟中應該使用的相關的 key 值和 value 值。

步驟2:執行登錄網站

對於這個腳本,我們只需要導入如下內容:

import requests

from lxml import html

首先,我們要創建 session 對象。這個對象會允許我們保存所有的登錄會話請求。

session_requests = requests.session()

第二,我們要從該網頁上提取在登錄時所使用的 csrf 標記。在這個例子中,我們使用的是 lxml 和 xpath 來提取,我們也可以使用正則表達式或者其他的一些方法來提取這些數據。

login_url = "https://bitbucket.org/account/signin/?next=/"

result = session_requests.get(login_url)

tree = html.fromstring(result.text)

authenticity_token = list(set(tree.xpath("//input[@name='csrfmiddlewaretoken']/@value")))[0]

更多關於xpath 和lxml的信息可以在這裏找到。

接下來,我們要執行登錄階段。在這一階段,我們發送一個 POST 請求給登錄的 url。我們使用前面步驟中創建的 payload 作爲 data 。也可以爲該請求使用一個標題並在該標題中給這個相同的 url 添加一個參照鍵。

result = session_requests.post(

login_url,

data = payload,

headers = dict(referer=login_url)

)

步驟三:爬取內容

現在,我們已經登錄成功了,我們將從 bitbucket dashboard 頁面上執行真正的爬取操作。

url = 'https://bitbucket.org/dashboard/overview'

result = session_requests.get(

url,

headers = dict(referer = url)

)

爲了測試以上內容,我們從 bitbucket dashboard 頁面上爬取了項目列表。我們將再次使用 xpath 來查找目標元素,清除新行中的文本和空格並打印出結果。如果一切都運行 OK,輸出結果應該是你 bitbucket 賬戶中的 buckets / project 列表。

tree = html.fromstring(result.content)

bucket_elems = tree.findall(".//span[@class='repo-name']/")

bucket_names = [bucket.text_content.replace("n", "").strip() for bucket inbucket_elems]

print bucket_names

你也可以通過檢查從每個請求返回的狀態代碼來驗證這些請求結果。它不會總是能讓你知道登錄階段是否是成功的,但是可以用來作爲一個驗證指標。

例如:

result.ok # 會告訴我們最後一次請求是否成功

result.status_code # 會返回給我們最後一次請求的狀態

就是這樣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章