1. 程式人生 > >Python網絡爬蟲(一)

Python網絡爬蟲(一)

basic mar cookie ons 。。 網絡爬蟲 會話 coo 原因

Urllib發送請求

基本用法

基本的用法就是調用request庫,
class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)在編寫代碼之前把這些屬性值填寫成自己想要的參數就行了,

高級用法

將介紹“處理器“---Handler。利用它就可以處理Cookies、設置代理等任何HTTP請求中所有的事情。
首先介紹下 urllib.request 模塊裏的 BaseHandler類,它是所有其他 Handler 的父類,它提供了最基本的 Handler 的方法,例如 default_open()、protocol_request() 方法等。接下來就有各種 Handler 子類繼承這個 BaseHandler 類,舉例幾個如下:

  • HTTPDefaultErrorHandler 用於處理 HTTP 響應錯誤,錯誤都會拋出 HTTPError 類型的異常。
  • HTTPRedirectHandler 用於處理重定向。
  • HTTPCookieProcessor 用於處理 Cookies。
  • ProxyHandler 用於設置代理,默認代理為空。
  • HTTPPasswordMgr 用於管理密碼,它維護了用戶名密碼的表。
  • HTTPBasicAuthHandler 用於管理認證,如果一個鏈接打開時需要認證,那麽可以用它來解決認證問題。
    更多的Handler可以參考https://docs.python.org/3/library/urllib.request.html#basehandler-objects

    在正常的request中需要使用urlopen,而handler則是需要使用Opener,urlopen()這個方法就是Urllib為我們提供的一個Opener。

    認證

    有些網站必須要輸入用戶名和密碼,認證成功後才能繼續顯示。類似的網站比如路由器的管理員登錄界面(在瀏覽器中輸入192.168.1.1跳轉的界面)。在這裏並不是繞過登錄界面,而是在模擬請求的時候不會報錯。

from urllib.request import HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener
from urllib.error import URLError

username = 'username'
password = 'password'
url = 'http://localhost:5000/'

p = HTTPPasswordMgrWithDefaultRealm()
p.add_password(None, url, username, password)
auth_handler = HTTPBasicAuthHandler(p)
opener = build_opener(auth_handler)

try:
    result = opener.open(url)
    html = result.read().decode('utf-8')
    print(html)
except URLError as e:
    print(e.reason)

代理

設置代理

from urllib.error import URLError
from urllib.request import ProxyHandler, build_opener

proxy_handler = ProxyHandler({
    'http': 'http://127.0.0.1:9743',
    'https': 'https://127.0.0.1:9743'
})
opener = build_opener(proxy_handler)
try:
    response = opener.open('https://www.baidu.com')
    print(response.read().decode('utf-8'))
except URLError as e:
    print(e.reason)

首先花點時間介紹一下Cookies,登錄網站的時候我們常常會發現有些網站自動登錄了,而且很長時間都不會失效、有些則是需要我們重新登錄(輸入用戶模型和密碼的),這其實涉及到了Session和Cookies的相關知識。HTTP協議是一種無狀態的協議,意思是客戶端與服務端進行數據交互的時候並不會保存進行的操作,舉個例子:當我們加載網頁的一張圖片,傳過來只有半張時停止加載,我們如果不加處理的再去向服務器請求,服務端是不會記住之前傳輸的操作的,服務端所進行的操作是重新將這張圖片完整的數據重新傳輸一次。所以,HTTP 的無狀態是指 HTTP 協議對事務處理是沒有記憶能力的,也就是說服務器不知道客戶端是什麽狀態。。這點雖然避免了信息的冗余性(不會要求HTTP協議在進行數據傳輸時仍然要保存事務處理),但是對於需要用戶登錄的頁面來說,為了保持前後狀態,我們肯定不希望將前面的請求全部重傳一次,這樣過於浪費資源了,所以保持HTTP連接狀態的技術就出現了。Session在服務端(網站的服務器),用於保存用戶的會話信息,Cookies在客戶端。服務器通過識別 Cookies 並鑒定出是哪個用戶,然後再判斷用戶是否是登錄狀態,然後返回對應的 Response。所以,我們可以這樣理解:如果我們將一次登陸成功後的Cookies放在Request Headers裏面直接請求服務端,就不必重新模擬登陸了。
當瀏覽器下一次再請求該網站時,瀏覽器會把此Cookies 放到 Request Headers 一起提交給服務器,Cookies 攜帶了 Session ID 信息,服務器檢查該 Cookies 即可找到對應的 Session 是什麽,然後再判斷 Session 來以此來辨認用戶狀態。所以我們在登錄某個網站的時候,登錄成功後服務器會告訴客戶端設置哪些 Cookies 信息,在後續訪問頁面時客戶端會把 Cookies 發送給服務器,服務器再找到對應的 Session 加以判斷,如果 Session 中的某些設置登錄狀態的變量是有效的,那就證明用戶是處於登錄狀態的,即可返回登錄之後才可以查看的網頁內容,瀏覽器進行解析便可以看到了。
好了,下面我們介紹python中與Cookies相關的Handler,首先將網站的Cookies獲取下來:

import http.cookiejar, urllib.request

cookie = http.cookiejar.CookieJar()    #申明一個CookieJar對象
handler = urllib.request.HTTPCookieProcessor(cookie) #創建Handler
opener = urllib.request.build_opener(handler)   #構建出Opener
response = opener.open('http://www.baidu.com')  #執行open()函數
for item in cookie:
    print(item.name+"="+item.value)

執行的結果如下:

BAIDUID=2E65A683F8A8BA3DF521469DF8EFF1E1:FG=1
BIDUPSID=2E65A683F8A8BA3DF521469DF8EFF1E1
H_PS_PSSID=20987_1421_18282_17949_21122_17001_21227_21189_21161_20927
PSTM=1474900615
BDSVRTM=0
BD_HOME=0

以上就是Cookies的完整樣貌,我們可以將這個Cookie保存下來方便我們後面調用:

filename = 'cookies.txt'
#cookie = http.cookiejar.MozillaCookieJar(filename)
cookie = http.cookiejar.LWPCookieJar(filename)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
cookie.save(ignore_discard=True, ignore_expires=True)

這時的 CookieJar就需要換成 MozillaCookieJar,生成文件時需要用到它,它是 CookieJar 的子類,可以用來處理 Cookies 和文件相關的事件,讀取和保存 Cookies,它可以將 Cookies 保存成 Mozilla 型瀏覽器的 Cookies 的格式。
生成的cookies.txt文件如下:

#LWP-Cookies-2.0
Set-Cookie3: BAIDUID="0CE9C56F598E69DB375B7C294AE5C591:FG=1"; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2084-10-14 18:25:19Z"; version=0
Set-Cookie3: BIDUPSID=0CE9C56F598E69DB375B7C294AE5C591; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2084-10-14 18:25:19Z"; version=0
Set-Cookie3: H_PS_PSSID=20048_1448_18240_17944_21089_21192_21161_20929; path="/"; domain=".baidu.com"; path_spec; domain_dot; discard; version=0
Set-Cookie3: PSTM=1474902671; path="/"; domain=".baidu.com"; path_spec; domain_dot; expires="2084-10-14 18:25:19Z"; version=0
Set-Cookie3: BDSVRTM=0; path="/"; domain="www.baidu.com"; path_spec; discard; version=0
Set-Cookie3: BD_HOME=0; path="/"; domain="www.baidu.com"; path_spec; discard; version=0

接下來利用Cookies的LWPCookieJar格式來讀取文件:

cookie = http.cookiejar.LWPCookieJar()
cookie.load('cookies.txt', ignore_discard=True, ignore_expires=True)
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open('http://www.baidu.com')
print(response.read().decode('utf-8')

Urllib處理異常

在跑程序獲取數據中,如果程序中途遇到錯誤而我們沒有寫異常處理的時候,盡可能辛辛苦苦跑的數據就損失了;在獲取豆瓣電影top250的時候,部分電影的參數不完整,導致爬蟲總是會在這中途出現錯誤。。。更有可能的是,如果網絡情況突然變更,要做異常處理,是的網絡恢復的時候能繼續運行程序。綜上,寫異常處理真的非常重要!!

HTTPError

  • code,返回 HTTP Status Code,即狀態碼,比如 404 網頁不存在,500 服務器內部錯誤等等。
  • reason,同父類一樣,返回錯誤的原因。
  • headers,返回 Request Headers。
from urllib import request,error
try:
    response = request.urlopen('http://沒有這個頁面.com/index.htm')
except error.HTTPError as e:
    print(e.reason, e.code, e.headers, seq='\n')

Python網絡爬蟲(一)