爬蟲(爬蟲原理和數據抓取)

通用爬蟲和聚焦爬蟲

根據使用場景,網絡爬蟲可分為 通用爬蟲 和 聚焦爬蟲 兩種.

通用爬蟲

通用網絡爬蟲 是 捜索引擎抓取系統(Baidu、Google、Yahoo等)的重要組成部分。主要目的是將互聯網上的網頁下載到本地,形成一個互聯網內容的鏡像備份。

通用搜索引擎(Search Engine)工作原理

通用網絡爬蟲 從互聯網中搜集網頁,采集信息,這些網頁信息用于為搜索引擎建立索引從而提供支持,它決定著整個引擎系統的內容是否豐富,信息是否即時,因此其性能的優劣直接影響著搜索引擎的效果。

第一步:抓取網頁

搜索引擎網絡爬蟲的基本工作流程如下:

  1. 首先選取一部分的種子URL,將這些URL放入待抓取URL隊列;

  2. 取出待抓取URL,解析DNS得到主機的IP,并將URL對應的網頁下載下來,存儲進已下載網頁庫中,并且將這些URL放進已抓取URL隊列。

  3. 分析已抓取URL隊列中的URL,分析其中的其他URL,并且將URL放入待抓取URL隊列,從而進入下一個循環....

[圖片上傳失敗...(image-7a4383-1599745420885)]

image
搜索引擎如何獲取一個新網站的URL:
1. 新網站向搜索引擎主動提交網址:(如百度http://zhanzhang.baidu.com/linksubmit/url
2. 在其他網站上設置新網站外鏈(盡可能處于搜索引擎爬蟲爬取范圍)
3. 搜索引擎和DNS解析服務商(如DNSPod等)合作,新網站域名將被迅速抓取。

但是搜索引擎蜘蛛的爬行是被輸入了一定的規則的,它需要遵從一些命令或文件的內容,如標注為nofollow的鏈接,或者是Robots協議。

Robots協議(也叫爬蟲協議、機器人協議等),全稱是“網絡爬蟲排除標準”(Robots Exclusion Protocol),網站通過Robots協議告訴搜索引擎哪些頁面可以抓取,哪些頁面不能抓取,例如:

淘寶網:https://www.taobao.com/robots.txt

騰訊網: http://www.qq.com/robots.txt

第二步:數據存儲

搜索引擎通過爬蟲爬取到的網頁,將數據存入原始頁面數據庫。其中的頁面數據與用戶瀏覽器得到的HTML是完全一樣的。

搜索引擎蜘蛛在抓取頁面時,也做一定的重復內容檢測,一旦遇到訪問權重很低的網站上有大量抄襲、采集或者復制的內容,很可能就不再爬行。

第三步:預處理

搜索引擎將爬蟲抓取回來的頁面,進行各種步驟的預處理。

  • 提取文字
  • 中文分詞
  • 消除噪音(比如版權聲明文字、導航條、廣告等……)
  • 索引處理
  • 鏈接關系計算
  • 特殊文件處理
  • ....

除了HTML文件外,搜索引擎通常還能抓取和索引以文字為基礎的多種文件類型,如 PDF、Word、WPS、XLS、PPT、TXT 文件等。我們在搜索結果中也經常會看到這些文件類型。

但搜索引擎還不能處理圖片、視頻、Flash 這類非文字內容,也不能執行腳本和程序。

第四步:提供檢索服務,網站排名

搜索引擎在對信息進行組織和處理后,為用戶提供關鍵字檢索服務,將用戶檢索相關的信息展示給用戶。

同時會根據頁面的PageRank值(鏈接的訪問量排名)來進行網站排名,這樣Rank值高的網站在搜索結果中會排名較前,當然也可以直接使用 Money 購買搜索引擎網站排名,簡單粗暴。

[圖片上傳失敗...(image-41a646-1599745420884)]

image

但是,這些通用性搜索引擎也存在著一定的局限性:

  1. 通用搜索引擎所返回的結果都是網頁,而大多情況下,網頁里90%的內容對用戶來說都是無用的。

  2. 不同領域、不同背景的用戶往往具有不同的檢索目的和需求,搜索引擎無法提供針對具體某個用戶的搜索結果。

  3. 萬維網數據形式的豐富和網絡技術的不斷發展,圖片、數據庫、音頻、視頻多媒體等不同數據大量出現,通用搜索引擎對這些文件無能為力,不能很好地發現和獲取。

  4. 通用搜索引擎大多提供基于關鍵字的檢索,難以支持根據語義信息提出的查詢,無法準確理解用戶的具體需求。

針對這些情況,聚焦爬蟲技術得以廣泛使用。

聚焦爬蟲

聚焦爬蟲,是"面向特定主題需求"的一種網絡爬蟲程序,它與通用搜索引擎爬蟲的區別在于: 聚焦爬蟲在實施網頁抓取時會對內容進行處理篩選,盡量保證只抓取與需求相關的網頁信息。

而我們今后要學習的,就是聚焦爬蟲。

HTTP和HTTPS

HTTP協議(HyperText Transfer Protocol,超文本傳輸協議):是一種發布和接收 HTML頁面的方法。

HTTPS(Hypertext Transfer Protocol over Secure Socket Layer)簡單講是HTTP的安全版,在HTTP下加入SSL層。

SSL(Secure Sockets Layer 安全套接層)主要用于Web的安全傳輸協議,在傳輸層對網絡連接進行加密,保障在Internet上數據傳輸的安全。

  • HTTP的端口號為80
  • HTTPS的端口號為443

HTTP工作原理

網絡爬蟲抓取過程可以理解為模擬瀏覽器操作的過程

瀏覽器的主要功能是向服務器發出請求,在瀏覽器窗口中展示您選擇的網絡資源,HTTP是一套計算機通過網絡進行通信的規則。

HTTP的請求與響應

HTTP通信由兩部分組成: 客戶端請求消息 與 服務器響應消息

image

[圖片上傳失敗...(image-bc7496-1599745459627)]

瀏覽器發送HTTP請求的過程:

  1. 當用戶在瀏覽器的地址欄中輸入一個URL并按回車鍵之后,瀏覽器會向HTTP服務器發送HTTP請求。HTTP請求主要分為“Get”和“Post”兩種方法。

  2. 當我們在瀏覽器輸入URL http://www.baidu.com 的時候,瀏覽器發送一個Request請求去獲取 http://www.baidu.com 的html文件,服務器把Response文件對象發送回給瀏覽器。

  3. 瀏覽器分析Response中的 HTML,發現其中引用了很多其他文件,比如Images文件,CSS文件,JS文件。 瀏覽器會自動再次發送Request去獲取圖片,CSS文件,或者JS文件。

  4. 當所有的文件都下載成功后,網頁會根據HTML語法結構,完整的顯示出來了。

URL(Uniform / Universal Resource Locator的縮寫):統一資源定位符,是用于完整地描述Internet上網頁和其他資源的地址的一種標識方法。

image

[圖片上傳失敗...(image-38fa96-1599745459627)]

基本格式:scheme://host[:port#]/path/…/[?query-string][#anchor]

  • scheme:協議(例如:http, https, ftp)
  • host:服務器的IP地址或者域名
  • port#:服務器的端口(如果是走協議默認端口,缺省端口80)
  • path:訪問資源的路徑
  • query-string:參數,發送給http服務器的數據
  • anchor:錨(跳轉到網頁的指定錨點位置)

例如:

客戶端HTTP請求

URL只是標識資源的位置,而HTTP是用來提交和獲取資源。客戶端發送一個HTTP請求到服務器的請求消息,包括以下格式:

請求行請求頭部空行請求數據

四個部分組成,下圖給出了請求報文的一般格式。

image

[圖片上傳失敗...(image-cf840f-1599745459626)]

一個典型的HTTP請求示例
GET https://www.baidu.com/ HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: http://www.baidu.com/
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
Cookie: BAIDUID=04E4001F34EA74AD4601512DD3C41A7B:FG=1; BIDUPSID=04E4001F34EA74AD4601512DD3C41A7B; PSTM=1470329258; MCITY=-343%3A340%3A; BDUSS=nF0MVFiMTVLcUh-Q2MxQ0M3STZGQUZ4N2hBa1FFRkIzUDI3QlBCZjg5cFdOd1pZQVFBQUFBJCQAAAAAAAAAAAEAAADpLvgG0KGyvLrcyfrG-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFaq3ldWqt5XN; H_PS_PSSID=1447_18240_21105_21386_21454_21409_21554; BD_UPN=12314753; sug=3; sugstore=0; ORIGIN=0; bdime=0; H_PS_645EC=7e2ad3QHl181NSPbFbd7PRUCE1LlufzxrcFmwYin0E6b%2BW8bbTMKHZbDP0g; BDSVRTM=0

請求方法

GET https://www.baidu.com/ HTTP/1.1

根據HTTP標準,HTTP請求可以使用多種請求方法。

HTTP 0.9:只有基本的文本 GET 功能。

HTTP 1.0:完善的請求/響應模型,并將協議補充完整,定義了三種請求方法: GET, POST 和 HEAD方法。

HTTP 1.1:在 1.0 基礎上進行更新,新增了五種請求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。

HTTP 2.0(未普及):請求/響應首部的定義基本沒有改變,只是所有首部鍵必須全部小寫,而且請求行要獨立為 :method、:scheme、:host、:path這些鍵值對。

序號 方法 描述
1 GET 請求指定的頁面信息,并返回實體主體。
2 HEAD 類似于get請求,只不過返回的響應中沒有具體的內容,用于獲取報頭
3 POST 向指定資源提交數據進行處理請求(例如提交表單或者上傳文件),數據被包含在請求體中。POST請求可能會導致新的資源的建立和/或已有資源的修改。
4 PUT 從客戶端向服務器傳送的數據取代指定的文檔的內容。
5 DELETE 請求服務器刪除指定的頁面。
6 CONNECT HTTP/1.1協議中預留給能夠將連接改為管道方式的代理服務器。
7 OPTIONS 允許客戶端查看服務器的性能。
8 TRACE 回顯服務器收到的請求,主要用于測試或診斷。

HTTP請求主要分為GetPost兩種方法

  • GET是從服務器上獲取數據,POST是向服務器傳送數據

  • GET請求參數顯示,都顯示在瀏覽器網址上,HTTP服務器根據該請求所包含URL中的參數來產生響應內容,即“Get”請求的參數是URL的一部分。 例如: http://www.baidu.com/s?wd=Chinese

  • POST請求參數在請求體當中,消息長度沒有限制而且以隱式的方式進行發送,通常用來向HTTP服務器提交量比較大的數據(比如請求中包含許多參數或者文件上傳操作等),請求的參數包含在“Content-Type”消息頭里,指明該消息體的媒體類型和編碼,

注意:避免使用Get方式提交表單,因為有可能會導致安全問題。 比如說在登陸表單中用Get方式,用戶輸入的用戶名和密碼將在地址欄中暴露無遺。

常用的請求報頭

1. Host (主機和端口號)

Host:對應網址URL中的Web名稱和端口號,用于指定被請求資源的Internet主機和端口號,通常屬于URL的一部分。

2. Connection (鏈接類型)

Connection:表示客戶端與服務連接類型

  1. Client 發起一個包含 Connection:keep-alive 的請求,HTTP/1.1使用 keep-alive 為默認值。

  2. Server收到請求后:

    • 如果 Server 支持 keep-alive,回復一個包含 Connection:keep-alive 的響應,不關閉連接;
    • 如果 Server 不支持 keep-alive,回復一個包含 Connection:close 的響應,關閉連接。
  3. 如果client收到包含 Connection:keep-alive 的響應,向同一個連接發送下一個請求,直到一方主動關閉連接。

keep-alive在很多情況下能夠重用連接,減少資源消耗,縮短響應時間,比如當瀏覽器需要多個文件時(比如一個HTML文件和相關的圖形文件),不需要每次都去請求建立連接。

3. Upgrade-Insecure-Requests (升級為HTTPS請求)

Upgrade-Insecure-Requests:升級不安全的請求,意思是會在加載 http 資源時自動替換成 https 請求,讓瀏覽器不再顯示https頁面中的http請求警報。

HTTPS 是以安全為目標的 HTTP 通道,所以在 HTTPS 承載的頁面上不允許出現 HTTP 請求,一旦出現就是提示或報錯。

4. User-Agent (瀏覽器名稱)

User-Agent:是客戶瀏覽器的名稱,以后會詳細講。

5. Accept (傳輸文件類型)

Accept:指瀏覽器或其他客戶端可以接受的MIME(Multipurpose Internet Mail Extensions(多用途互聯網郵件擴展))文件類型,服務器可以根據它判斷并返回適當的文件格式。

舉例:

Accept: */*:表示什么都可以接收。

Accept:image/gif:表明客戶端希望接受GIF圖像格式的資源;

Accept:text/html:表明客戶端希望接受html文本。

Accept: text/html, application/xhtml+xml;q=0.9, image/*;q=0.8:表示瀏覽器支持的 MIME 類型分別是 html文本、xhtml和xml文檔、所有的圖像格式資源。

q是權重系數,范圍 0 =< q <= 1,q 值越大,請求越傾向于獲得其“;”之前的類型表示的內容。若沒有指定q值,則默認為1,按從左到右排序順序;若被賦值為0,則用于表示瀏覽器不接受此內容類型。

Text:用于標準化地表示的文本信息,文本消息可以是多種字符集和或者多種格式的;Application:用于傳輸應用程序數據或者二進制數據。詳細請點擊

6. Referer (頁面跳轉處)

Referer:表明產生請求的網頁來自于哪個URL,用戶是從該 Referer頁面訪問到當前請求的頁面。這個屬性可以用來跟蹤Web請求來自哪個頁面,是從什么網站來的等。

有時候遇到下載某網站圖片,需要對應的referer,否則無法下載圖片,那是因為人家做了防盜鏈,原理就是根據referer去判斷是否是本網站的地址,如果不是,則拒絕,如果是,就可以下載;

7. Accept-Encoding(文件編解碼格式)

Accept-Encoding:指出瀏覽器可以接受的編碼方式。編碼方式不同于文件格式,它是為了壓縮文件并加速文件傳遞速度。瀏覽器在接收到Web響應之后先解碼,然后再檢查文件格式,許多情形下這可以減少大量的下載時間。

舉例:Accept-Encoding:gzip;q=1.0, identity; q=0.5, *;q=0

如果有多個Encoding同時匹配, 按照q值順序排列,本例中按順序支持 gzip, identity壓縮編碼,支持gzip的瀏覽器會返回經過gzip編碼的HTML頁面。 如果請求消息中沒有設置這個域服務器假定客戶端對各種內容編碼都可以接受。

8. Accept-Language(語言種類)

Accept-Langeuage:指出瀏覽器可以接受的語言種類,如en或en-us指英語,zh或者zh-cn指中文,當服務器能夠提供一種以上的語言版本時要用到。

9. Accept-Charset(字符編碼)

Accept-Charset:指出瀏覽器可以接受的字符編碼。

舉例:Accept-Charset:iso-8859-1,gb2312,utf-8
  • ISO8859-1:通常叫做Latin-1。Latin-1包括了書寫所有西方歐洲語言不可缺少的附加字符,英文瀏覽器的默認值是ISO-8859-1.
  • gb2312:標準簡體中文字符集;
  • utf-8:UNICODE 的一種變長字符編碼,可以解決多種語言文本顯示問題,從而實現應用國際化和本地化。

如果在請求消息中沒有設置這個域,缺省是任何字符集都可以接受。

10. Cookie (Cookie)

Cookie:瀏覽器用這個屬性向服務器發送Cookie。Cookie是在瀏覽器中寄存的小型數據體,它可以記載和服務器相關的用戶信息,也可以用來實現會話功能,以后會詳細講。

11. Content-Type (POST數據類型)

Content-Type:POST請求里用來表示的內容類型。

舉例:Content-Type = Text/XML; charset=gb2312:

指明該請求的消息體中包含的是純文本的XML類型的數據,字符編碼采用“gb2312”。

服務端HTTP響應

HTTP響應也由四個部分組成,分別是: 狀態行消息報頭空行響應正文

[圖片上傳失敗...(image-a8d073-1599745493447)]

HTTP/1.1 200 OK
Server: Tengine
Connection: keep-alive
Date: Wed, 30 Nov 2016 07:58:21 GMT
Cache-Control: no-cache
Content-Type: text/html;charset=UTF-8
Keep-Alive: timeout=20
Vary: Accept-Encoding
Pragma: no-cache
X-NWS-LOG-UUID: bd27210a-24e5-4740-8f6c-25dbafa9c395
Content-Length: 180945

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ....

常用的響應報頭(了解)

理論上所有的響應頭信息都應該是回應請求頭的。但是服務端為了效率,安全,還有其他方面的考慮,會添加相對應的響應頭信息,從上圖可以看到:

1. Cache-Control:must-revalidate, no-cache, private。

這個值告訴客戶端,服務端不希望客戶端緩存資源,在下次請求資源時,必須要從新請求服務器,不能從緩存副本中獲取資源。

  • Cache-Control是響應頭中很重要的信息,當客戶端請求頭中包含Cache-Control:max-age=0請求,明確表示不會緩存服務器資源時,Cache-Control作為作為回應信息,通常會返回no-cache,意思就是說,"那就不緩存唄"。

  • 當客戶端在請求頭中沒有包含Cache-Control時,服務端往往會定,不同的資源不同的緩存策略,比如說oschina在緩存圖片資源的策略就是Cache-Control:max-age=86400,這個意思是,從當前時間開始,在86400秒的時間內,客戶端可以直接從緩存副本中讀取資源,而不需要向服務器請求。

2. Connection:keep-alive

這個字段作為回應客戶端的Connection:keep-alive,告訴客戶端服務器的tcp連接也是一個長連接,客戶端可以繼續使用這個tcp連接發送http請求。

3. Content-Encoding:gzip

告訴客戶端,服務端發送的資源是采用gzip編碼的,客戶端看到這個信息后,應該采用gzip對資源進行解碼。

4. Content-Type:text/html;charset=UTF-8

告訴客戶端,資源文件的類型,還有字符編碼,客戶端通過utf-8對資源進行解碼,然后對資源進行html解析。通常我們會看到有些網站是亂碼的,往往就是服務器端沒有返回正確的編碼。

5. Date:Sun, 21 Sep 2016 06:18:21 GMT

這個是服務端發送資源時的服務器時間,GMT是格林尼治所在地的標準時間。http協議中發送的時間都是GMT的,這主要是解決在互聯網上,不同時區在相互請求資源的時候,時間混亂問題。

6. Expires:Sun, 1 Jan 2000 01:00:00 GMT

這個響應頭也是跟緩存有關的,告訴客戶端在這個時間前,可以直接訪問緩存副本,很顯然這個值會存在問題,因為客戶端和服務器的時間不一定會都是相同的,如果時間不同就會導致問題。所以這個響應頭是沒有Cache-Control:max-age=*這個響應頭準確的,因為max-age=date中的date是個相對時間,不僅更好理解,也更準確。

7. Pragma:no-cache

這個含義與Cache-Control等同。

8.Server:Tengine/1.4.6

這個是服務器和相對應的版本,只是告訴客戶端服務器的信息。

9. Transfer-Encoding:chunked

這個響應頭告訴客戶端,服務器發送的資源的方式是分塊發送的。一般分塊發送的資源都是服務器動態生成的,在發送時還不知道發送資源的大小,所以采用分塊發送,每一塊都是獨立的,獨立的塊都能標示自己的長度,最后一塊是0長度的,當客戶端讀到這個0長度的塊時,就可以確定資源已經傳輸完了。

10. Vary: Accept-Encoding

告訴緩存服務器,緩存壓縮文件和非壓縮文件兩個版本,現在這個字段用處并不大,因為現在的瀏覽器都是支持壓縮的。

響應狀態碼

響應狀態代碼有三位數字組成,第一個數字定義了響應的類別,且有五種可能取值。

常見狀態碼:

  • 100~199:表示服務器成功接收部分請求,要求客戶端繼續提交其余請求才能完成整個處理過程。

  • 200~299:表示服務器成功接收請求并已完成整個處理過程。常用200(OK 請求成功)。

  • 300~399:為完成請求,客戶需進一步細化請求。例如:請求的資源已經移動一個新地址、常用302(所請求的頁面已經臨時轉移至新的url)、307和304(使用緩存資源)。

  • 400~499:客戶端的請求有錯誤,常用404(服務器無法找到被請求的頁面)、403(服務器拒絕訪問,權限不夠)。

  • 500~599:服務器端出現錯誤,常用500(請求未完成。服務器遇到不可預知的情況)。

Cookie 和 Session:

服務器和客戶端的交互僅限于請求/響應過程,結束之后便斷開,在下一次請求時,服務器會認為新的客戶端。

為了維護他們之間的鏈接,讓服務器知道這是前一個用戶發送的請求,必須在一個地方保存客戶端的信息。

Cookie:通過在 客戶端 記錄的信息確定用戶的身份。

Session:通過在 服務器端 記錄的信息確定用戶的身份。

Fiddler界面

設置好后,本機HTTP通信都會經過127.0.0.1:8888代理,也就會被Fiddler攔截到。

image

[圖片上傳失敗...(image-7cb0dd-1599745493447)]

請求 (Request) 部分詳解

  1. Headers —— 顯示客戶端發送到服務器的 HTTP 請求的 header,顯示為一個分級視圖,包含了 Web 客戶端信息、Cookie、傳輸狀態等。
  2. Textview —— 顯示 POST 請求的 body 部分為文本。
  3. WebForms —— 顯示請求的 GET 參數 和 POST body 內容。
  4. HexView —— 用十六進制數據顯示請求。
  5. Auth —— 顯示響應 header 中的 Proxy-Authorization(代理身份驗證) 和 Authorization(授權) 信息.
  6. Raw —— 將整個請求顯示為純文本。
  7. JSON - 顯示JSON格式文件。
  8. XML —— 如果請求的 body 是 XML 格式,就是用分級的 XML 樹來顯示它。

響應 (Response) 部分詳解

  1. Transformer —— 顯示響應的編碼信息。
  2. Headers —— 用分級視圖顯示響應的 header。
  3. TextView —— 使用文本顯示相應的 body。
  4. ImageVies —— 如果請求是圖片資源,顯示響應的圖片。
  5. HexView —— 用十六進制數據顯示響應。
  6. WebView —— 響應在 Web 瀏覽器中的預覽效果。
  7. Auth —— 顯示響應 header 中的 Proxy-Authorization(代理身份驗證) 和 Authorization(授權) 信息。
  8. Caching —— 顯示此請求的緩存信息。
  9. Privacy —— 顯示此請求的私密 (P3P) 信息。
  10. Raw —— 將整個響應顯示為純文本。
  11. JSON - 顯示JSON格式文件。
  12. XML —— 如果響應的 body 是 XML 格式,就是用分級的 XML 樹來顯示它 。

HTTP/HTTPS的GETPOST方法

urllib.parse.urlencode()

# IPython 中的測試結果
In [1]: import urllib.parse

In [2]: word = {"wd" : "傳智播客"}

# 通過urllib.parse.urlencode()方法,將字典鍵值對按URL編碼轉換,從而能被web服務器接受。
In [3]: urllib..parse.urlencode(word)  
Out[3]: "wd=%E4%BC%A0%E6%99%BA%E6%92%AD%E5%AE%A2"

# 通過urllib.parse.unquote()方法,把 URL編碼字符串,轉換回原先字符串。
In [4]: print (urllib.parse.unquote("wd=%E4%BC%A0%E6%99%BA%E6%92%AD%E5%AE%A2"))
wd=傳智播客

一般HTTP請求提交數據,需要編碼成 URL編碼格式,然后做為url的一部分,或者作為參數傳到Request對象中。

Get方式

GET請求一般用于我們向服務器獲取數據,比如說,我們用百度搜索傳智播客https://www.baidu.com/s?wd=傳智播客

瀏覽器的url會跳轉成如圖所示:

https://www.baidu.com/s?wd=%E4%BC%A0%E6%99%BA%E6%92%AD%E5%AE%A2

在其中我們可以看到在請求部分里,http://www.baidu.com/s? 之后出現一個長長的字符串,其中就包含我們要查詢的關鍵詞傳智播客,于是我們可以嘗試用默認的Get方式來發送請求。

# urllib_get.py

import urllib.parse      #負責url編碼處理
import urllib.request

url = "http://www.baidu.com/s"
word = {"wd":"傳智播客"}
word = urllib.parse.urlencode(word) #轉換成url編碼格式(字符串)
newurl = url + "?" + word    # url首個分隔符就是 ?

headers={ "User-Agent": "
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36
"} 
request = urllib.request.Request(newurl, headers=headers) 
response = urllib.request.urlopen(request) 

print (response.read()) 

批量爬取貼吧頁面數據

首先我們創建一個python文件, tiebaSpider.py,我們要完成的是,輸入一個百度貼吧的地址,比如:

百度貼吧LOL吧第一頁:http://tieba.baidu.com/f?kw=lol&ie=utf-8&pn=0

第二頁: http://tieba.baidu.com/f?kw=lol&ie=utf-8&pn=50

第三頁: http://tieba.baidu.com/f?kw=lol&ie=utf-8&pn=100

發現規律了吧,貼吧中每個頁面不同之處,就是url最后的pn的值,其余的都是一樣的,我們可以抓住這個規律。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import urllib.request
import urllib.parse

def loadPage(url, filename):
    """
        作用:根據url發送請求,獲取服務器響應文件
        url: 需要爬取的url地址
        filename : 處理的文件名
    """
    print ("正在下載 " + filename)
    headers = {"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36"}

    request = urllib.request.Request(url, headers = headers)
    return urllib.request.urlopen(request).read()

def writePage(html, filename):
    """
        作用:將html內容寫入到本地
        html:服務器相應文件內容
    """
    print ("正在保存 " + filename)
    # 文件寫入
    with open(filename, "wb+") as f:
        f.write(html)
    print ("-" * 30)

def tiebaSpider(url, beginPage, endPage):
    """
        作用:貼吧爬蟲調度器,負責組合處理每個頁面的url
        url : 貼吧url的前部分
        beginPage : 起始頁
        endPage : 結束頁
    """
    for page in range(beginPage, endPage + 1):
        pn = (page - 1) * 50
        filename = "第" + str(page) + "頁.html"
        fullurl = url + "&pn=" + str(pn)
        #print fullurl
        html = loadPage(fullurl, filename)
        #print html
        writePage(html, filename)
        print ('謝謝使用')

if __name__ == "__main__":
    kw = input("請輸入需要爬取的貼吧名:")
    beginPage = int(input("請輸入起始頁:"))
    endPage = int(input("請輸入結束頁:"))

    url = "http://tieba.baidu.com/f?"
    key = urllib.parse.urlencode({"kw": kw})
    fullurl = url + key
    tiebaSpider(fullurl, beginPage, endPage)

其實很多網站都是這樣的,同類網站下的html頁面編號,分別對應網址后的網頁序號,只要發現規律就可以批量爬取頁面了。

POST方式:

上面我們說了Request請求對象的里有data參數,它就是用在POST里的,我們要傳送的數據就是這個參數data,data是一個字典,里面要匹配鍵值對。

有道詞典翻譯網站:

輸入測試數據,再通過使用Fiddler觀察,其中有一條是POST請求,而向服務器發送的請求數據并不是在url里,那么我們可以試著模擬這個POST請求。

[圖片上傳失敗...(image-9a9c6c-1599746015652)]

于是,我們可以嘗試用POST方式發送請求。

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import urllib.request
import urllib.parse

# 通過抓包的方式獲取的url,并不是瀏覽器上顯示的url
url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=null"

# 完整的headers
headers = {
        "Accept" : "application/json, text/javascript, */*; q=0.01",
        "X-Requested-With" : "XMLHttpRequest",
        "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36",
        "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8",
    }

# 用戶接口輸入

# 發送到web服務器的表單數據
formdata = {
"type" : "AUTO",
"i" : "我愛你",
"doctype" : "json",
"xmlVersion" : "1.6",
"keyfrom" : "fanyi.web",
"ue" : "UTF-8",
"typoResult" : "true"
}

# 經過urlencode轉碼
data = urllib.parse.urlencode(formdata).encode('utf-8')

# 如果Request()方法里的data參數有值,那么這個請求就是POST
# 如果沒有,就是Get
#request = urllib.request.Request(url, data = data, headers = headers)
response = urllib.request.urlopen(url,data)

html = response.read().decode('utf-8')

print(html)
#print (urllib.request.urlopen(req).read())
發送POST請求時,需要特別注意headers的一些屬性:
Content-Length: 144: 是指發送的表單數據長度為144,也就是字符個數是144個。

X-Requested-With: XMLHttpRequest :表示Ajax異步請求。

Content-Type: application/x-www-form-urlencoded : 表示瀏覽器提交 Web 表單時使用,表單數據會按照 name1=value1&name2=value2 鍵值對形式進行編碼。

獲取AJAX加載的內容
有些網頁內容使用AJAX加載,只要記得,AJAX一般返回的是JSON,直接對AJAX地址進行post或get,就返回JSON數據了。

"作為一名爬蟲工程師,你最需要關注的,是數據的來源"

import urllib
import urllib2

# demo1

url = "https://movie.douban.com/j/chart/top_list?type=11&interval_id=100%3A90&action"

headers={"User-Agent": "Mozilla...."}

# 變動的是這兩個參數,從start開始往后顯示limit個
formdata = {
    'start':'0',
    'limit':'10'
}
data = urllib.urlencode(formdata)

request = urllib2.Request(url, data = data, headers = headers)
response = urllib2.urlopen(request)

print response.read()


# demo2

url = "https://movie.douban.com/j/chart/top_list?"
headers={"User-Agent": "Mozilla...."}

# 處理所有參數
formdata = {
    'type':'11',
    'interval_id':'100:90',
    'action':'',
    'start':'0',
    'limit':'10'
}
data = urllib.urlencode(formdata)

request = urllib2.Request(url, data = data, headers = headers)
response = urllib2.urlopen(request)

print response.read()

問題:為什么有時候POST也能在URL內看到數據?

  • GET方式是直接以鏈接形式訪問,鏈接中包含了所有的參數,服務器端用Request.QueryString獲取變量的值。如果包含了密碼的話是一種不安全的選擇,不過你可以直觀地看到自己提交了什么內容。
  • POST則不會在網址上顯示所有的參數,服務器端用Request.Form獲取提交的數據,在Form提交的時候。但是HTML代碼里如果不指定 method 屬性,則默認為GET請求,Form中提交的數據將會附加在url之后,以?分開與url分開。
  • 表單數據可以作為 URL 字段(method="get")或者 HTTP POST (method="post")的方式來發送。比如在下面的HTML代碼中,表單數據將因為 (method="get") 而附加到 URL 上:
<form action="form_action.asp" method="get">
    <p>First name: <input type="text" name="fname" /></p>
    <p>Last name: <input type="text" name="lname" /></p>
    <input type="submit" value="Submit" />
</form>

利用cookie模擬登陸

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import urllib.request

url = "http://www.renren.com/410043129/profile"

headers = {
    "Host" : "www.renren.com",
    "Connection" : "keep-alive",
    #"Upgrade-Insecure-Requests" : "1",
    "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
    "Accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Referer" : "http://www.renren.com/SysHome.do",
    #"Accept-Encoding" : "gzip, deflate, sdch",#加上會得到壓縮文件
    "Cookie" : "anonymid=ixrna3fysufnwv; _r01_=1; depovince=GW; jebe_key=f6fb270b-d06d-42e6-8b53-e67c3156aa7e%7Cc13c37f53bca9e1e7132d4b58ce00fa3%7C1484060607478%7C1%7C1484400895379; jebe_key=f6fb270b-d06d-42e6-8b53-e67c3156aa7e%7Cc13c37f53bca9e1e7132d4b58ce00fa3%7C1484060607478%7C1%7C1484400890914; JSESSIONID=abcX8s_OqSGsYeRg5vHMv; jebecookies=0c5f9b0d-03d8-4e6a-b7a9-3845d04a9870|||||; ick_login=8a429d6c-78b4-4e79-8fd5-33323cd9e2bc; _de=BF09EE3A28DED52E6B65F6A4705D973F1383380866D39FF5; p=0cedb18d0982741d12ffc9a0d93670e09; ap=327550029; first_login_flag=1; ln_uact=mr_mao_hacker@163.com; ln_hurl=http://hdn.xnimg.cn/photos/hdn521/20140529/1055/h_main_9A3Z_e0c300019f6a195a.jpg; t=56c0c522b5b068fdee708aeb1056ee819; societyguester=56c0c522b5b068fdee708aeb1056ee819; id=327550029; xnsid=5ea75bd6; loginfrom=syshome",
    "Accept-Language" : "zh-CN,zh;q=0.8,en;q=0.6",
}

request = urllib.request.Request(url, headers = headers)

response = urllib.request.urlopen(request)

print(response.read())

處理HTTPS請求 SSL證書驗證

現在隨處可見 https 開頭的網站,urllib2可以為 HTTPS 請求驗證SSL證書,就像web瀏覽器一樣,如果網站的SSL證書是經過CA認證的,則能夠正常訪問,如:https://www.baidu.com/等...

如果SSL證書驗證不通過,或者操作系統不信任服務器的安全證書,比如瀏覽器在訪問12306網站如:https://www.12306.cn/mormhweb/的時候,會警告用戶證書不受信任。(據說 12306 網站證書是自己做的,沒有通過CA認證)

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import urllib.request
import ssl

# 忽略SSL安全認證
context = ssl._create_unverified_context()

url = "https://www.12306.cn/mormhweb/"
#url = "https://www.baidu.com/"

headers = {
    "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
    }
request = urllib.request.Request(url, headers = headers)

# 添加到context參數里
response = urllib.request.urlopen(request, context = context)

print (response.read())

關于CA

CA(Certificate Authority)是數字證書認證中心的簡稱,是指發放、管理、廢除數字證書的受信任的第三方機構,如北京數字認證股份有限公司上海市數字證書認證中心有限公司等...

CA的作用是檢查證書持有者身份的合法性,并簽發證書,以防證書被偽造或篡改,以及對證書和密鑰進行管理。

現實生活中可以用身份證來證明身份, 那么在網絡世界里,數字證書就是身份證。和現實生活不同的是,并不是每個上網的用戶都有數字證書的,往往只有當一個人需要證明自己的身份的時候才需要用到數字證書。

普通用戶一般是不需要,因為網站并不關心是誰訪問了網站,現在的網站只關心流量。但是反過來,網站就需要證明自己的身份了。

比如說現在釣魚網站很多的,比如你想訪問的是www.baidu.com,但其實你訪問的是www.daibu.com”,所以在提交自己的隱私信息之前需要驗證一下網站的身份,要求網站出示數字證書。

一般正常的網站都會主動出示自己的數字證書,來確保客戶端和網站服務器之間的通信數據是加密安全的。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372