作者 | 葉庭雲
來源 | 修煉Python
頭圖 | 下載於視覺中國
爬蟲基本原理
1. URI 和 URL
URI 的全稱爲 Uniform Resource Identifier,即統一資源標誌符;URL 的全稱爲 Universal Resource Locator,即統一資源定位符。
比如Github的圖標:https://github.com/favicon.ico,它是一個 URL,也是一個 URI。即有這樣的一個圖標資源,我們用 URL/URI 來唯一指定了它的訪問方式,這其中包括了訪問協議 HTTPS、訪問路徑(即根目錄)和資源名稱 favicon.ico。通過這樣一個鏈接,我們便可以從互聯網上找到這個資源,這就是 URL/URI。
URL 是 URI 的子集,也就是說每個 URL 都是 URI,但不是每個 URI 都是 URL。那麼,什麼樣的 URI 不是 URL 呢?URI 還包括一個子類叫做 URN,它的全稱爲 Universal Resource Name,即統一資源名稱。
URN 只命名資源而不指定如何定位資源,比如 urn:isbn:0451450523 指定了一本書的 ISBN,可以唯一標識這本書,但是沒有指定到哪裏定位這本書,這就是 URN。URL、URN 和 URI 的關係可以用圖表示:
但是在目前的互聯網,URN 的使用非常少,幾乎所有的 URI 都是 URL,所以一般的網頁鏈接我們可以稱之爲 URL,也可以稱之爲 URI。
2. 超文本
超文本:Hypertext,我們在瀏覽器裏看到的網頁就是超文本解析而成的,其網頁源代碼是一系列 HTML 代碼,裏面包含了一系列標籤,比如 img 顯示圖片,p 指定顯示段落等。瀏覽器解析這些標籤後,便形成了我們平常看到的網頁,而網頁的源代碼 HTML 就可以稱作超文本。
例如,我們在 Chrome 瀏覽器裏面打開任意一個頁面,比如我的 CSDN 博客首頁,右擊任一地方並選擇 “檢查” 項(或者直接按快捷鍵 F12),即可打開瀏覽器的開發者工具,這時在 Elements 選項卡即可看到當前網頁的源代碼,這些源代碼都是超文本,如下圖所示:
3. HTTP 和 HTTPS
在我的 CSDN 博客首頁 https://yetingyun.blog.csdn.net/ 中,URL 的開頭會有 http 或 https,這個就是訪問資源需要的協議類型,有時我們還會看到 ftp、sftp、smb 開頭的URL,那麼這裏的 ftp、sftp、smb 都是指的協議類型。在寫爬蟲的時候,我們抓取的頁面通常就是 http 或 https 協議的,瞭解一下這兩個協議的含義:
HTTP 的全稱是 Hyper Text Transfer Protocol,中文名叫作超文本傳輸協議,HTTP 協議是用於從網絡傳輸超文本數據到本地瀏覽器的傳送協議,它能保證高效而準確地傳送超文本文檔。HTTP 是由萬維網協會(World Wide Web Consortium)和 Internet 工作小組 IETF(Internet Engineering Task Force)共同合作制定的規範,目前廣泛使用的是 HTTP 1.1 版本。
HTTPS 的全稱是 Hyper Text Transfer Protocol over Secure Socket Layer,是以安全爲目標的 HTTP 通道,簡單講是 HTTP 的安全版,即 HTTP 下加入 SSL 層,簡稱爲 HTTPS。
HTTPS 的安全基礎是 SSL,因此通過它傳輸的內容都是經過 SSL 加密的,它的主要作用可以分爲兩種:
建立一個信息安全通道,來保證數據傳輸的安全。
確認網站的真實性,凡是使用了 HTTPS 的網站,都可以通過點擊瀏覽器地址欄的鎖頭標誌來查看網站認證之後的真實信息,也可以通過 CA 機構頒發的安全簽章來查詢。
現在越來越多的網站和 App 都已經向 HTTPS 方向發展,例如:
騰訊微信小程序的官方需求文檔要求後臺使用 HTTPS 請求進行網絡通信,不滿足條件的域名和協議無法請求。
谷歌從 2017 年 1 月推出的 Chrome 56 開始,對未進行 HTTPS 加密的網址鏈接亮出風險提示,會在地址欄的顯著位置提醒用戶 “此網頁不安全”。
蘋果公司強制所有 iOS App 在 2017 年 1 月 1 日 前全部改爲使用 HTTPS 加密,否則 App 就無法在應用商店上架。
HTTPS 已是大勢所趨。
4. HTTP 請求過程
我們在瀏覽器中輸入一個 URL,回車之後便可以在瀏覽器中觀察到頁面內容。實際上,這個過程是瀏覽器向網站所在的服務器發送了一個請求,網站服務器接收到這個請求後進行處理和解析,然後返回對應的響應,接着傳回給瀏覽器。響應裏包含了頁面的源代碼等內容,瀏覽器再對其進行解析,便將網頁呈現了出來,傳輸模型如下圖所示:
此處客戶端即代表我們自己的 PC 或手機瀏覽器,服務器即要訪問的網站所在的服務器。
爲了更直觀地說明這個過程,這裏用 Chrome 瀏覽器的開發者模式下的 Network 監聽組件來做下演示,它可以顯示訪問當前請求網頁時發生的所有網絡請求和響應。
打開 Chrome 瀏覽器,右擊並選擇 “檢查” 項,即可打開瀏覽器的開發者工具。訪問百度 https://www.baidu.com/,輸入該 URL 後回車,觀察這個過程中發生了怎樣的網絡請求。可以看到,在 Network 頁面下方出現了一個個的條目,其中一個條目就代表一次發送請求和接收響應的過程,如下圖所示:
觀察第一個網絡請求,即 www.baidu.com,其中各列字段的的含義如下:
第一列 Name:請求的名稱,一般會將 URL 的最後一部分內容當作名稱。
第二列 Status:響應的狀態碼,這裏顯示爲 200,代表響應是正常的;通過狀態碼,我們可以判斷髮送了請求之後是否得到了正常的響應。
第三列 Type:請求的文檔類型。這裏爲 document,代表我們這次請求的是一個 HTML 文檔,內容就是一些 HTML 代碼。
第四列 Initiator:請求源。用來標記請求是由哪個對象或進程發起的。
第五列 Size:從服務器下載的文件和請求的資源大小。如果是從緩存中取得的資源,則該列會顯示 from cache。
第六列 Time:發起請求到獲取響應所用的總時間。
第七列 Waterfall:網絡請求的可視化瀑布流。
點擊進入這個條目還可以看到其更詳細的信息,如圖所示:
General 部分:Request URL 爲請求的 URL,Request Method 爲請求的方法,Status Code 爲響應狀態碼,Remote Address 爲遠程服務器的地址和端口,Referrer Policy 爲 Referrer 判別策略。
Response Headers 和 Request Headers:這分別代表響應頭和請求頭,請求頭裏帶有許多請求信息,例如瀏覽器標識、Cookies、Host 等信息,這是請求的一部分,服務器會根據請求頭內的信息判斷請求是否合法,進而作出對應的響應。圖中看到的 Response Headers 就是響應的一部分,例如其中包含了服務器的類型、文檔類型、日期等信息,瀏覽器接受到響應後,會解析響應內容,進而呈現網頁內容。
請求包含的內容如下:
請求,由客戶端向服務端發出,可以分爲 4 部分內容:請求方法(Request Method)、請求的網址(Request URL)、請求頭(Request Headers)、請求體(Request Body)。
1)請求方法
常見的請求方法有兩種:GET 和 POST
在瀏覽器中直接輸入 URL 並回車,這便發起了一個 GET 請求,請求的參數會直接包含到 URL 裏。例如,在百度中搜索 Python,這就是一個 GET 請求,鏈接爲 https://www.baidu.com/s?wd=Python,其中 URL 中包含了請求的參數信息,這裏參數 wd 表示要搜尋的關鍵字;而 POST 請求大多在表單提交時發起。比如,對於一個登錄表單,輸入用戶名和密碼後,點擊 “登錄” 按鈕,這通常會發起一個 POST 請求,其數據通常以表單的形式傳輸,而不會體現在 URL 中。
GET 和 POST 請求方法有如下區別:
GET 請求中的參數包含在 URL 裏面,數據可以在 URL 中看到,而 POST 請求的 URL 不會包含這些數據,數據都是通過表單形式傳輸的,會包含在請求體中。
GET 請求提交的數據最多隻有 1024 字節,而 POST 請求沒有限制。
一般來說,登錄時,需要提交用戶名和密碼,其中包含了敏感信息,使用 GET 方式請求的話,密碼就會暴露在 URL 裏面,造成密碼泄露,所以這裏最好以 POST 方式發送。上傳文件時,由於文件內容比較大,也會選用 POST 方式。
我們平常遇到的絕大部分請求都是 GET 或 POST 請求,另外還有一些請求方法,如 HEAD、PUT、DELETE、OPTIONS、CONNECT、TRACE 等,簡單將其總結爲下表:
請求的網址本表參考網址:http://www.runoob.com/http/http-methods.html
請求的網址,即統一資源定位符 URL,它可以唯一確定我們想請求的資源。
2)請求頭
請求頭,用來說明服務器要使用的附加信息,比較重要的信息有 Cookie、Referer、User-Agent 等。下面簡要說明一些常用的頭信息。
Cookie:也常用複數形式 Cookies,這是網站爲了辨別用戶進行會話跟蹤而存儲在用戶本地的數據,它的主要功能是維持當前訪問會話。例如:我們輸入用戶名和密碼成功登錄某個網站後,服務器會用會話保存登錄狀態信息,後面我們每次刷新或請求該站點的其他頁面時,會發現都是登錄狀態,這就是 Cookies 的作用。Cookies 中有信息標識了我們所對應的服務器的會話,每次瀏覽器在請求該站點的頁面時,都會在請求頭中加上 Cookies 並將其發送給服務器,服務器通過 Cookies 識別出是我們自己,並且查出當前狀態是登錄狀態,所以返回結果就是登錄之後才能看到的網頁內容。
Referer:此內容用來標識這個請求是從哪個頁面發過來的,服務器可以拿到這一信息並做相應的處理,如做來源統計、防盜鏈處理等。
Host:用於指定請求資源的主機 IP 和端口號,其內容爲請求 URL 的原始服務器或網關的位置。從 HTTP 1.1 版本開始,請求必須包含此內容。
User-Agent:簡稱 UA,它是一個特殊的字符串頭,可以使服務器識別客戶使用的操作系統及版本、瀏覽器及版本等信息。在做爬蟲時加上此信息,可以僞裝成瀏覽器;如果不加,很可能會被識別出爲爬蟲。
Accept:請求報頭域,用於指定客戶端可接受哪些類型的信息。
Accept-Language:指定客戶端可接受的語言類型。
Accept-Encoding:指定客戶端可接受的內容編碼。
Content-Type:也叫互聯網媒體類型(Internet Media Type)或者 MIME 類型,在 HTTP 協議消息頭中,它用來表示具體請求中的媒體類型信息。例如,text/html 代表 HTML 格式,image/gif 代表 GIF 圖片,application/json 代表 JSON 類型,更多對應關係可以查看此對照表:http://tool.oschina.net/commons。
請求頭是請求的重要組成部分,在寫爬蟲程序時,一般都需要設定請求頭。
3)請求體
請求體一般承載的內容是 POST 請求中的表單數據,而對於 GET 請求,請求體則爲空。
例如,登錄 GitHub 時捕獲到的請求和響應如圖所示:
登錄之前,我們填寫了用戶名和密碼信息,提交時這些內容就會以表單數據的形式提交給服務器,此時需要注意 Request Headers 中指定 Content-Type 爲 application/x-www-form-urlencoded。只有設置 Content-Type 爲 application/x-www-form-urlencoded,纔會以表單數據的形式提交。另外,我們也可以將 Content-Type 設置爲 application/json 來提交 JSON 數據,或者設置爲 multipart/form-data 來上傳文件。
下面表格中列出了 Content-Type 和 POST 提交數據方式的關係:
在爬蟲中,如果要構造 POST 請求,需要使用正確的 Content-Type,並瞭解各種請求庫的各個參數設置時使用的是哪種 Content-Type,不然可能會導致 POST 提交後無法得到正常響應。
4)響應狀態碼
響應狀態碼錶示服務器的響應狀態,如 200 代表服務器正常響應,404 代表頁面未找到,500 代表服務器內部發生錯誤。在爬蟲中,我們可以根據狀態碼來判斷服務器響應狀態,如狀態碼爲 200,則證明成功返回數據,再進行進一步的處理,否則直接忽略。
下表列出了常見的錯誤代碼及錯誤原因:
在寫 python 爬蟲時,我們主要通過響應體得到網頁的源代碼、JSON 數據等,然後從中提取我們想要的數據並保存下來。
Web網頁基礎
當我們用瀏覽器訪問網站時,頁面各不相同,不同網頁的有不同的基本組成、結構和節點等內容。網頁可以分爲三大部分:HTML、CSS 和 JavaScript。
1. HTML
HTML 是用來描述網頁的一種語言,其全稱爲 Hyper Text Markup Language,即超文本標記語言。
我們瀏覽的網頁包括文字、按鈕、圖片和視頻等各種複雜的元素,其基礎架構就是 HTML。不同類型的元素通過不同類型的標籤來表示,如圖片用 img 標籤表示,視頻用 video 標籤表示,段落用 p 標籤表示,它們之間的佈局又常通過佈局標籤 div 嵌套組合而成,各種標籤通過不同的排列和嵌套就可以形成網頁的框架。
我們在 Chrome 瀏覽器中打開百度,右擊並選擇 “檢查” 項(或按 F12鍵),打開開發者模式,這時在 Elements 選項卡中即可看到網頁的源代碼,如下圖所示:
這就是 HTML,整個網頁由各種標籤嵌套組合而成的。這些標籤定義的節點元素相互嵌套和組合形成複雜的層次關係,也形成了網頁的架構。
2. CSS
雖然 HTML 形成了網頁的結構,但是隻有 HTML 頁面的佈局並不美觀,可能只是簡單的節點元素的排列,爲了讓網頁看起來更好看一些,這裏就需要藉助 CSS 了。
CSS,全稱叫作 Cascading Style Sheets,即層疊樣式表。“層疊” 是指當在 HTML 中引用了數個樣式文件,並且樣式發生衝突時,瀏覽器能依據層疊順序處理。"樣式" 指網頁中文字大小、顏色、元素間距、排列等格式。
CSS 是網頁頁面排版樣式標準,有了它的幫助,頁面可以變得更爲美觀。
1#head_wrapper.s-ps-islite .s-p-top {
2 position: absolute;
3 bottom: 40px;
4 width: 100%;
5 height: 181px;
以上是一個 CSS 樣式。大花括號前面是一個 CSS 選擇器。此選擇器的作用是首先選中 id 爲 head_wrapper 且 class 爲 s-ps-islite 的節點,然後再選中其內部的 class 爲 s-p-top 的節點。
大括號內部寫的就是一條條樣式規則,例如 position 指定了這個元素的佈局方式爲絕對佈局,bottom 指定元素的下邊距爲 40 像素,width 指定了寬度爲 100% 佔滿父元素,height 則指定了元素的高度。
也就是說,我們將位置、寬度、高度等樣式配置統一寫成這樣的形式,然後用大括號括起來,接着在開頭再加上 CSS 選擇器,這就代表這個樣式對 CSS 選擇器選中的元素生效,元素就會根據此樣式來展示了。
在網頁中,一般會統一定義整個網頁的樣式規則,並寫入 CSS 文件中(其後綴爲 .css)。在 HTML 中,只需要用 link 標籤即可引入寫好的 CSS 文件,這樣可以使頁面變得更美觀、優雅。
3. JavaScript
JavaScript,簡稱 JS,是一種腳本語言。HTML 和 CSS 配合使用,提供給用戶的只是一種靜態信息,缺乏交互性。我們在網頁裏可能會看到一些交互和動畫效果,如下載進度條、提示框、輪播圖等,這通常就是 JavaScript 的功勞。它的出現使得用戶與信息之間不只是一種瀏覽與顯示的關係,而是實現了一種實時、動態、交互的頁面功能。
JavaScript 通常也是以單獨的文件形式加載的,後綴爲 .js,在 HTML 中通過 script 標籤即可引入,例如:
1<script src="jquery-2.1.0.js"></script>
小結:HTML 定義了網頁的內容和結構,CSS 描述了網頁的佈局,JavaScript 定義了網頁的行爲。
4. 網頁基本結構
瞭解了網頁的基本組成,用一個實例來感受下 HTML 的基本結構。新建一個文本文件,名稱自取,後綴爲 .html,內容如下:
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="utf-8">
5 <title>網頁基本結構</title>
6</head>
7<body>
8 <div id="container">
9 <div class="wrapper">
10 <h2 class="title">Hello World</h2>
11 <p class="text">This is a paragraph!</p>
12 <img src="./imgs/test.jpg" width="960px" height="540px">
13 </div>
14 </div>
15
16</body>
17</html>
這是一個簡單的 HTML 實例。開頭用 DOCTYPE 定義了文檔類型,其次最外層是 html 標籤,最後還有對應的結束標籤來表示閉合,其內部是 head 標籤和 body 標籤,分別代表網頁頭和網頁體,它們也需要結束標籤。
head 標籤內定義了一些頁面的配置和引用,如:<meta charset="utf-8">,它指定了網頁的編碼爲 UTF-8。title 標籤則定義了網頁的標題,會顯示在網頁的選項卡中,不會顯示在正文中。body 標籤內則是在網頁正文中顯示的內容。
div 標籤定義了網頁中的區塊,它的 id 是 container,這是一個非常常用的屬性,且 id 的內容在網頁中是唯一的,我們可以通過它來獲取這個區塊。然後在此區塊內又有一個 div 標籤,它的 class 爲 wrapper,這也是一個非常常用的屬性,經常與 CSS 配合使用來設定樣式。
然後此區塊內部又有一個 h2 標籤,這代表一個二級標題。另外,還有一個 p 標籤,這代表一個段落。在這兩者中直接寫入相應的內容即可在網頁中呈現出來,它們也有各自的 class 屬性。
通過 img 標籤插入圖片,src='圖片引用路徑',重新設置顯示網頁上顯示該圖片的寬、高
將代碼保存後,在瀏覽器中打開該文件,可以看到如下內容:
可以看到,在選項卡上顯示了 網頁基本結構 字樣,這是我們在 head 中的 title 裏定義的文字。而網頁正文是 body 標籤內部定義的各個元素生成的,可以看到這裏顯示了二級標題、段落和顯示的圖片。
這個實例可以說明網頁的一般結構。一個網頁的標準形式是 html 標籤內嵌套 head 和 body 標籤,head 內定義網頁的配置和引用,body 內定義網頁的正文。
5. CSS選擇器
網頁由一個個節點組成,CSS 選擇器會根據不同的節點設置不同的樣式規則,那麼怎樣來定位節點呢?
在 CSS 中,我們使用 CSS 選擇器來定位節點。例如,上例中 div 節點的 id 爲 container,那麼就可以表示爲 #container,其中 # 開頭代表選擇 id,其後緊跟 id 的名稱。
另外,如果我們想選擇 class 爲 wrapper 的節點,便可以使用 .wrapper,這裏以點"."開頭代表選擇 class,其後緊跟 class 的名稱。另外,還有一種選擇方式,那就是根據標籤名篩選,例如想選擇二級標題,直接用 h2 即可。這是最常用的 3 種表示,分別是根據 id、class、標籤名篩選,請牢記它們的寫法。
另外,CSS 選擇器還支持嵌套選擇,各個選擇器之間加上空格分隔開便可以代表嵌套關係,如 #container .wrapper p 則代表先選擇 id 爲 container 的節點,然後選中其內部的 class 爲 wrapper 的節點,然後再進一步選中其內部的 p 節點。
另外,如果不加空格,則代表並列關係,如 div#container .wrapper p.text 代表先選擇 id 爲 container 的 div 節點,然後選中其內部的 class 爲 wrapper 的節點,再進一步選中其內部的 class 爲 text 的 p 節點。這就是 CSS 選擇器,其篩選功能是非常強大的。
瞭解 Web 網頁的基本內容後,纔好有更加清晰的思路去解析和提取網頁內容,有利於爬蟲學習。
更多精彩推薦
☞程序員硬核“年終大掃除”,清理了數據庫 70GB 空間☞打造 AI 語音新標杆,英特爾與騰訊雲小微創新共贏
☞三種方法,用Python輕鬆提取PDF中的全部圖片
☞這25條極簡Python代碼,你還不知道
點分享點收藏點點贊點在看