自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何使用Python遍歷HTML表和抓取表格數(shù)據(jù)

譯文
開(kāi)發(fā) 前端
遍歷HTML表通常很棘手,因此需要?jiǎng)?chuàng)建一個(gè)指南來(lái)幫助人們理解如何使用Python從公共HTML表中提取表格數(shù)據(jù)。

譯者 | 李睿

審校 | 孫淑娟

表格數(shù)據(jù)是網(wǎng)絡(luò)上最好的數(shù)據(jù)來(lái)源之一。它們可以存儲(chǔ)大量有用的信息,同時(shí)又不丟失易于閱讀的格式,使其成為數(shù)據(jù)相關(guān)項(xiàng)目的金礦。

無(wú)論是抓取足球賽事數(shù)據(jù)還是提取股票市場(chǎng)數(shù)據(jù),都可以使用Python從HTML表中快速訪問(wèn)、解析和提取數(shù)據(jù),而這需要感謝Requests和Beautiful Soup。

理解HTML表的結(jié)構(gòu)

從視覺(jué)上看,HTML表是一組以表格格式顯示信息的行和列。本文主要介紹如何抓取表格數(shù)據(jù):

為了能夠抓取該表中包含的數(shù)據(jù),需要更深入地研究它的編碼。

一般來(lái)說(shuō),HTML表實(shí)際上是使用以下HTML標(biāo)記構(gòu)建的:

  • <table>:標(biāo)志著HTML表的開(kāi)始  
  • <th> 或 <thead>:定義行作為HTML表的標(biāo)題  
  • <tbody>:表示數(shù)據(jù)所在的部分
  • <tr>:表示表中的一行
  • <td>:在表中定義單元格  

??然而,正如人們?cè)趯?shí)際場(chǎng)景中看到的,并不是所有開(kāi)發(fā)人員在構(gòu)建表時(shí)都遵循這些約定,這使得一些項(xiàng)目比其他項(xiàng)目更難。不過(guò),了解它們的工作原理對(duì)于找到正確的方法至關(guān)重要。

在瀏覽器中輸入表的??URL??,并檢查頁(yè)面,看看在底層發(fā)生了什么。  

這就是這個(gè)頁(yè)面非常適合練習(xí)用Python抓取表格數(shù)據(jù)的原因。有一個(gè)明確的<table>標(biāo)簽對(duì)打開(kāi)和關(guān)閉表,所有相關(guān)數(shù)據(jù)都在<tbody>標(biāo)簽中。它只顯示與前端所選條目數(shù)量匹配的10行。  

關(guān)于這個(gè)表還有一些需要了解的事情,即想要抓取的條目共有57個(gè),并且似乎有兩種訪問(wèn)數(shù)據(jù)的解決方案。第一種是點(diǎn)擊下拉菜單,選擇“100”,顯示所有條目:

或者單擊“下一步”按鈕以瀏覽分頁(yè)。

那么哪一種方案會(huì)更好?這兩種解決方案都會(huì)給腳本增加額外的復(fù)雜性,因此,先檢查從哪里提取數(shù)據(jù)。  

當(dāng)然,因?yàn)檫@是一個(gè)HTML表,因此所有數(shù)據(jù)都應(yīng)該在HTML文件本身上,而不需要AJAX注入。要驗(yàn)證這一點(diǎn),需要右擊>查看頁(yè)面來(lái)源。接下來(lái),復(fù)制一些單元格并在源代碼中搜索它們。  

對(duì)來(lái)自不同分頁(yè)單元格的多個(gè)條目執(zhí)行了相同的操作,盡管前端沒(méi)有顯示,但似乎所有目標(biāo)數(shù)據(jù)都在其中。

有了這些信息,就可以開(kāi)始編寫(xiě)代碼了。

使用Python的Beautiful Soup刪除HTML表

因?yàn)橐@取的所有員工數(shù)據(jù)都在HTML文件中,所以可以使用Requests庫(kù)發(fā)送HTTP請(qǐng)求,并使用Beautiful Soup解析響應(yīng)。  

注:對(duì)于網(wǎng)頁(yè)抓取的新手,本文作者在Python教程中為初學(xué)者創(chuàng)建了一個(gè)網(wǎng)絡(luò)抓取教程。盡管新手沒(méi)有經(jīng)驗(yàn)也可以學(xué)習(xí),但從基礎(chǔ)開(kāi)始總是一個(gè)好主意。  

1.發(fā)送主請(qǐng)求  

在這個(gè)項(xiàng)目中創(chuàng)建一個(gè)名為python-html-table的新目錄,然后創(chuàng)建一個(gè)名為bs4-table-scraper的新文件夾,最后創(chuàng)建一個(gè)新的python_table_scraper.py文件。

從終端pip3安裝請(qǐng)求beautifulsoup4,并將它們導(dǎo)入到項(xiàng)目中,如下所示:

import requests 
from bs4 import BeautifulSoup

要用requests發(fā)送HTTP請(qǐng)求,所需要做的就是設(shè)置一個(gè)URL并通過(guò)request.get()傳遞它,將返回的HTML存儲(chǔ)在響應(yīng)變量中并輸出response.status_code。  

注:如果完全不熟悉Python,可以使用命令python3python_table_scraper.py從終端運(yùn)行代碼。  

url = 'https://datatables.net/examples/styling/stripe.html'  
response = requests.get(url)
print(response.status_code)

如果它有效,將會(huì)返回一個(gè)200狀態(tài)碼。任何其他情況都意味著IP正在被網(wǎng)站設(shè)置的反抓取系統(tǒng)拒絕。一個(gè)潛在的解決方案是在腳本中添加自定義標(biāo)題,使腳本看起來(lái)更加人性化,但這可能還不夠。另一個(gè)解決方案是使用Web抓取API處理所有這些復(fù)雜的問(wèn)題。  

2.使用Beautiful Soup構(gòu)建解析器  

在提取數(shù)據(jù)之前,需要將原始HTML轉(zhuǎn)換為格式化或解析的數(shù)據(jù)。將這個(gè)解析后的HTML存儲(chǔ)到一個(gè)soup對(duì)象中,如下所示:

soup = BeautifulSoup(response.text, 'html.parser')

從這里開(kāi)始,可以使用HTML標(biāo)記及其屬性遍歷解析樹(shù)。  

如果返回到頁(yè)面上的表,已經(jīng)看到該表用類(lèi)stripe dataTable封裝在<table>標(biāo)記之間,可以使用它來(lái)選擇該表。

table = soup.find('table', class_ = 'stripe') 
print(table)

注:在測(cè)試之后,添加第二個(gè)類(lèi)(dataTable)并沒(méi)有返回元素。實(shí)際上,在return元素中,表的類(lèi)只是stripe。還可以使用id='example'。

以下是它返回的結(jié)果:

Table Return

既然已經(jīng)獲取了表,就可以遍歷行并獲取所需的數(shù)據(jù)。

3.遍歷HTML表  

回想一下HTML表的結(jié)構(gòu),每一行都由<tr>元素表示,其中有包含數(shù)據(jù)的<td>元素,所有這些都包裝在<tbody>標(biāo)簽對(duì)之間。

為了提取數(shù)據(jù),將創(chuàng)建兩個(gè)for looks,一個(gè)用于抓取表的<tbody>部分(所有行所在的位置),另一個(gè)用于將所有行存儲(chǔ)到可以使用的變量中:

for employee_data in table.find_all('tbody'):  
rows = employee_data.find_all('tr')
print(rows)

在行中,將存儲(chǔ)表正文部分中找到的所有<tr>元素。如果遵循這個(gè)邏輯,下一步就是將每一行存儲(chǔ)到單個(gè)對(duì)象中,并循環(huán)遍歷它們以查找所需的數(shù)據(jù)。

首先,嘗試使用.querySelectorAll()方法在瀏覽器控制臺(tái)上選擇第一個(gè)員工的名字。這個(gè)方法的一個(gè)真正有用的特性是,可以越來(lái)越深入地實(shí)現(xiàn)大于(>)符號(hào)的層次結(jié)構(gòu),以定義父元素(在左側(cè))和要獲取的子元素(在右側(cè))。

document.querySelectorAll('table.stripe &amp;amp;amp;gt; tbody &amp;amp;amp;gt; tr &amp;amp;amp;gt; td')[0]

如上所見(jiàn),一旦抓取所有<td>元素,這些元素就會(huì)成為節(jié)點(diǎn)列表。因?yàn)椴荒芤蕾?lài)類(lèi)來(lái)獲取每個(gè)單元格,所以只需要知道它們?cè)谒饕械奈恢?,而第一個(gè)name是0。

從那里,可以像這樣編寫(xiě)代碼:  

for row in rows:    
name = row.find_all('td')[0].text
print(name)

簡(jiǎn)單地說(shuō),逐個(gè)獲取每一行,并找到其中的所有單元格,一旦有了列表,只獲取索引中的第一個(gè)單元格(position 0),然后使用.text方法只獲取元素的文本,忽略不需要的HTML數(shù)據(jù)。

這是一個(gè)包含所有員工姓名的列表! 對(duì)于其余部分,只需要遵循同樣的邏輯:

position = row.find_all('td')[1].text 
office = row.find_all('td')[2].text
age = row.find_all('td')[3].text
start_date = row.find_all('td')[4].text
salary = row.find_all('td')[5].text

然而,將所有這些數(shù)據(jù)輸出在控制臺(tái)上并沒(méi)有太大幫助。與其相反,可以將這些數(shù)據(jù)存儲(chǔ)為一種、更有用的新格式。

4.將表格數(shù)據(jù)存儲(chǔ)到JSON文件中  

雖然可以輕松地創(chuàng)建一個(gè)CSV文件并將數(shù)據(jù)發(fā)送到那里,但如果可以使用抓取的數(shù)據(jù)創(chuàng)建一些新內(nèi)容,那么這將不是最容易管理的格式。

盡管如此,以前做的一個(gè)項(xiàng)目解釋了如何創(chuàng)建一個(gè)CSV文件來(lái)存儲(chǔ)抓取的數(shù)據(jù)。  

好消息是,Python有自己的JSON模塊來(lái)處理JSON對(duì)象,所以不需要安裝任何程序,只需要導(dǎo)入它。  

import json

但是,在繼續(xù)并創(chuàng)建JSON文件之前,需要將所有這些抓取的數(shù)據(jù)轉(zhuǎn)換為一個(gè)列表。為此,將在循環(huán)外部創(chuàng)建一個(gè)空數(shù)組。  

employee_list = []

然后向它追加數(shù)據(jù),每個(gè)循環(huán)向數(shù)組追加一個(gè)新對(duì)象。

employee_list.append({    'Name': name,    'Position': position,    'Office': office,    'Age': age,    'Start date': start_date,    'salary': salary })

如果print(employee_list),其結(jié)果如下:

Employee_List

還是有點(diǎn)混亂,但已經(jīng)有了一組準(zhǔn)備轉(zhuǎn)換為JSON的對(duì)象。  

注:作為測(cè)試,輸出employee_list的長(zhǎng)度,它返回57,這是抓取的正確行數(shù)(行現(xiàn)在是數(shù)組中的對(duì)象)。  

將列表導(dǎo)入到JSON只需要兩行代碼:  

with open('json_data', 'w') as json_file:   
json.dump(employee_list, json_file, indent=2)
  • 首先,打開(kāi)一個(gè)新文件,傳入想要的文件名稱(chēng)(json_data)和'w',因?yàn)橄胍獙?xiě)入數(shù)據(jù)。  
  • 接下來(lái),使用.dump()函數(shù)從數(shù)組(employee_list)和indent=2中轉(zhuǎn)儲(chǔ)數(shù)據(jù),這樣每個(gè)對(duì)象都有自己的行,而不是所有內(nèi)容都在一個(gè)不可讀的行中。  

5.運(yùn)行腳本和完整代碼  

如果一直按照下面的方法做,那么代碼庫(kù)應(yīng)該是這樣的:

#dependencies 
import requests
from bs4 import BeautifulSoup
import json
url = 'http://api.scraperapi.com?api_key=51e43be283e4db2a5afbxxxxxxxxxxx&url=https://datatables.net/examples/styling/stripe.html'
#empty array
employee_list = []
#requesting and parsing the HTML file
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
#selecting the table
table = soup.find('table', class_ = 'stripe')
#storing all rows into one variable
for employee_data in table.find_all('tbody'):
rows = employee_data.find_all('tr')
#looping through the HTML table to scrape the data
for row in rows:
name = row.find_all('td')[0].text
position = row.find_all('td')[1].text
office = row.find_all('td')[2].text
age = row.find_all('td')[3].text
start_date = row.find_all('td')[4].text
salary = row.find_all('td')[5].text
#sending scraped data to the empty array
employee_list.append({
'Name': name,
'Position': position,
'Office': office,
'Age': age,
'Start date': start_date,
'salary': salary
})
#importing the array to a JSON file
with open('employee_data', 'w') as json_file:
json.dump(employee_list, json_file, indent=2)

注:在這里為場(chǎng)景添加了一些注釋。

以下是JSON文件中的前三個(gè)對(duì)象:

以JSON格式存儲(chǔ)抓取數(shù)據(jù)允將信息用于新的應(yīng)用程序

使用Pandas抓取HTML表  

在離開(kāi)頁(yè)面之前,希望探索第二種抓取HTML表的方法。只需幾行代碼,就可以從HTML文檔中抓取所有表格數(shù)據(jù),并使用Pandas將其存儲(chǔ)到數(shù)據(jù)框架中。  

在項(xiàng)目的目錄中創(chuàng)建一個(gè)新文件夾(將其命名為panda-html-table-scraper),并創(chuàng)建一個(gè)新文件名pandas_table_scraper.py。  

打開(kāi)一個(gè)新的終端,導(dǎo)航到剛剛創(chuàng)建的文件夾(cdpanda-html-table-scraper),并從那里安裝pandas:

pip install pandas

在文件的頂部導(dǎo)入它。

import pandas as pd

Pandas有一個(gè)名為read_html()的函數(shù),它主要抓取目標(biāo)URL,并返回所有HTML表作為DataFrame對(duì)象的列表。  

要實(shí)現(xiàn)這一點(diǎn),HTML表至少需要結(jié)構(gòu)化,因?yàn)樵摵瘮?shù)將查找<table>之類(lèi)的元素來(lái)標(biāo)識(shí)文件中的表。

為了使用這個(gè)函數(shù),需要?jiǎng)?chuàng)建一個(gè)新變量,并將之前使用的URL傳遞給它:  

employee_datapd.read_html('http://api.scraperapi.com?api_key=51e43be283e4db2a5afbxxxxxxxxxxxx&url=https://datatables.net/examples/styling/stripe.html')

當(dāng)輸出它時(shí),它將返回頁(yè)面內(nèi)的HTML表列表。  

HTMLTables

如果比較DataFrame中的前三行,它們與采用BeautifulSoup抓取的結(jié)果完全匹配。  

為了處理JSON,Pandas可以有一個(gè)內(nèi)置的.to_json()函數(shù)。它將把DataFrame對(duì)象列表轉(zhuǎn)換為JSON字符串。  

而所需要做的就是調(diào)用DataFrame上的方法,并傳入路徑、格式(split,data,records,index等),并添加縮進(jìn)以使其更具可讀性:  

employee_data[0].to_json('./employee_list.json', orient='index', indent=2)

如果現(xiàn)在運(yùn)行代碼,其結(jié)果文件如下:

Resulting File

注意,需要從索引([0])中選擇表,因?yàn)?read_html()返回一個(gè)列表,而不是單個(gè)對(duì)象。  

以下是完整的代碼以供參考

import pandas as pd  
employee_data = pd.read_html('http://api.scraperapi.com?api_key=51e43be283e4db2a5afbxxxxxxxxxxxx&url=https://datatables.net/examples/styling/stripe.html')
employee_data[0].to_json('./employee_list.json', orient='index', indent=2)

有了這些新知識(shí),就可以開(kāi)始抓取網(wǎng)絡(luò)上幾乎所有的HTML表了。只要記住,如果理解了網(wǎng)站的結(jié)構(gòu)和背后的邏輯,就沒(méi)有什么是不能抓取的。  

也就是說(shuō),只要數(shù)據(jù)在HTML文件中,這些方法就有效。如果遇到動(dòng)態(tài)生成的表,則需要找到一種新的方法。  

原文標(biāo)題:??How to Use Python to Loop Through HTML Tables and Scrape Tabular Data??,作者:Zoltan Bettenbuk?

責(zé)任編輯:華軒 來(lái)源: 51CTO
相關(guān)推薦

2010-07-16 11:16:40

Perl抓取網(wǎng)頁(yè)

2017-05-08 15:47:06

2017-02-24 11:00:57

iOS抓取HTML解析數(shù)據(jù)

2024-11-14 08:00:00

Python迭代器

2017-01-20 08:44:53

Apache Flum抓取數(shù)據(jù)

2020-08-24 14:21:27

app爬蟲(chóng)Python

2021-06-29 15:52:03

PythonPOST

2020-11-20 10:52:54

Antd表格日程

2021-07-09 18:26:41

PythonMySQL MongoDB

2010-11-11 10:41:03

sql server遍

2010-11-24 13:11:06

MySQL遍歷數(shù)據(jù)表

2010-11-11 11:00:06

sql server遍

2019-09-29 09:08:41

Python數(shù)據(jù)庫(kù)Google

2011-12-15 01:01:16

ibmdw

2020-10-12 08:19:43

Python爬蟲(chóng)網(wǎng)頁(yè)數(shù)據(jù)

2022-06-06 08:21:13

MySQL數(shù)據(jù)庫(kù)命令

2020-04-13 13:50:15

Python電子表格編程語(yǔ)言

2017-08-10 13:43:00

大數(shù)據(jù)數(shù)據(jù)表格優(yōu)化設(shè)計(jì)

2012-10-29 11:34:26

IBMdw

2020-07-08 15:43:26

數(shù)據(jù)機(jī)器學(xué)習(xí)提取
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)