標籤:

Python爬蟲學習之(一)| 從零開始

作者:xiaoyu

微信公眾號:Python數據科學


大家好,相信點進來看的小夥伴都對爬蟲非常感興趣,博主也是一樣的。博主剛開始接觸爬蟲的時候,就被深深吸引了,因為感覺SO COOL啊!每當敲完代碼後看著一串串數據在屏幕上浮動,感覺很有成就感,有木有?更厲害的是,爬蟲的技術可以應用到很多生活場景中,例如,自動投票啊,批量下載感興趣的文章、小說、視頻啊,微信機器人啊,爬取重要的數據進行數據分析啊,切實的感覺到這些代碼是給自己寫的,能為自己服務,也能為他人服務,所以人生苦短,我選爬蟲

1. 什麼是爬蟲?

首先應該弄明白一件事,就是什麼是爬蟲,為什麼要爬蟲,博主百度了一下,是這樣解釋的:

網路爬蟲(又被稱為網頁蜘蛛,網路機器人,在FOAF社區中間,更經常的稱為網頁追逐者),是一種按照一定的規則,自動地抓取萬維網信息的程序或者腳本。另外一些不常使用的名字還有螞蟻、自動索引、模擬程序或者蠕蟲。

其實,說白了就是爬蟲可以模擬瀏覽器的行為做你想做的事,訂製化自己搜索和下載的內容,並實現自動化的操作。比如瀏覽器可以下載小說,但是有時候並不能批量下載,那麼爬蟲的功能就有用武之地了。

實現爬蟲技術的編程環境有很多種,JavaPythonC++等都可以用來爬蟲。但是博主選擇了Python,相信很多人也一樣選擇Python,因為Python確實很適合做爬蟲,豐富的第三方庫十分強大,簡單幾行代碼便可實現你想要的功能,更重要的,Python也是數據挖掘和分析的好能手。這樣爬取數據和分析數據一條龍的服務都用Python真的感覺很棒啊!

2. 爬蟲學習路線

知道了什麼是爬蟲,給大家說說博主總結出的學習爬蟲的基本路線吧,只供大家參考,因為每個人都有適合自己的方法,在這裡只是提供一些思路。

學習Python爬蟲的大致步驟如下:

  • 首先學會基本的Python語法知識
  • 學習Python爬蟲常用到的幾個重要內置庫urllib, http等,用於下載網頁
  • 學習正則表達式reBeautifulSoup(bs4)、Xpath(lxml)等網頁解析工具
  • 開始一些簡單的網站爬取(博主從百度開始的,哈哈),了解爬取數據過程
  • 了解爬蟲的一些反爬機制,headerrobot時間間隔代理ip隱含欄位
  • 學習一些特殊網站的爬取,解決登錄Cookie動態網頁js模擬等問題
  • 學習selenium自動化工具,應對非同步載入頁面
  • 了解爬蟲與資料庫的結合,如何將爬取數據進行儲存, Mysql,Mongodb
  • 學習應用Python的多線程非同步,提高爬蟲效率
  • 學習爬蟲的框架,ScrapyPySpider
  • 學習redis分散式爬蟲(數據量龐大的需求)
  • 學習增量式爬蟲

以上便是一個整體的學習概況,好多內容博主也需要繼續學習,關於提到的每個步驟的細節,博主會在後續內容中以實戰的例子逐步與大家分享,當然中間也會穿插一些關於爬蟲的好玩內容。

3. 從第一個爬蟲開始

第一個爬蟲代碼的實現我想應該是從urllib開始吧,博主開始學習的時候就是使用urllib庫敲了幾行代碼就實現了簡單的爬數據功能,我想大多夥伴們也都是這麼過來的。當時的感覺就是:哇,好厲害,短短几行竟然就可以搞定一個看似很複雜的任務,於是就在想這短短的幾行代碼到底是怎麼實現的呢,如何進行更高級複雜的爬取呢?帶著這個問題我也就開始了urllib庫的學習。

首先不得不提一下爬取數據的過程,弄清楚這到底是怎樣一個過程,學習urllib的時候會更方便理解。

爬蟲的過程

其實,爬蟲的過程和瀏覽器瀏覽網頁的過程是一樣的。道理大家應該都明白,就是當我們在鍵盤上輸入網址點擊搜索之後,通過網路首先會經過DNS伺服器,分析網址的域名,找到了真正的伺服器。然後我們通過HTTP協議對伺服器發出GETPOST請求,若請求成功,我們就得到了我們想看到的網頁,一般都是用HTML, CSS, JS等前端技術來構建的,若請求不成功,伺服器會返回給我們請求失敗的狀態碼,常見到的503403等。

爬蟲的過程亦是如此,通過對伺服器發出請求得到HTML網頁,然後對下載的網頁進行解析,得到我們想要的內容。當然,這是一個爬蟲過程的一個概況,其中還有很多細節的東西需要我們處理的,這些在後續會繼續與大家分享。

了解了爬蟲的基本過程後,就可以開始我們真正的爬蟲之旅了。

urllib庫

Python有一個內置的urllib庫,可謂是爬蟲過程非常重要的一部分了。這個內置庫的使用就可以完成向伺服器發出請求並獲得網頁的功能,所以也是學習爬蟲的第一步了。

博主用的是Python3.xurllib庫的結構相對於Python2.x有一些出入,Python2.x中使用的urllib2urllib庫,而Python3.x中合併成一個唯一的urllib庫。

首先,我們來看看Python3.x的urllib庫都有什麼吧。

博主用的IDE是Pycharm,編輯調試非常方便,很贊。 在控制台下輸入如下代碼:

>>importurllib>>dir(urllib)[__builtins__,__cached__, __doc__, __file__, __loader__, __name__, __package__,__path__, __spec__, error, parse, request, response]

可以看到urllib除了以雙下劃線開頭結尾的內置屬性外,還有4個重要的屬性,分別是error,parse,request,response

在Python的urllib庫中doc開頭是這樣簡短描述的:

  • Error:「Exception classesraised by urllib.」----就是由urllib舉出的exception類
  • Parse:「Parse (absolute andrelative) URLs.」----解析絕對和相對的URLs
  • Request:「An extensiblelibrary for opening URLs using a variety of protocols」 ----用各種協議打開URLs的一個擴展庫
  • Response:「Response classesused by urllib.」----被urllib使用的response類

這4個屬性中最重要的當屬request了,它完成了爬蟲大部分的功能,我們先來看看request是怎麼用的。

request的使用

request請求最簡單的操作是用urlopen方法,代碼如下:

import urllib.requestresponse = urllib.request.urlopen(http://python.org/)result = response.read()print(result)

運行結果如下:

b<!doctype html>
<!--[if lt IE 7]>...</body>
</html>

發現得到的運行結果竟然是亂碼!!別著急,這是因為編碼的問題,我們只需要將請求的類文件讀取再解碼就可以了。

修改代碼如下:

import urllib.requestresponse = urllib.request.urlopen(http://python.org/)result = response.read().decode(utf-8)print(result)

運行結果如下:

<!doctype html><!--[if lt IE 7]> <html class="no-js ie6 lt-ie7 lt-ie8>..<!--[if IE 7]> <html class="no-js ie7 lt-ie8 lt-ie9">.. <!--[if IE 8]> <html class="no-js ie8 lt-ie9"> <![endif]--><!--[if gt IE 8]><!--><html class="no-js" lang="en" dir="ltr"<head> <meta charset="utf-8">...

得到的就是我們想要的html的網頁了,怎麼樣,簡單吧。

下面來介紹一下這個urlopen方法和其中應用的參數。

urlopen方法

def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TI MEOUT,*, cafile=None, capath=None, cadefault=False, context=None):

urlopen是request的其中一個方法,功能是打開一個URL,URL參數可以是一串字元串(如上例子中一樣),也可以是Request對象(後面會提到)。

  • url:即是我們輸入的url網址,(如:xxxx.com/);
  • data:是我們要發給伺服器請求的額外信息(比如登錄網頁需要主動填寫的用戶信息)。如果需要添加data參數,那麼是POST請求,默認無data參數時,就是GET請求;
    • 一般來講,data參數只有在http協議下請求才有意義
    • data參數被規定為byte object,也就是位元組對象
    • data參數應該使用標準的結構,這個需要使用urllib.parse.urlencode()將data進行轉換,而一般我們把data設置成字典格式再進行轉換即可;data在以後實戰中會介紹如何使用
  • timeout:是選填的內容,定義超時時間,單位是秒,防止請求時間過長,不填就是默認的時間;
  • cafile:是指向單獨文件的,包含了一系列的CA認證 (很少使用,默認即可);
  • capath:是指向文檔目標,也是用於CA認證(很少使用,默認即可);
  • cafile:可以忽略
  • context:設置SSL加密傳輸(很少使用,默認即可);

它會返回一個類文件對象,並可以針對這個對象進行各種操作(如上例中的read操作,將html全部讀出來),其它常用方法還有:

  • geturl(): 返回URL,用於看是否有重定向。

result = response.geturl()

結果: https://www.python.org/

  • info():返回元信息,例如HTTP的headers

result = response.info()

結果:

x-xss-protection: 1; mode=block

X-Clacks-Overhead: GNU Terry Pratchett

...

Vary: Cookie

Strict-Transport-Security: max-age=63072000;includeSubDomains

  • getcode():返回回復的HTTP狀態碼,成功是200,失敗可能是503等,可以用來檢查代理IP的可使用性。

result = response.getcode()

結果:200

Request方法

class Request: def __init__(self, url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None):

如上定義,Request是一個類,初始化中包括請求需要的各種參數:

  • urldata和上面urlopen中的提到的一樣。
  • headersHTTP請求的報文信息,如User_Agent參數等,它可以讓爬蟲偽裝成瀏覽器而不被伺服器發現你正在使用爬蟲。
  • origin_reg_host, unverifiable, method等不太常用

headers很有用,有些網站設有反爬蟲機制,檢查請求若沒有headers就會報錯,因此博主為保證爬蟲的穩定性,基本每次都會將headers信息加入進去,這是反爬的簡單策略之一。

那麼如何找到你所在瀏覽器的headers呢?

可以通過進入瀏覽器F12查看到 比如,博主用的Chrome瀏覽器,按F12->network就可以查看request的headers,可以把這個瀏覽器的headers信息複製下來使用。

下面來看看Request如何使用吧,代碼如下:

import urllib.requestheaders = {User_Agent: }response = urllib.request.Request(http://python.org/, headers=headers)html = urllib.request.urlopen(response)result = html.read().decode(utf-8)print(result)

結果和前面urlopen是一樣的,前面提到urlopen除了可以接受指定參數,也可以接受Request類的對象。 裡面填寫自己瀏覽器的信息即可。

urllib庫的requset屬性裡面還有很多其它方法,代理超時認證HTTP的POST模式下請求等內容將在下次進行分享,這次主要介紹基本功能。

下面來說說異常,urllib庫的error方法。

error的使用

error屬性裡面主要包括了兩個重要的exception類URLError類HTTPError類

1. URLError類

def __init__(self, reason, filename=None): self.args = reason, self.reason = reason if filename is not None: self.filename = filename

  • URLError類OSError的子類,繼承OSError,沒有自己的任何行為特點,但是將作為error裡面所有其它類型的基類使用。
  • URLError類初始化定義了reason參數,意味著當使用URLError類的對象時,可以查看錯誤的reason。

2. HTTPErro類

def __init__(self, url, code, msg, hdrs, fp): self.code = code self.msg = msg self.hdrs = hdrs self.fp = fp self.filename = url

  • HTTPErrorURLError的子類,當HTTP發生錯誤將舉出HTTPError
  • HTTPError也是HTTP有效回應的實例,因為HTTP協議錯誤是有效的回應,包括狀態碼headersbody。所以看到在HTTPError初始化的時候定義了這些有效回應的參數。
  • 當使用HTTPError類的對象時,可以查看狀態碼,headers等。

下面我們用一個例子來看一下如何使用這兩個exception類。

import urllib.requestimport urllib.errortry: headers = {User_Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0} response = urllib.request.Request(http://python.org/, headers=headers) html = urllib.request.urlopen(response) result = html.read().decode(utf-8)except urllib.error.URLError as e: if hasattr(e, reason): print(錯誤原因是 + str(e.reason))except urllib.error.HTTPError as e: if hasattr(e, code): print(錯誤狀態碼是 + str(e.code))else: print(請求成功通過。)

以上代碼使用了try..exception的結構,實現了簡單的網頁爬取,當有異常時,如URLError發生時,就會返回reason,或者HTTPError發生錯誤時就會返回code。異常的增加豐富了爬取的結構,使其更加健壯。

為什麼說更加健壯了呢?

不要小看了這些異常的錯誤,這些異常的錯誤非常好用,也非常關鍵。想想看,當你編寫一個需要不斷自動運行爬取並解析的代碼時,你是不希望程序中間被打斷而終止的。如果這些異常狀態沒有設置好,那麼就很有可能彈出錯誤而被終止,但如果設置好了完整的異常,則遇到錯誤時就會執行發生錯誤的代碼而不被打斷(比如向上面代碼一樣列印錯誤code等)。

這些打斷程序的錯誤可能是很多種,尤其當你使用代理ip池的時候,會發生很多不同錯誤,這時異常就起到作用了。

4. 總結

  • 介紹了爬蟲的定義和學習路線
  • 介紹了爬蟲的過程
  • 介紹開始爬蟲學習的urllib庫的使用,包含以下幾個方法:
  • request請求: urlopen, Request
  • error異常

關注微信公眾號Python數據科學,帶你走進數據的世界。


推薦閱讀:

利用requests爬取表情包
Python爬取拉勾網所有的職位信息(一)
case1: 爬取豆瓣top250排行榜的所有電影的信息
解讀爬蟲中HTTP的秘密(基礎篇)

TAG:python爬蟲 |