網頁爬蟲的原理

原文地址: https://zhuanlan.zhihu.com/p/35324806

這篇文章的定位是,給有一些python基礎,但是對爬蟲一無所知的人寫的。文中只會涉及到爬蟲最核心的部分,完全避開莫名其妙的坑或概念,讓讀者覺得爬蟲是一件非常簡單的事情,而事實上爬蟲確實是一件非常簡單的事情(如果你不是以爬蟲爲工作的話)。

本文分爲如下幾個部分

  • 引言
  • 概念介紹
  • HTML介紹
  • 解析代碼介紹
  • chrome檢查工具介紹

引言

簡單理解網絡爬蟲就是自動抓取網頁信息的代碼,可以簡單理解成代替繁瑣的複製粘貼操作的手段。首先必須聲明,爬蟲的對象必須是你已經看到的網頁,比如你不能說你想找到知乎上哪個用戶的關注人數最多,就希望通過寫一個爬蟲來幫你爬到答案。你必須明確地知道這個人,找到他的主頁,然後才能用爬蟲來抓取他頁面上的信息。下面我們用一個簡單的例子來展示爬蟲的工作流程。感覺多數教程第一篇都使用的是豆瓣top250,我們這裏換一個,抓取CSDN首頁的文章標題,鏈接在這裏,頁面樣子是這樣的

https://pic1.zhimg.com/80/v2-850dd573365d9c9a1c9d58fa7f27532c_1440w.jpg

抓取標題完整代碼如下

`import requests # 導入網頁請求庫from bs4 import BeautifulSoup # 導入網頁解析庫# 傳入URLr = requests**.**get('https://www.csdn.net/')

# 解析URLsoup = BeautifulSoup(r**.text, 'html.parser') content_list = soup.**find_all('div', attrs = {'class': 'title'})

for content in content_list: print(content**.h2.a.**text)`

這樣就會打印出所有標題,展示一部分如下

https://pic2.zhimg.com/80/v2-13c20a4c25725fb9d363c567ab4eb08d_1440w.jpg

上述過程是一個最簡單的完整爬蟲流程,可以看出它的功能就是把那些標題複製粘貼到一起,免除了手動操作的繁瑣。其實爬蟲一般就是做這些事的,比如我們需要用鏈家的數據進行分析,看到鏈家的頁面是這樣的

https://pic1.zhimg.com/80/v2-c0235ab217e08e205305de260bea60e0_1440w.jpg

我們想獲取每個房子的標題、幾室幾廳、多少平米、朝向、裝修、價格等等字段(即指標),就可以通過爬蟲進行定位,自動化抓取這100頁所有房子的這些字段信息。比如100頁裏有2000個房子,總共抓取10個字段,爬蟲運行結束就可以得到一個2000行10列的excel表格。

注:如果還沒有安裝上面兩個庫的讀者可以在命令行下分別運行下面兩行命令完成安裝

pip install requests pip install beautifulsoup4

概念介紹

知道了爬蟲是用來幹什麼的之後,我們來介紹一些最常見到的概念

1.URL

URL中文稱爲統一資源定位符,其實可以理解成網頁的鏈接,比如上面的https://www.csdn.net/就是一個URL。

但是更廣義的URL不只是我們常看到的網頁資源鏈接,而是資源在網頁中的定位標識。我們通常說的網頁是一個資源,網頁中加載的每一張圖片也是一個資源,它們在互聯網中也有唯一的定位URL。比如我們從CSDN網頁上隨便找一張圖片

https://pic2.zhimg.com/80/v2-99be53d259d1d0c0755a63b578816f05_1440w.jpg

這個鏈接https://csdnimg.cn/feed/20180330/49f4cd810ad4606e3c45ed9edb16a8b8.jpg就是這個圖片資源的定位符,將這個鏈接輸入瀏覽器中就會顯示出這張圖片,所以說這張圖片也對應一個URL。

不過知道這麼回事就好,我們通常所說的傳入URL指的就是把網頁的鏈接傳進去。上面代碼中

r **=** requests**.**get('<https://www.csdn.net/>')

就是在將URL傳入請求函數。

2.網頁請求

說到網頁請求,就有必要講一下我們平常瀏覽網頁時,信息交互的模式大概是什麼樣的。我們平常用瀏覽器瀏覽網頁的時候,鼠標點了一個鏈接,比如你現在點擊這裏,其實瀏覽器幫你向這個網頁發送了請求(request),維護網頁的服務器(可以理解爲CSDN公司裏的一臺電腦,在維護這CSDN上的各個網頁)收到了這個請求,判定這個請求是有效的,於是返回了一些響應信息(response)到瀏覽器,瀏覽器將這些信息進行渲染(可以理解成 處理成人能看懂的樣子),就是你看到的網頁的樣子了。發送請求與接收請求的過程就和 發微信和收到回覆的過程類似。

而現在我們要用代碼來模擬鼠標點擊的過程。上面的requests.get就是讓代碼幫你向這個網頁發送了這個請求,如果請求被判定爲有效,網頁的服務器也會把信息傳送給你,傳送回來的這些信息就被賦值到變量r之中。所以這個變量r裏就包含有我們想要的信息了,也包括那些我們想要提取的標題。

我們可以print(r.text)看一下里面有什麼東西

https://pic4.zhimg.com/80/v2-bb0040576245087202432c2c4ebbc88b_1440w.jpg

我們再看一下網頁的源代碼(如何看懂這個源碼,以及這個源碼怎麼查看下一節HTML會詳細講到)

https://pic3.zhimg.com/80/v2-184bf0e862d37b5e2297f2c4289d8662_1440w.jpg

源代碼和r.text其實是一模一樣的東西。r.text其實就是一個字符串,字符串中有我們剛剛抓取到的所有標題,我們只要通過字符串匹配方法(比如正則表達式)將他們提取出來就可以了。這樣說是不是感覺爬蟲非常簡單呢?只要這樣傻瓜操作

r = requests.get('<https://www.csdn.net/>')

再直接從r.text字符串中提取信息即可。其實爬蟲就是這麼簡單。

但是解析是怎麼回事呢,爲什麼剛剛不直接用正則而要用bs4呢?因爲方便,但是正則也是完全可以的,只是相對麻煩一些、需要寫更多的代碼而已。

3.網頁解析

網頁解析其實就從網頁服務器返回給我們的信息中提取我們想要數據的過程。其實使用正則表達式提取我們要的標題的過程也可以稱爲網頁解析。

因爲當前絕大多數網頁源代碼都是用HTML語言寫的,而HTML語言時非常有規律性的,比如我們要的所有文章標題都具有相同結構,也就是說它周圍的字符串都是非常類似的,這樣我們才能批量獲取。所以就有大佬專門封裝瞭如何從HTML代碼中提取特定文本的庫,也就是我們平時說的網頁解析庫,如bs4 lxml pyquery等,其實把他們當成處理字符串的就可以了。

爲了更清楚地瞭解如何對網頁進行解析,我們需要先粗略掌握HTML代碼的結構。

HTML介紹

引用維基百科中的一段話來介紹HTML

超文本標記語言(英語:HyperText Markup Language,簡稱:HTML)是一種用於創建網頁的標準標記語言。HTML是一種基礎技術,常與CSS、JavaScript一起被衆多網站用於設計令人賞心悅目的網頁、網頁應用程序以及移動應用程序的用戶界面[1]。網頁瀏覽器可以讀取HTML文件,並將其渲染成可視化網頁。

爲了讓讀者對HTML有更清楚的認識,我們來寫一點簡單的HTML代碼。用文本編輯器(記事本也可以)創建一個名字爲a.html的文件,在裏面寫下如下代碼

**<!DOCTYPE html>**<html> <head> <title>爬蟲基本原理</title> </head> <body> <h1>HTML介紹</h1> <p>第一段</p> <p>第二段</p> </body> </html>

保存,然後你雙擊這個文件,就會自動用瀏覽器打開,然後你就能看到下面這個樣子的頁面

https://pic2.zhimg.com/80/v2-7d761d77317867021fd59e4e90c1bddd_1440w.jpg

你如果按照我的操作來做的話,你已經創建了一個簡單的網頁,現在你看到的所有網頁都是這樣設計的,只是比你的複雜一點而已,不信你去看看剛纔截圖下來的網頁源代碼圖片。

接下來,我們來看一下HTML語言的特點。最重要的一點是,文本都是被標籤(h1標籤 p標籤)夾在中間的,而這些標籤都是特定的,有專門用途的。比如<h1>就表示一級標題,包在裏面的文本自然會被放大顯示;而<p>標籤則表示段落。

再看上面的源代碼截圖,head meta script title div li每一個都是標籤,層層嵌套。我們完全不需要知道總共有哪些種標籤,也不需要知道這些標籤都是用來幹什麼的,我們只要找到我們要的信息包含在什麼標籤裏就行了。比如使用正則表達式就直接用<p>(.*?)</p>就可以把裏面的內容提取出來了。

但是事實好像沒有那麼簡單,看上面的截圖標籤怎麼是這樣的<nav id="nav" class="clearfix">?其實這是一個<nav>標籤,後面的id class是這個標籤的屬性。

爲什麼要給標籤設置屬性呢?我們先考慮這樣一個問題:我們看到的網頁千差萬別,文字的顏色字體等都不一樣,這是怎麼設置的呢?答案是使用css樣式。

css語句類似這樣

h1 { **color**: **white**; **text-align**: **center**; } p { **font-family**: verdana; **font-size**: 20**px**; }

即設置對應標籤的顏色、字體、大小、居中等。而當有的段落使用這個字體,有的段落使用那個字體怎麼辦呢?css這樣設置

p.**test1** { **font-size**: 20**px**; } p.**test2** { **font-size**: 15**px**; }

在HTML代碼中則這樣寫

<p class**=**"test1">20px大小的字</p> <p class**=**"test2">15px大小的字</p>

所以不同屬性就是爲了區分相同標籤用的,這相當於給標籤進行了分類,在統一設計樣式上更方便,同時對於我們根據屬性定位我們想要內容的位置其實也是更方便了。這裏要說明一下,class id這兩個屬性比較特殊,用的也最多,所以各自弄了一個快捷鍵來表示,class.id#

做爬蟲不需要了解剛剛編寫的css代碼內容放在哪裏之類的問題,也不需要了解css代碼設置了什麼,我們只會和HTML打交道,所以只要理解HTML中屬性的作用就可以了。

如果想要更進一步瞭解HTML和CSS,可以到w3school網站學習。

現在你就已經具備瞭解析網頁需要的全部HTML知識了。我們一般就是根據標籤名配合屬性值來定位我們想要資源的位置的,其他的都不用管。這時,我們再來看爬蟲的解析代碼

解析代碼介紹

把前面的代碼再粘貼一遍如下

`import requests # 導入網頁請求庫from bs4 import BeautifulSoup # 導入網頁解析庫# 傳入URLr = requests**.**get('https://www.csdn.net/')

# 解析URLsoup = BeautifulSoup(r**.text, 'html.parser') content_list = soup.**find_all('div', attrs = {'class': 'title'})

for content in content_list: print(content**.h2.a.**text)`

解釋一下上面代碼的過程

  • 第一步,把r.text這個網頁源代碼字符串傳到BeautifulSoup函數中(第二個參數固定用法先不用管),得到的soup對象,可以理解成這一步是爲了讓這個字符串可以用一些更簡單的方法,比如它可以調用find_all方法,尋找class屬性是title的div標籤,這樣的標籤有非常多,返回了一個list。
  • 第二步,對這個list進行循環,每一個元素內部尋找h2標籤裏的a標籤,提取a標籤中的文本,即我們要的標題。

可以看到上面的代碼非常簡潔,思路清晰,讀者可以自己想一想如果要用正則表達式如何匹配這些標籤,會發現代碼繁瑣很多,雖然它也有更快的優勢。

那麼我們是怎麼知道要尋找什麼樣屬性的div標籤,爲什麼要找h2 a標籤而不是其他的呢?這就要去分析網頁的源代碼了。而這個過程也非常簡單。

chrome檢查工具介紹

我們現在用谷歌瀏覽器打開CSDN這個網站,找一個空白的位置右鍵-查看網頁源代碼,這時就會打開一個新的頁面這個頁面就是這個網站的HTML源代碼了,我們可以通過這個頁面來看我們要的信息在哪裏,但是感覺非常不方便,因爲有太多無用的信息做干擾,我們無法快速掌控網頁的結構。所以我們可以用另一種方式查看源代碼。

用谷歌瀏覽器打開CSDN這個網站,找一個空白的位置右鍵-檢查,就會彈出一個框,如下圖所示

https://pic4.zhimg.com/80/v2-9a315bb94c08e58ed5f63202e8a25d5b_1440w.jpg

(如果沒有看到這個界面,注意要切換到Element中)

這個頁面最大的好處是通過摺疊來讓人更快探索出網頁的結構。

其中的那些代碼就是HTML代碼,該頁面的一個個標題就存在這一個個li裏面。點擊li前面的三角就可以展開具體的代碼內容,如下圖所示

https://pic2.zhimg.com/80/v2-8499b2eb6e641620474641daedb61931_1440w.jpg

可以看到文章的標題(打造一個高性能、易落地的公鏈開發平臺)就在這個源代碼之中,也就是說在我們剛剛獲得的r.text字符串之中。而我們代碼定位路徑也一目瞭然了,因爲每個li裏面都會有一個<div class="title">而每一個div裏面都會有一個h2 裏面有一個a,a中包含我們要的標題名稱。所以我們就用find_all找到所有這樣的div標籤,存儲爲一個list,再對list進行循環,對每一個元素提取h2 a 再提取標籤中的內容。

當然我們也可以find_all最外面的li標籤,再一層層往裏找,都是一樣的。只要找到定位信息的唯一標識(標籤或者屬性)就可以了。

雖然在這裏看源代碼可以摺疊一些沒用的代碼,但是其實還有一些更好用的工具來輔助我們找到我們要的信息在網頁源碼中的位置。比如下面這個鼠標符號。

https://pic1.zhimg.com/80/v2-11e49b3e1474035316b4bd2ae4d59a4c_1440w.jpg

在所有代碼都摺疊起來的情況下,點擊這個鼠標,之後再去點擊網頁中的元素,瀏覽器就會自動幫你把你點擊的元素選中出來,其實你鼠標懸在一個元素上面的時候,就已經幫你定位了,如下圖所示

https://pic2.zhimg.com/80/v2-88b64ae8861ace4172d54a6cdb81da31_1440w.jpg

總結

當我們要爬一個網頁的時候,只需要如下流程

  • 導入兩個庫,一個用於請求,一個用於網頁解析
  • 請求網頁,獲得源代碼
  • 初始化soup對象,使其可以調用更簡單易用的方法
  • 用瀏覽器打開網頁,右鍵-檢查,使用那個鼠標定位你要找的資源的位置
  • 分析那個位置的源代碼,找到合適的用於定位的標籤及屬性
  • 編寫解析代碼,獲得想要的資源

現在,對於一些沒有絲毫反爬措施的網站我們都可以遊刃有餘了。至於抓取多個字段的數據如何組織在一起、抓取多頁(URL有規律的情況下)的代碼如何設計,就不是爬蟲知識範疇了,這是用python基礎知識就可以解決的。下一系列文章就主要講這一部分。接下來給幾個當前可以練手的網站

  • CSDN首頁除了標題之外的其他信息,比如作者名、發佈的時間等,可以存儲到一個以字典爲元素的list裏
  • 豆瓣top250的信息,會翻頁的話250個電影的信息可以直接一個循環抓取下來,其實找到規律構造出10個URL即可
  • stackoverflow 簡書 伯樂在線 等等網站都可以拿來練手

如果使用BeautifulSoup的定位的過程中遇到困難,可以直接到網上搜教程,也可以等我們這個專題後面更新的BeautifulSoup詳細介紹。

如果你去抓取其他網站,最好先看一下r.text是不是和網站源代碼一模一樣,如果不是,說明你對方服務器沒有把真正的信息給你,說明他可能看出你是爬蟲了(進行網頁請求的時候,瀏覽器和requests.get都相當於帶着一堆資格證去敲門,對方會檢查你這些資格證,瀏覽器的資格證一般是可以通過的,而代碼的資格證就可能不合格,因爲代碼的資格證可能有一些比較固定的特點,對方服務器預先設定好,資格證是這樣的請求一律拒絕,因爲他們一定是爬蟲,這就是反爬蟲機制),這時就需要懂一些反反爬措施才能獲得真正的信息,反反爬方法的學習是一個積累的過程,我們後面再講。讀者如果遇到一些反爬機制,可以到網上查這個網站的爬蟲,估計都能查到一些博客講如何破解,甚至直接貼出代碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章