VOOZH about

URL: https://read01.com/BnMeE47.html

⇱ 用 Python 抓網頁?你想問的都幫答好了 - 壹讀


Sunday, Apr 12, 2026

用 Python 抓網頁?你想問的都幫答好了

2018/07/24 來源:知乎專欄

近年來,隨著大數據、人工智慧、機器學習等技術的興起,Python 語言也越來越為人們所喜愛。但早在這些技術普及之前,Python 就一直擔負著一個重要的工作:自動化抓取網頁內容。

舉個栗子,飛機票的價格每時每刻都在變化,甚至有些 app,你搜索的越多,價格就越貴。那不搜又不行啊,怎麼樣才能知道確切的價格呢?

這就是 Python 大顯身手的時候啦~ 我們可以用Python寫一段程序,讓它自動幫你從網絡上獲取需要的數據——這就是所謂的「爬蟲程序」——它能從你指定的一個或多個網站上讀取並記錄數據(比如從某個航班數據網站上讀取指定日期和航線的機票信息),並根據數據進行一些自動操作,比如記錄下最低價,並通知用戶。

總結一下:

網頁抓取是一種通過自動化程序從網頁上獲取頁面內容的計算機軟體技術。

我們這裡說的「爬蟲」,正式名稱叫做「網頁抓取」。按照維基百科的說法,網頁抓取和大多數搜尋引擎採用的網頁索引的爬蟲技術不同,網頁抓取更側重於將網絡上的非結構化數據(常見的是HTML格式)轉換成為能在一個中央資料庫中儲存和分析的結構化數據。「網頁抓取也涉及到網絡自動化,它利用計算機軟體模擬了人的瀏覽。網頁抓取的用途包括在線比價,聯繫人數據抓取,氣象數據監測,網頁變化檢測,以及各類科研和Web數據集成等。」

👁 Image
...

對於一般用戶,我們主要關注的就是網頁抓取。因此,以下提到的「爬蟲」一律指網頁抓取所用的自動化程序。

在今天的文章里,我們將帶你從最基礎的工具和庫入手,詳細了解一下一個爬蟲程序的常用結構,爬取網絡數據時應該遵循哪些規則,存在哪些陷阱;最後,我們還將解答一些常見的問題,比如反追蹤,該做什麼不該做什麼,以及如何採用並行處理技術加速你的爬蟲等等。

文中介紹的每項內容都會附上 Python實例代碼,方便你可以直接上手試玩。同時,我們還會介紹幾個非常有用的 Python 庫。

本教程主要分為5個部分:

1. 常用的代碼庫和工具

2. 從最簡單的例子開始

3. 小心陷阱

4. 一些規則

5. 利用並行加速爬蟲程序

在開始之前,請記住:務必善待伺服器,我們並不希望把人家網站弄掛了,是吧。

1. 常用的代碼庫和工具

總的來說,網頁抓取並沒有一個一成不變的解決方案,畢竟通常每個網站的數據都因為網站自身結構的不同而具有各不相同的特性。事實上,如果你希望從某個網站上抓取數據,你需要對這個網站的結構有足夠的理解,針對這個網站自己寫出對應的腳本,或將某個腳本設置到符合網站的結構,才可能成功。不過,你也無須重新發明輪子:已經有很多不同的代碼庫,能幫你完成絕大多數底層的工作,它們多多少少都能幫上你一點忙。

1.1「檢查」選項

大部分時候,在實際爬取之前,你都需要熟悉網站的 HTML 代碼。你可以簡單地在你想查看的網頁元素上點擊右鍵,選擇「檢查」(Chrome)或者「查看元素」(火狐)

之後,系統就會彈出一個調試工具區,高亮你剛選中的網頁元素。以 Medium 網站的作者信息頁為例:

👁 Image
...

在頁面上,這個被選中的元素包含了作者的姓名、標籤及個人介紹。這個元素的 class 是 hero hero--profile u-flexTOP。然後在這個元素里還有幾個子元素,其中顯示作者姓名的是 <h1> 標籤,它的 class 是 ui-h2 hero-title,顯示作者個人信息的 <p>,它的 class 是 ui-body hero-description。

你可以在 Mozilla 的開發者學院裡找到更多關於 HTML 標記,以及 class 和 id 的區別等的詳細介紹。

1.2 Scrapy 庫

有個可獨立運行,開箱即用的數據抓取框架,名叫 Scrapy。除了抓取並輸出 HTML 外,這個庫還提供了許多額外的功能,比如按特定的格式輸出數據,記錄日誌等。同時,它的可定製性也很高,你可以在多個不同的進程上運行不同的爬蟲,禁用 cookie ¹,設置下載延時²等。

¹ 有些站點會用 cookie 來識別爬蟲。

² 數量過多的爬取請求會給網站帶來額外的負擔,甚至可能會導致網站宕機。

但對我個人而言,這個庫有點太大太全面了:我只不過是想讀取站點每個頁面上的連結,按順序訪問每個連結並導出頁面上的數據而已。

1.3 BeautifulSoup 和 Requests 庫

BeautifulSoup 庫能讓你優雅地處理 HTML 源碼。同時你還需要一個 Request 庫,用於從指定URL獲取內容。不過,你需要自己處理其他的細節問題,包括錯誤捕獲與處理,導出數據,並行處理等。

我個人特別喜歡 BeautifulSoup 因為它迫使我自己探索許多 Scrapy 可能已經幫我處理好了的技術細節,讓我從自己動手開始,從錯誤中學習。

2. 從最簡單的例子開始

從網站上抓取數據其實還是蠻直截了當的。大部分時候我們要關注的就是 HTML 源碼,找到你需要的內容所對應的 class 和 id。

下面是一個示例的網頁 HTML 代碼,假設我們要抓取到原價和折後價,那我們需要關注的就是 main_price 和 discounted_price 兩個元素。請注意,discounted_price 元素並不總是出現。

👁 Image
...

於是,我們從最基本的代碼開始:先導入需要用的 BeautifulSoup 和 Requests 庫,然後發起查詢請求( requests.get ),接著處理 html 源碼,最後找到所有 class 為 main_price 的元素。

👁 Image
...

文字版原始碼詳見:

有的時候,網頁的其他地方可能也有 main_price 的元素。為了避免導出無關的信息,我們可以先找到我們需要的 id='listings_prices',然後只在這個元素的子元素中查找 main_price 元素。

3. Pitfalls 小心陷阱

3.1 檢查 robots.txt

許多網站會將爬取規則和限制寫在 robots.txt 里,這個文件通常是在根域名下,你可以直接在域名後面加上 /robots.txt 來獲取這個文件。例如: http://www.example.com/robots.txt

robots.txt 里一般會規定哪些網頁不允許被自動抓取,或者限定某個頁面被機器人訪問的頻率。雖然大部分人確實都不理會這些,不過就算你真的不打算遵守這個規定,起碼也先看一看它的內容,給點表面的尊重吧,哈哈。

Google官方的幫助文檔中,對此的解釋是:「robots.txt 文件中的命令並不能強制抓取工具對您的網站採取具體的操作;對於訪問您網站的抓取工具來說,這些命令僅作為指令。Googlebot 和其他正規的網頁抓取工具都會遵循 robots.txt 文件中的命令,但其他抓取工具未必也會如此。」

3.2 小心 HTML 里的坑

HTML 標籤中可能包含 id 或 class,或二者兼有。 HTML id 是一個獨一無二的標記,而 HTML class 可能在多個元素中被重用。class 名或元素內容可能會改變,而這種改變可能會讓你的代碼崩潰,或是返回錯誤的結果。

一般來說,有兩種辦法避免這種情況出現:

● 採用 id 來獲取元素內容,而不是 class,因為 id 一般來說不那麼容易改變。

● 記得檢查返回值,如果返回了 None,那很可能有什麼地方出了問題。

👁 Image
...

不過,因為有一些 class 可能並不總是出現(例如前面例子中的 discounted_price ),相關的元素並不一定在每個列表中都有。所以你需要統計某個元素在所有列表中出現的比例,比如計算返回 None 的次數。如果每次都返回 None,那也許你需要檢查代碼或者是 HTML 源碼,看看是不是這個元素在網站的 HTML 中就已經改變了。

3.3 對 User agent 進行偽裝

每當你訪問一個網站時,網站都會通過瀏覽器的 user agent 獲取到你的瀏覽器信息。有些網站如果沒收到 user agent 信息,就不會返回任何內容,還有些網站會根據不同的 user agent,給不同的瀏覽器提供不同的內容。

網站並不會阻止正常用戶的訪問,但如果你用同一個 user agent 發起每秒 200 次的請求,那看起來也太可疑了一點。怎麼解決呢?你可以通過 user_agent 庫,產生(幾乎是)隨機的 user agent,也可以自定義一個特殊的 user agent。

👁 Image
...

文字版見:

3.4 給 request 請求設置一個超時時間

在默認狀態,request 庫會無止境地等待某個請求返回對應的響應內容。所以,給它設置一個參數,等待超時就斷開連接,還是很有必要的。

文字版見:

3.5 我是不是剛被屏蔽了?

如果你拿到的返回值經常是 404(找不到頁面)、403(被禁止)、408(訪問超時),就應該考慮你是不是被這個站點屏蔽了。

如果你對 HTTP 返回值不熟悉,看看我們之前解釋 HTTP 返回值的漫畫吧~

同樣,你也應該在返回的響應中對這類錯誤進行處理。

👁 Image
...

文字版見:

3.6 切換 IP 地址

就算你採用了隨機生成的 user agent,程序發起的所有連接都還用的是同一個 IP 地址:你的地址。雖然這通常並不會引起太多重視,畢竟很多圖書館、大學以及企業分別都只有少數幾個 IP 地址,由這些機構內的所有計算機共同使用。然而,如果在短時間內從某一個 IP 地址發出了巨量的請求,還是會被伺服器發現的。

這時候,你多年珍藏的科學上網工具就能大顯身手啦。

當你採用了代理、VPN或者其他技術之後,對應的網站會將你發起的請求識別為來自相應的伺服器,而不是你的。

3.7 蜜罐攻擊

蜜罐是引誘網頁爬蟲對其進行抓取或索引,從而進行偵測的一種技術手段。

比如,網頁上可能會存在一些「隱藏」連結,正常用戶在訪問的時候看不到這個連結,但爬蟲在處理 HTML 原始碼的時候會把它當作正常連結進行處理。此類連結有可能用 CSS 樣式設置了 display:none,或者設置成和背景相同的顏色,甚至採用比如藏在頁面中的不可見位置等手段。一旦你的爬蟲訪問了這類連結,你的 IP 地址可能就被記錄日誌,甚至伺服器可能直接將你屏蔽。

另外一種蜜罐,是用超連結建立一串近乎無限深度的目錄樹,如果有人訪問了足夠深位置的內容,那基本上可以確定這人不是個普通用戶。因此,在編寫爬蟲時,需要限制爬蟲取回的頁面數量,或控制遍歷深度。

4. 一些規則

  • 在抓取之前,先看看目標網站是不是已經提供了公開的 API。畢竟通過 API 能更好更快(也合法)地獲取所需的信息。比如社交網站 Twitter 就提供了許多不同的 API。
  • 如果你需要抓取非常大量的數據,你應該考慮用一個資料庫把這些數據整理起來,方便之後進行分析和使用。這裡有一篇用 Python 操作本地資料庫的教程。
  • 務必保持禮貌。有時候,甚至建議你直接和對方網站的運維人員取得聯繫,說不定他們能更方便快速地幫你解決你的機器人遇到的問題。

同時,再強調一遍,切記不要貪得無厭地發起太多請求,這會給目標網站帶來不必要的負載。

5. 利用並行加速爬蟲程序

如果你希望讓你的程序並行運行,一定要小心檢查自己的代碼,否則可能你會突然發現自己正在榨乾目標伺服器的資源。同時,請一定一定認真看完上一節的幾個規則。最後,你需要確保自己已經理解了並行處理和並發處理,多線程和多進程之間的區別。

如果你在抓取過程中還要對巨量的頁面信息進行預處理,你會發現平均每秒鐘能發起的請求數其實是相當少的。

在我個人的另一個抓取出租房價格的項目里,因為抓取時的預處理信息量實在太大,每秒能發起的請求數大約只有1個。處理 4000 個左右的連結,需要程序運行上大約一個小時。

為了並行發送請求,你可能需要採用一個叫做 multiprocessing 的 Python 庫。

假設我們有100個頁面要發起請求,我們希望給將任務量平均分給每個處理器。假設你有 N 個 CPU,你可以把所有的頁面分成 N 個部分,每個 CPU 處理一個部分。每個進程都將有自己的名字,目標函數以及需要處理的參數。每個進程的名字可以在之後被調用,以便將獲取到的信息寫入具體的文件中。

後來,我將 4000 個頁面分成 4 份,我的 4 個 CPU 各分到 1000 個,於是總的請求數增加到 4 個/秒,總的抓取時間就減少到了 17 分鐘左右。

👁 Image
...

文字版見:

最後,祝大家爬得開心順利!記得多關注我們哦!!

文-Jekaterina Kokatjuhha
編譯-歐剃

人生苦短,我用 Python!簡潔高效,新手友好!來自矽谷的「Python 編程入門」基石納米學位課程,已經開放報名,限量課程席位!點擊以下卡片,免費預覽和體驗課程。

Python 編程入門_Python基礎教程_Python培訓班_Python快速入門-優達學城(Udacity)官網
您可能感興趣
免責聲明:本文內容來源于知乎專欄,文章觀點不代表壹讀立場,如若侵犯到您的權益,或涉不實謠言,敬請向我們提出檢舉
最新文章 / 服務條款 / 私隱保護 / DMCA / 聯絡我們

壹讀/READ01.COM