Python从网页上提取表格

本文的主要目的是演示如何使用Pandas和Python的lxml ,从网页中提取表格。

Python从网页中提取表

在这个现代社会中,数据具有重要的意义,每天都有大量的信息被处理、存储和提取,而且频率很高。关于这一点,我们的项目可能要求我们从某个在线位置、存储库或网页中提取数据。

这在许多用例中都有可能发生。也许因为众多原因需要访问一个公共记录网站来提取、处理和存储数据,或者从我们的存储库中提取数据。

有更好的方法可以做到这一点,但为了简单起见,让我们假设这是需要的方式。

为了解决这种情况,我们必须设计一个解决方案,建立与网页的连接,通读页面,找到任何表格(如果有的话),正确地提取它们,并以合适的格式存储它们。这样就可以在我们的程序中进行处理。

解决这个问题的方法有多种,下面提到其中的两种:

使用Pandas从网页上提取表

在进一步进行之前,请确保你已经安装了以下模块/包:

  1. lxml
  2. html5lib
  3. BeautifulSoup4

你可以使用下面的命令用pip 来安装上述软件包:

pip install lxml html5lib BeautifulSoup4

这将得到以下输出:

Collecting lxml
  Downloading lxml-4.9.1-cp310-cp310-win_amd64.whl (3.6 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.6/3.6 MB 37.9 kB/s eta 0:00:00
Requirement already satisfied: html5lib in c:program filespython310libsite-packages (1.1)
Collecting BeautifulSoup4
  Downloading beautifulsoup4-4.11.1-py3-none-any.whl (128 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 128.2/128.2 kB 29.0 kB/s eta 0:00:00
Requirement already satisfied: webencodings in c:program filespython310libsite-packages (from html5lib) (0.5.1)
Requirement already satisfied: six>=1.9 in c:program filespython310libsite-packages (from html5lib) (1.16.0)
Collecting soupsieve>1.2
  Downloading soupsieve-2.3.2.post1-py3-none-any.whl (37 kB)
Collecting requests
  Downloading requests-2.28.1-py3-none-any.whl (62 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 62.8/62.8 kB 420.8 kB/s eta 0:00:00
Collecting urllib3<1.27,>=1.21.1
  Downloading urllib3-1.26.12-py2.py3-none-any.whl (140 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 140.4/140.4 kB 1.0 MB/s eta 0:00:00
Collecting idna<4,>=2.5
  Downloading idna-3.4-py3-none-any.whl (61 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.5/61.5 kB 121.6 kB/s eta 0:00:00
Collecting charset-normalizer<3,>=2
  Downloading charset_normalizer-2.1.1-py3-none-any.whl (39 kB)
Collecting certifi>=2017.4.17
  Downloading certifi-2022.9.24-py3-none-any.whl (161 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 161.1/161.1 kB 1.4 MB/s eta 0:00:00
Installing collected packages: urllib3, idna, charset-normalizer, certifi, requests, soupsieve, lxml, BeautifulSoup4
Successfully installed BeautifulSoup4-4.11.1 lxml-4.9.1 soupsieve-2.3.2.post1 certifi-2022.9.24 charset-normalizer-2.1.1 idna-3.4 requests-2.28.1 urllib3-1.26.12

在安装了必要的模块后,是时候进入执行部分了。

考虑一下下面的代码:

import requests
import pandas as pd
url = 'https://www.ffiec.gov/census/report.aspx?year=2020&county=009&state=09&report=demographic'
html = requests.get(url).content
df_list = pd.read_html(html)
df = df_list[-1]
print(df)

这给出了以下的输出:

    Tract Code Tract Income Level Distressed or Under-served Tract  ...  Minority Population Owner Occupied Units 1- to 4- Family Units
1       1202.0           Moderate                                No  ...                 3040                  918                  2010
2       1251.0             Middle                                No  ...                  551                 1400                  1555
3       1252.0           Moderate                                No  ...                 2088                 1139                  1992
4       1253.0           Moderate                                No  ...                 2443                  728                  1814
..         ...                ...                               ...  ...                  ...                  ...                   ...
95      1714.0           Moderate                                No  ...                 1278                  141                   638
96      1715.0           Moderate                                No  ...                 2241                  396                  1274
97      1716.0             Middle                                No  ...                 1466                 1378                  1803
98      1717.0             Middle                                No  ...                  820                 1456                  1647
99      1751.0             Middle                                No  ...                  851                  669                  1240
[100 rows x 12 columns]

使用Pandas库很容易从任何网页上提取表格。潘达斯库的read_html 方法可用于从网页中读取和提取数据,然后将其转换为数据帧,以协助顺利处理数据,因为它们成为Dataframe 对象。

还可以使用to_csv 方法将提取的表格保存到CSV文件中,该方法将Dataframe 对象保存到CSV文件中。

使用Python从网页中提取表lxml

考虑一下下面的代码:

from lxml import etree
import urllib.request
site = "https://www.ffiec.gov/census/report.aspx?year=2020&county=009&state=09&report=demographic"
hdr = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
       'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
       'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
       'Accept-Encoding': 'none',
       'Accept-Language': 'en-US,en;q=0.8',
       'Connection': 'keep-alive'}
request = urllib.request.Request(site, headers=hdr)
web = urllib.request.urlopen(request)
s = web.read()
html = etree.HTML(s)
## Get all 'tr'
tr_nodes = html.xpath('//table[@id="Report1_dgReportDemographic"]/tr')
## 'th' is inside first 'tr'
headers = [i.text for i in tr_nodes[0].xpath("th")]
## Get text from rest all 'tr'
td_content = [[td.text for td in tr.xpath('td')] for tr in tr_nodes[1:]]
for head in headers:
    print(head, end=" ")
print("")
for content in td_content:
    print(content)

这就得到了下面的输出:

Tract Code Tract Income Level  Distressed or Under   Tract Median Family Income % 2020 FFIEC Est. MSA/MD non-MSA/MD Median Family Income 2020 Est. Tract Median Family Income 2015 Tract Median Family Income Tract Population Tract Minority % Minority Population Owner Occupied Units 1- to 4- Family Units
['1201.00', 'Middle', 'No', '93.64', '$91,800', '$85,962', '$75,611', '6013', '26.44', '1590', '1862', '2248']
['1202.00', 'Moderate', 'No', '68.12', '$91,800', '$62,534', '$55,000', '6783', '44.82', '3040', '918', '2010']
['1251.00', 'Middle', 'No', '109.80', '$91,800', '$100,796', '$88,654', '4477', '12.31', '551', '1400', '1555']
['1252.00', 'Moderate', 'No', '62.55', '$91,800', '$57,421', '$50,506', '5912', '35.32', '2088', '1139', '1992']
['1253.00', 'Moderate', 'No', '57.28', '$91,800', '$52,583', '$46,250', '5164', '47.31', '2443', '728', '1814']
.
.
.
.
.

也可以使用lxmlurllib ,从网页中提取表格并进行处理。从代码中可以看出,我们需要为请求提供一个自定义的头,否则会收到一个403: Forbidden 的错误。

请求成功后,会对表格进行搜索(专门针对这个网站),之后我们手动从表格中提取标题和内容(行)。

虽然这个选项比Pandas模块更冗长、更复杂,但当需要对提取什么和不提取什么有更多的控制和自由时,它是非常有用的。