Web爬取是從Web上收集和解析資料的過程。Python社群已經開發出一些非常強大的web爬取工具。其中,Pandas read_html()是從html表中爬取資料的一種快速方便的方法。
在本文中,你將學習Pandas read_html()來處理以下常見問題,並幫助你進行web爬取。
1.從字串讀取表
2.從URL讀取表
3.從檔案讀取表
4.使用parse_dates分析日期列
5.使用converters顯式轉換型別
6.多索引、標題和索引列
7.用match匹配表
8.使用屬性篩選表
9.使用缺失值
請檢查Notebook的原始碼(https://github.com/BindiChen/machine-learning/blob/master/data-analysis/024-pandas-read_html/pandas-read_html.ipynb)。
1.從字串中讀取表在第一個示例中,我們將從字串中讀取HTML表。
html_string = """<table> <thead> <tr> <th>date</th> <th>name</th> <th>year</th> <th>cost</th> <th>region</th> </tr> </thead> <tbody> <tr> <td>2020-01-01</td> <td>Jenny</td> <td>1998</td> <td>0.2</td> <td>South</td> </tr> <tr> <td>2020-01-02</td> <td>Alice</td> <td>1992</td> <td>-1.34</td> <td>East</td> </tr> <tr> <td>2020-01-03</td> <td>Tomas</td> <td>1982</td> <td>1.00023</td> <td>South</td> </tr> </tbody></table>"""
要從字串中讀取表,請執行以下操作:
dfs = pd.read_html(html_string)
現在,我們得到的結果不是Pandas資料幀而是Python列表。如果使用type()函式,可以看到:
>>> type(dfs)list
如果要獲取表,可以使用索引訪問它:
dfs[0]
結果看起來很棒。讓我們看看dfs[0].info()的資料型別。預設情況下,數值列被轉換為數值型別,例如,year和cost列分別被轉換為int64和float64。
>>> df[0].info()RangeIndex: 3 entries, 0 to 2Data columns (total 5 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 date 3 non-null object 1 name 3 non-null object 2 year 3 non-null int64 3 cost 3 non-null float64 4 region 3 non-null object dtypes: float64(1), int64(1), object(3)memory usage: 248.0+ bytes
2.從URL讀取表Pandas read_html()接受URL。讓我們透過一個例子來看看這是如何工作的。
URL = 'https://en.wikipedia.org/wiki/London'dfs = pd.read_html(URL)
與從字串讀取相同,它返回一個數據幀列表。如果我們執行len(dfs),我們可以從給定的URL得到31個表。
>>> print(f'Total tables: {len(dfs)}')31
下面是dfs[6]的一個例子:
3.從檔案讀取表Pandas read_html()接受一個檔案。讓我們透過一個例子來看看這是如何工作的。
file_path = 'html_string.txt'with open(file_path, 'r') as f: dfs = pd.read_html(f.read())dfs[0]
注意:以下教程將從字串中讀取資料,因為隨著時間的推移,網頁內容可能變更。
4.使用parse_dates分析日期列日期列作為物件資料型別讀取。要正確讀取日期列,可以使用引數parse_dates指定日期列的列表。
>>> dfs = pd.read_html(html_string, parse_dates=['date'])>>> dfs[0].info()RangeIndex: 3 entries, 0 to 2Data columns (total 5 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 date 3 non-null datetime64[ns] 1 name 3 non-null object 2 year 3 non-null int64 3 cost 3 non-null float64 4 region 3 non-null object dtypes: datetime64[ns](1), float64(1), int64(1), object(2)memory usage: 248.0+ bytes
5.使用converters顯式轉換型別預設情況下,數值列被轉換為數值型別,例如,我們看到的year和cost列。但並非所有的數字文字資料都必須是數字型別,例如,所有值都以零開頭的ID列。
ID = 0001
此外,有時可能需要顯式地進行型別轉換以確保資料型別的完整性。對於這些要求,我們可以使用引數轉換器顯式地進行型別轉換:
dfs = pd.read_html(html_string, converters={ 'ID': str, 'year': int, 'cost': float,})
6.多索引、標題和索引列
預設情況下,位於<thead>中的<th>或<td>元素用於形成列索引,如果<thead>中包含多行,則建立一個多索引。
下面是一個在<thead>中包含多行的HTML表的示例。
html_string = """<table> <thead> <tr> <th colspan="5">Year 2020</th> </tr> <tr> <th>date</th> <th>name</th> <th>year</th> <th>cost</th> <th>region</th> </tr> </thead> <tbody> <tr> <td>2020-01-01</td> <td>Jenny</td> <td>1998</td> <td>1.2</td> <td>South</td> </tr> <tr> <td>2020-01-02</td> <td>Alice</td> <td>1992</td> <td>-1.34</td> <td>East</td> </tr> </tbody></table>"""
它建立多重索引,因為<thead>中有多行。
dfs = pd.read_html(html_string)dfs[0]
指定標題行:
dfs = pd.read_html(html_string, header=1)dfs[0]
指定索引列:
dfs = pd.read_html(html_string, header=1, index_col=0)dfs[0]
7.用match匹配表
引數匹配採用字串或正則表示式。該值預設為.+(匹配任何非空字串),並將返回所有表。
我們透過一個例子來看看這是如何工作的。
html_string = """<table id="report"> <caption>2020 report</caption> <thead> <tr> <th>date</th> <th>name</th> </tr> </thead> <tbody> <tr> <td>2020-01-01</td> <td>Jenny</td> </tr> <tr> <td>2020-01-02</td> <td>Alice</td> </tr> </tbody></table><table> <caption>Average income</caption> <thead> <tr> <th>name</th> <th>income</th> </tr> </thead> <tbody> <tr> <td>Tom</td> <td>200</td> </tr> <tr> <td>James</td> <td>300</td> </tr> </tbody></table>"""
要讀取包含特定文字的表:
# 標題中的文字dfs = pd.read_html(html_string, match='2020 report')# 表格單元格中的文字dfs = pd.read_html(html_string, match='James')
8.使用屬性篩選表
引數attrs接受任何有效的HTML標記屬性的字典來篩選表。例如:
dfs = pd.read_html(html_string, attrs={'id': 'report'})
id是有效的HTML標記屬性。
9.使用缺失值預設情況下,所有空字串都被視為缺失值,並作為NaN讀取。
下面是一個HTML表格的示例,其中的< td >單元格中有一些空字串。
html_string = """<table> <tr> <th>date</th> <th>name</th> <th>year</th> <th>cost</th> <th>region</th> </tr> <tr> <td>2020-01-01</td> <td>Jenny</td> <td>1998</td> <td>1.2</td> <td>South</td> </tr> <tr> <td>2020-01-02</td> <td>Alice</td> <td>1992</td> <td></td> <td>East</td> </tr> <tr> <td>2020-01-03</td> <td>Tomas</td> <td>1982</td> <td></td> <td>South</td> </tr></table>"""
以預設設定讀取。
dfs = pd.read_html(html_string)dfs[0]
為了保留這些空字串,我們可以將引數keep_default_na設定為False。
dfs = pd.read_html(html_string, keep_default_na=False)
有時,對於缺少的值,你可能有其他字元表示法。如果我們知道什麼型別的字元用作表中的缺失值,我們可以使用na_values引數處理它們:
dfs = pd.read_html(html_string, na_values=['?', '&'])
當資料幀已經建立好後,我們可以使用pandas replace()函式來處理這些值:
df_clean = dfs[0].replace({ "?": np.nan, "&": np.nan })
結論
Pandas read_html()函式是一種快速方便地從html表中獲取資料的方法。
謝謝你的閱讀。請檢視Notebook的原始碼,如果你對機器學習的實際方面感興趣,請繼續關注:https://github.com/BindiChen/machine-learning/blob/master/data-analysis/024-pandas-read_html/pandas-read_html.ipynb。