beautifulsoup爬取網頁中的表格_用 Python 爬取網頁

來自公眾號:優達學城Udacity

作者:Kerry Parker

編譯:歐剃

作為數據科學家的第一個任務,就是做網頁爬取。那時候,我對使用代碼從網站上獲取數據這項技術完全一無所知,它偏偏又是最有邏輯性并且最容易獲得的數據來源。在幾次嘗試之后,網頁爬取對我來說就幾乎是種本能行為了。如今,它更成為了我幾乎每天都要用到的少數幾個技術之一。

在今天的文章中,我將會用幾個簡單的例子,向大家展示如何爬取一個網站——比如從?Fast Track?上獲取 2018 年 100 強企業的信息。用腳本將獲取信息的過程自動化,不但能節省手動整理的時間,還能將所有企業數據整理在一個結構化的文件里,方便進一步分析查詢。

太長不看版:如果你只是想要一個最基本的 Python 爬蟲程序的示例代碼,本文中所用到的全部代碼都放在?GitHub?(https://github.com/kaparker/tutorials/blob/master/pythonscraper/websitescrapefasttrack.py),歡迎自取。

準備工作

每一次打算用 Python 搞點什么的時候,你問的第一個問題應該是:“我需要用到什么庫”。

網頁爬取方面,有好幾個不同的庫可以用,包括:

  • Beautiful Soup

  • Requests

  • Scrapy

  • Selenium

今天我們打算用 Beautiful Soup 庫。你只需要用?pip(Python包管理工具)就能很方便地將它裝到電腦上:

2b4745ea17380028e206b534fac0357d.png

安裝完畢之后,我們就可以開始啦!

檢查網頁

為了明確要抓取網頁中的什么元素,你需要先檢查一下網頁的結構。

以?Tech Track 100強企業(https://link.zhihu.com/?target=http%3A//www.fasttrack.co.uk/league-tables/tech-track-100/league-table/)?這個頁面為例,你在表格上點右鍵,選擇“檢查”。在彈出的“開發者工具”中,我們就能看到頁面中的每個元素,以及其中包含的內容。

da2aca353e5348b06d436eaafce1400f.png
2af1a24f2bef1bd2a2f36cc693136432.png

右鍵點擊你想要查看的網頁元素,選擇“檢查”,就能看到具體的 HTML 元素內容

既然數據都保存在表格里,那么只需要簡單的幾行代碼就能直接獲取到完整信息。如果你希望自己練習爬網頁內容,這就是一個挺不錯的范例。但請記住,實際情況往往不會這么簡單。

這個例子里,所有的100個結果都包含在同一個頁面中,還被??標簽分隔成行。但實際抓取過程中,許多數據往往分布在多個不同的頁面上,你需要調整每頁顯示的結果總數,或者遍歷所有的頁面,才能抓取到完整的數據。

在表格頁面上,你可以看到一個包含了所有100條數據的表格,右鍵點擊它,選擇“檢查”,你就能很容易地看到這個 HTML 表格的結構。包含內容的表格本體是在這樣的標簽里:

c01abe9f8401c5982d34a8b4dc59b704.png

每一行都是在一個??標簽里,也就是我們不需要太復雜的代碼,只需要一個循環,就能讀取到所有的表格數據,并保存到文件里。

附注:你還可以通過檢查當前頁面是否發送了 HTTP GET 請求,并獲取這個請求的返回值,來獲取顯示在頁面上的信息。因為 HTTP GET 請求經常能返回已經結構化的數據,比如 JSON 或者 XML 格式的數據,方便后續處理。你可以在開發者工具里點擊 Network 分類(有必要的話可以僅查看其中的 XHR 標簽的內容)。這時你可以刷新一下頁面,于是所有在頁面上載入的請求和返回的內容都會在 Network 中列出。此外,你還可以用某種 REST 客戶端(比如?Insomnia)來發起請求,并輸出返回值。
6c16c3bbcc3dfd6cfedc82c4e8b95e31.png
刷新頁面后,Network 標簽頁的內容更新了

用 Beautiful Soup 庫處理網頁的 HTML 內容

在熟悉了網頁的結構,了解了需要抓取的內容之后,我們終于要拿起代碼開工啦~

首先要做的是導入代碼中需要用到的各種模塊。上面我們已經提到過?BeautifulSoup,這個模塊可以幫我們處理 HTML 結構。接下來要導入的模塊還有?urllib,它負責連接到目標地址,并獲取網頁內容。最后,我們需要能把數據寫入 CSV 文件,保存在本地硬盤上的功能,所以我們要導入?csv庫。當然這不是唯一的選擇,如果你想要把數據保存成 json 文件,那相應的就需要導入?json?庫。

3eed8fcd4fb7ebcd9d4d1a4598adec2b.png

下一步我們需要準備好需要爬取的目標網址。正如上面討論過的,這個網頁上已經包含了所有我們需要的內容,所以我們只需要把完整的網址復制下來,賦值給變量就行了:

3c268339739ab410baec2fcfa77756c5.png

接下來,我們就可以用?urllib?連上這個URL,把內容保存在?page?變量里,然后用 BeautifulSoup 來處理頁面,把處理結果存在?soup?變量里:

a18d86d16b5252bb5b63e3bde457c104.png

這時候,你可以試著把?soup?變量打印出來,看看里面已經處理過的 html 數據長什么樣:

f28670a772229da06bba9d58ca000d85.png

如果變量內容是空的,或者返回了什么錯誤信息,則說明可能沒有正確獲取到網頁數據。你也許需要用一些錯誤捕獲代碼,配合?urllib.error?(https://docs.python.org/3/library/urllib.error.html)模塊,來發現可能存在的問題。

查找 HTML 元素

既然所有的內容都在表格里(

?標簽),我們可以在?soup?對象里搜索需要的表格,然后再用?find_all?方法,遍歷表格中的每一行數據。

如果你試著打印出所有的行,那應該會有 101 行 —— 100 行內容,加上一行表頭。

33e1225ed53d1d69c01e3e482fe0f215.png

看看打印出來的內容,如果沒問題的話,我們就可以用一個循環來獲取所有數據啦。

如果你打印出 soup 對象的前 2 行,你可以看到,每一行的結構是這樣的:

309c0232fd194ce6dc9a4d4e4b2ba357.png

可以看到,表格中總共有 8 列,分別是 Rank(排名)、Company(公司)、Location(地址)、Year End(財年結束)、Annual Sales Rise(年度銷售增長)、Latest Sales(本年度銷售額)、Staff(員工數)和 Comments(備注)。

這些都是我們所需要的數據。

這樣的結構在整個網頁中都保持一致(不過在其他網站上可能就沒這么簡單了!),所以我們可以再次使用?find_all?方法,通過搜索??元素,逐行提取出數據,存儲在變量中,方便之后寫入 csv 或 json 文件。

循環遍歷所有的元素并存儲在變量中

在 Python 里,如果要處理大量數據,還需要寫入文件,那列表對象是很有用的。我們可以先聲明一個空列表,填入最初的表頭(方便以后CSV文件使用),而之后的數據只需要調用列表對象的?append?方法即可。

801945224c076780efd2aa0ff2973535.png

這樣就將打印出我們剛剛加到列表對象?rows?中的第一行表頭。

你可能會注意到,我輸入的表頭中比網頁上的表格多寫了幾個列名,比如?Webpage(網頁)和?Description(描述),請仔細看看上面打印出的 soup 變量數據——第二行第二列的數據里,可不只有公司名字,還有公司的網址和簡單描述。所以我們需要這些額外的列來存儲這些數據。

下一步,我們遍歷所有100行數據,提取內容,并保存到列表中。

循環讀取數據的方法:

f170d668c303e905ef6834438bf85ff4.png

因為數據的第一行是 html 表格的表頭,所以我們可以跳過不用讀取它。因為表頭用的是??標簽,沒有用??標簽,所以我們只要簡單地查詢?標簽內的數據,并且拋棄空值即可。

接著,我們將 data 的內容讀取出來,賦值到變量中:

9f9cc86304c94ae642af88b590011675.png

如上面的代碼所示,我們按順序將 8 個列里的內容,存儲到 8 個變量中。當然,有些數據的內容還需有額外的清理,去除多余的字符,導出所需的數據。

數據清理

如果我們打印出?company?變量的內容,就能發現,它不但包含了公司名稱,還包括和描述。如果我們打印出?sales?變量的內容,就能發現它還包括一些備注符號等需要清除的字符。

6e00bc541c4ff9c78dabe56045cf5408.png

我們希望把?company?變量的內容分割成公司名稱和描述兩部分。這用幾行代碼就能搞定。再看看對應的 html 代碼,你會發現這個單元格里還有一個??元素,這個元素里只有公司名稱。另外,還有一個??鏈接元素,包含一個指向該公司詳情頁面的鏈接。我們一會也會用到它!

f8b2c9496608153373cfb3fc46f44b67.png

為了區分公司名稱和描述兩個字段,我們再用?find?方法把??元素里的內容讀取出來,然后刪掉或替換?company?變量中的對應內容,這樣變量里就只會留下描述了。

要刪除?sales?變量中的多余字符,我們用一次?strip?方法即可。

9649dce06161772ed72f2a61523861cb.png

最后我們要保存的是公司網站的鏈接。就像上面說的,第二列中有一個指向該公司詳情頁面的鏈接。每一個公司的詳情頁都有一個表格,大部分情況下,表格里都有一個公司網站的鏈接。

e3107ea314a40bb84e76fd8718f01895.png

檢查公司詳情頁里,表格中的鏈接

為了抓取每個表格中的網址,并保存到變量里,我們需要執行以下幾個步驟:

在最初的 fast track 網頁上,找到需要訪問的公司詳情頁的鏈接。

發起一個對公司詳情頁鏈接的請求

用 Beautifulsoup 處理一下獲得的 html 數據

找到需要的鏈接元素

正如上面的截圖那樣,看過幾個公司詳情頁之后,你就會發現,公司的網址基本上就在表格的最后一行。所以我們可以在表格的最后一行里找??元素。

190b7ad7d6da8b252bb15c7a7262d5e3.png

同樣,有可能出現最后一行沒有鏈接的情況。所以我們增加了?try... except?語句,如果沒有發現網址,則將變量設置成?None。當我們把所有需要的數據都存在變量中的以后(還在循環體內部),我們可以把所有變量整合成一個列表,再把這個列表?append?到上面我們初始化的 rows 對象的末尾。

4381d1f3dfd826b84ee1f2a12582276f.png

上面代碼的最后,我們在結束循環體之后打印了一下 rows 的內容,這樣你可以在把數據寫入文件前,再檢查一下。

寫入外部文件

最后,我們把上面獲取的數據寫入外部文件,方便之后的分析處理。在 Python 里,我們只需要簡單的幾行代碼,就可以把列表對象保存成文件。

c355f564c7d5ccbc258270cca9b64098.png

最后我們來運行一下這個 python 代碼,如果一切順利,你就會發現一個包含了 100 行數據的 csv 文件出現在了目錄中,你可以很容易地用 python 讀取和處理它。

總結

這篇簡單的 Python 教程中,我們一共采取了下面幾個步驟,來爬取網頁內容:

連接并獲取一個網頁的內容

用 BeautifulSoup 處理獲得的 html 數據

在 soup 對象里循環搜索需要的 html 元素

進行簡單的數據清理

把數據寫入 csv 文件中

如果有什么沒說清楚的,歡迎大家在下面留言,我會盡可能給大家解答的!

附:?本文全部代碼(https://github.com/kaparker/tutorials/blob/master/pythonscraper/websitescrapefasttrack.py)

祝你的爬蟲之旅有一個美好的開始!

編譯來源:?towardsdatascience.com

●輸入m獲取文章目錄

推薦↓↓↓

d987dc7e13317e94b838cea692ad3460.png

人工智能與大數據技術

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/539011.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/539011.shtml
英文地址,請注明出處:http://en.pswp.cn/news/539011.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java中Runnable和Thread的區別

概述 Runnable 是接口。 Thread 是類,且實現了Runnable接口。 Thread部分源碼 public class Threadimplements Runnable {private static class Caches{static final ConcurrentMap subclassAudits new ConcurrentHashMap();static final ReferenceQueue subcla…

python 神經網絡工具_神經網絡15分鐘入門!使用python從零開始寫一個兩層神經網絡...

本篇是該系列的第三篇,建議在閱讀本篇文章之前先看前兩篇文章。在本文中將使用python實現之前描述的兩層神經網絡,并完成所提出的“象限分類”的問題。需要注意的是,雖然標題叫做神經網絡15分鐘入門,但是到這篇文章,對…

12.3目錄結構

目錄結構 設計好目錄結構 可讀性高可維護性高比如一個Foo項目Foo/--- bin/--- foo--- foo/--- tests/--- _init__.py--- test_main.py--- init.py--- main.py---doc--- conf.py---abc.rst--- setup.py--- requirement.txt--- README簡要解釋一下: bin/:存放項目的一…

pyecharts添加文字_超燃的文字云效果,用Python就能輕松get!

本文轉載自公眾號:數據森麟(ID:shujusenlin)作者:葉庭云鏈接:https://blog.csdn.net/fyfugoyfa/ 01 / 詞云圖詞云圖是一種用來展現高頻關鍵詞的可視化表達,通過文字、色彩、圖形的搭配,產生有沖擊力地視覺效…

同步關鍵詞synchronized

概述 synchronized是java中的一個關鍵字,也就是說是Java語言內置的特性。 synchronized( 一個任意的對象(鎖) ){ 代碼塊中放操作共享數據的代碼。 } public synchronized int getIndex() {return 1;}public static synchronized int getN…

python連接mysql用哪個模塊_Python連接MySQL數據庫之pymysql模塊使用

Python3連接MySQL本文介紹Python3連接MySQL的第三方庫--PyMySQL的基本使用。PyMySQL介紹PyMySQL 是在 Python3.x 版本中用于連接 MySQL 服務器的一個庫,Python2中則使用mysqldb。Django中也可以使用PyMySQL連接MySQL數據庫。PyMySQL安裝pip install pymysql連接數據…

mysql 創建視圖 主鍵_MySQL數據庫基礎操作命令,本文助你更上一層樓!

今天介紹的是關于Mysql數據庫一些操作的基礎命令用戶與權限創建用戶mysql>create user test identified by BaC321#; 修改密碼5.5版本及以前的命令mysql>set password for testpassowrd(!1A2#3); 5.6及以上命令mysql>update mysql.user set authentication_stringpass…

mysql 聚合函數 怎么用在條件里_MySql 中聚合函數增加條件表達式的方法

Mysql 與聚合函數在一起時候where條件和having條件的過濾時機where 在聚合之前過濾當一個查詢包含了聚合函數及where條件&#xff0c;像這樣的情況select max(cid) from t where t.id<999這時候會先進行過濾&#xff0c;然后再聚合。先過濾出ID《999的記錄&#xff0c;再查找…

drbd(三):drbd的狀態說明

1.幾種獲取狀態信息的方法 drbd有很多獲取信息的方式。在drbd84和之前的版本&#xff0c;大多都使用cat /proc/drbd來獲取信息&#xff0c;多數情況下&#xff0c;這個文件展示的信息對于管理和維護drbd來說已經足夠。 例如以下是drbd84上兩個volume的節點狀態信息&#xff1a;…

Lock的lock()方法

ReentrantLock是JDK唯一實現了Lock接口的類 lock() 是平常使用得最多的一個方法&#xff0c;就是用來獲取鎖。如果鎖已被其他線程獲取&#xff0c;則進行等待。 由于在前面講到如果采用Lock&#xff0c;必須主動去釋放鎖&#xff0c;并且在發生異常時&#xff0c;不會自動釋放鎖…

Lock的tryLock()方法

概述 tryLock()方法是有返回值的&#xff0c;它表示用來嘗試獲取鎖&#xff0c;如果獲取成功&#xff0c;則返回true&#xff0c;如果獲取失敗&#xff08;即鎖已被其他線程獲取&#xff09;&#xff0c;則返回false&#xff0c;這個方法無論如何都會立即返回。在拿不到鎖時不…

python requests庫詳解_python的requests庫詳解

快速上手迫不及待了嗎&#xff1f;本頁內容為如何入門 Requests 提供了很好的指引。其假設你已經安裝了 Requests。如果還沒有&#xff0c;去安裝一節看看吧。首先&#xff0c;確認一下&#xff1a;Requests 已安裝Requests 是最新的讓我們從一些簡單的示例開始吧。發送請求使用…

python QTreeWidgetItem下面有幾個子tree_python-nlp ch1筆記:nlp的基礎應用、高級應用、python優勢、nltk環境搭建...

本帖是對(印度)Jalaj Thanaki作品《python自然語言處理》的翻譯、縮減及改編~nlp的基礎應用NLP是AI的子分支&#xff0c;其相關概念可以用于以下專家系統中&#xff1a;語音識別系統問答系統機器翻譯文本摘要情感分析基于模板的聊天機器人文本分類主題分割nlp的高級應用理解自然…

C#使用ListView更新數據出現閃爍解決辦法

C#使用ListView更新數據出現閃爍解決辦法 在使用vs自動控件ListView控件時候&#xff0c;更新里面的部分代碼時候出現閃爍的情況 如圖&#xff1a; 解決以后&#xff1a; 解決辦法使用雙緩沖&#xff1a;添加新類繼承ListView 對其重寫 1 public class DoubleBufferListView : …

Lock的tryLock(long time, TimeUnit unit)方法

概述 tryLock(long time, TimeUnit unit)方法和tryLock()方法是類似的&#xff0c;只不過區別在于這個方法在拿不到鎖時會等待一定的時間&#xff0c;在時間期限之內如果還拿不到鎖&#xff0c;就返回false。如果一開始拿到鎖或者在等待期間內拿到了鎖&#xff0c;則返回true。…

python語音識別的第三方庫_python標準庫+內置函數+第三方庫: 7.音頻處理

python標準庫內置函數第三方庫 欲善其事&#xff0c;必先利其器 這其器必是python的標準庫內置函數&#xff0c;話說許多第三方庫&#xff0c; 也是對標準庫的使用&#xff0c;進行封裝&#xff0c;使得使用起來更方便。 這些庫以使用場景來分類: 7、音頻處理 音頻處理主要適用…

SperingBoot+vue文件上傳下載預覽

上傳文件&#xff1a; 前端&#xff1a; 整個過程&#xff0c;就是在使用FormData 添加 上File&#xff08;這個Blob&#xff09;&#xff0c;并且key要和后臺的名字對應上在點擊上傳按鈕開始上傳之前&#xff0c;使用了URL.createObjectURL(File)創建blobUrl&#xff0c;給了…

keepalived腦裂問題查找

在自己環境做keepalivedredis實驗時&#xff0c;當重啟了備用redies機器后&#xff0c;發現兩臺redies主機都拿到了VIP [plain] view plaincopy [rootredis2 ~]# ip addr list 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN link/loopbac…

python 多線程并行 矩陣乘法_python實現簡單的并行矩陣乘法

python實現簡單的并行矩陣乘法python實現簡單的并行矩陣乘法本文采用的矩陣乘法方式是利用一個矩陣的行和二個矩陣的列相乘時不會互相影響。假設A(m,n)表示矩陣的m行&#xff0c;n列。那么C(m,m)A(m,n) * B(n,m) &#xff1a;計算C矩陣時候分解成&#xff1a;process-1&#xf…

停止Java線程,小心interrupt()方法

轉自http://www.blogjava.NET/jinfeng_wang/archive/2008/04/27/196477.html ---------------------------------------------------------------------------------------------------- 程序是很簡易的。然而&#xff0c;在編程人員面前&#xff0c;多線程呈現出了一組新的難…