【问题标题】:Scrape multiple individual tables on one web page在一个网页上抓取多个单独的表格
【发布时间】:2020-04-27 13:53:16
【问题描述】:

我正在尝试从一个网页上抓取一堆表格,使用下面的代码,我可以获得一个表格,并且输出可以用 pandas 正确显示,但我一次不能获得多个表格。

import bs4 as bs
import urllib.request
import pandas as pd

source = urllib.request.urlopen('https://www.URLHERE.com').read()
soup = bs.BeautifulSoup(source, 'lxml')
tables = soup.select('table')[-1]
rows = tables.find_all('tr')
output = []

for rows in rows:
    cols = rows.find_all('td') 
    cols = [item.text.strip() for item in cols] 
    output.append([item for item in cols if item])
df = pd.DataFrame(output, columns = ['1','2', '3', '4', '5', '6'])
df = df.iloc[1:]

print(df) 

如果我从表变量中删除 [-1],则会收到以下错误。

AttributeError: 'list' object has no attribute 'find_all'

我需要进行哪些更改才能将所有表格从页面中移除?

【问题讨论】:

  • 也许是这样来获取所有表格:tables = soup.find_all('table')?
  • 我已经尝试过了,然后我得到一个不同的错误,AttributeError: ResultSet object has no attribute 'find_all'。您可能将项目列表视为单个项目。当您打算调用 find() 时,您是否调用了 find_all()?我是网络抓取的新手,并且对 python 也很熟悉,所以这也有助于我的挣扎

标签: python html pandas web-scraping beautifulsoup


【解决方案1】:

您已经走在正确的轨道上,就像评论者已经说过的那样,您需要 find_all 表,然后您可以将已经使用的行逻辑应用于循环中的每个表,而不仅仅是第一张桌子。您的代码将如下所示:

tables = soup.find_all('table')
for table in tables:
    # individual table logic here

    rows = table.find_all('tr')
    for row in rows:
        # individual row logic here

【讨论】:

  • 我尝试将它包含到我的代码中,但我不确定如何正确执行,所以我想要做的是扫描页面上的每个表并找到所有行,然后全部取走来自这些行的表数据并将它们组合到我的输出的大表中。
【解决方案2】:

我仔细看了一下,下面是我测试的示例代码:

source = urllib.request.urlopen('URL').read()
soup = bs.BeautifulSoup(source, 'lxml')
tables = soup.select('table')
print("I found " + str(len(tables)) + " tables.")

all_rows = []
for table in tables:
    print("Searching for <tr> items...")
    rows = table.find_all('tr')
    print("Found " + str(len(rows)) + "rows.")
    for row in rows:
        all_rows.append(row)


print("In total i have got " + str(len(all_rows)) + " rows.")

# example of first row
print(all_rows[0])

小解释:删除 [-1] 时出现属性错误的问题是,tables 变量是 List 对象 - 它没有 find_all 方法。

您使用 [-1] 进行的跟踪没问题 - 我假设您知道,[-1] 会抓取列表中的最后一项。所以你必须对所有元素做同样的事情——如上面的代码所示。

您可能会感兴趣阅读有关 Python 和可迭代对象的 for 构造:https://pythonfordatascience.org/for-loops-and-iterations-python/

【讨论】:

  • 通过您的示例,我可以知道我有多少行,但我想要做的是从这些行中的每个单元格中提取数据并将它们放在我的组合中到我自己的表中。当我将更改与现有代码结合起来时,我得到另一个“find_all”错误。 AttributeError: 'list' 对象没有属性 'find_all'
  • tables = soup.select('table') all_rows = [] 用于表中的表:rows = tables.find_all('tr') 用于行中的行:all_rows.append(row) 用于数据在 all_rows 中: cols = all_rows.find_all('td') cols = [item.text.strip() for item in cols] output = cols output([item for item in cols if item]) df = pd.DataFrame(output , columns = ['Teams','Odds', '1', '2', 'T', 'ATS']) df = df.iloc[1:] print(df) 运行这个会产生 cols = all_rows。 find_all('td') AttributeError: 'list' 对象没有属性 'find_all'
  • 嗯,通过这些更改,您几乎可以实现您所要求的一切。变量all_rows 是报废页表中所有行的列表;变量tables 是此页面上所有表格的列表 - 您接下来如何处理取决于您。
【解决方案3】:

如果您想一次性提取网页上的所有不同表格,您应该尝试:

tables = pd.read_html("<URL_HERE>")

tables 将是该页面上每个表格的数据框列表。

有关更具体的文档,请参阅Pandas-Documentation

【讨论】:

    猜你喜欢
    • 2020-07-31
    • 1970-01-01
    • 2017-03-01
    • 2019-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多