路漫漫其修遠兮,吾將上下而求索

0%

爬蟲實戰 - Using Python3 Part4

Level3: 處理Session

雖然這次的目標也是有分頁,但是當切換頁面時並不像Level 2一樣是:&page=nnn 的形式

反而是透過 &page={prev,next} 這兩種值來決定要上一頁或者下一頁

題目已經很好心的告訴你我們要透過Session 來處理這題,在開始前先來聊聊Session 是什麼吧。

Session 是一種儲存在伺服端的資料, 用於儲存用戶資訊
以買飲料來舉例:

  1. A 在飲料店點了一杯飲料
  2. 店員發給了A 一張號碼牌(cookie) 並且記住A 點了什麼飲料 (session)
  3. A 拿號碼牌(cookie) 給店員,並且詢問飲料狀況
  4. 店員透過號碼牌查詢 POS 機(session) 後,確定飲料已經好了,再遞飲料給A

由上方的例子可以看出,Session 及 Cookie 是相對應的存在。

回到我們斧頭幫的網站,所以我們可以猜測伺服端的處理流程如下:

使用者連線進來,檢查 cookie 中的 PHPSESSID 是否有對應的SESSION

  • 無對應:顯示第一頁,設定 $_SESSION[‘show’] = 1
  • 有對應:檢查傳遞過來的page 參數是否為 next 或者 prev
    • 沒有page 參數:讀取 $_SESSION[‘show’] 的值,並讀取相對應的值給使用者
    • page = next,設定 $_SESSION[‘show’] += 1,讀取下一頁的內容給使用者
    • page = prev,設定 $_SESSION[‘show’] -= 1,讀取上一頁的內容給使用者

了解網站的運作流程後就能開始寫程式拉。

與前面的寫法一樣, 只要修改 main function 即可:

1
2
3
4
5
6
7
# -*- coding: utf8 -*-
from lxml import etree
import requests
def main():
pass
if __name__ == "__main__":
main()

因為當讀取第一頁時,不需要給page參數,所以我們先把第一頁的及其他頁數的查詢分開處理

1
2
3
4
5
6
7
def main():
result = requests.get("http://axe-level-1.herokuapp.com/lv3/")
result.encoding='utf-8'
cookies = result.cookies
for i in range(1, 76):
result = requests.post("http://axe-level-1.herokuapp.com/lv3/?page=next", cookies=cookies)
result.encoding = 'utf-8'

因為網站需要透過session 來處理頁面,所以我們必須把cookie 內的PHPSESSID 傳遞過去,如果不傳cookie的話,每次查詢的 ?page=next 都會是第二頁的結果,除非指定cookies,不然每次送出的post 都會是新的PHPSESSID。

流程寫好後就能開始處理資料了,我們另外寫一個parseTable 來整理資料

1
2
3
4
5
6
7
def parseTable(result):
root = etree.fromstring(result.text, etree.HTMLParser())
tmp = ""
for row in root.xpath("//table[@class='table']/tr[position()>1]"):
column = row.xpath("./td/text()")
tmp += '{"town": "%s", "village": "%s", "name": "%s"},' % (column[0], column[1], column[2])
return tmp

把全部的code 整理起來後如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# -*- coding: utf8 -*-
from lxml import etree
import requests

def main():
jsonData = '['
result = requests.get("http://axe-level-1.herokuapp.com/lv3/")
result.encoding='utf-8'
cookies = result.cookies
jsonData += retriveToJson(result.text)
for i in range(1, 76):
result = requests.post("http://axe-level-1.herokuapp.com/lv3/?page=next", cookies=cookies)
result.encoding = 'utf-8'
jsonData += retriveToJson(result.text)
print(jsonData[0:-1] + "]")

def parseTable(result):
root = etree.fromstring(result.text, etree.HTMLParser())
tmp = ""
for row in root.xpath("//table[@class='table']/tr[position()>1]"):
column = row.xpath("./td/text()")
tmp += '{"town": "%s", "village": "%s", "name": "%s"},' % (column[0], column[1], column[2])
return tmp

if __name__ == "__main__":
main()

以上就是我們第三關的處理流程。