【问题标题】:Parse tables under h1 tag with BeautifulSoup and store in df使用 BeautifulSoup 解析 h1 标签下的表并存储在 df
【发布时间】:2021-09-25 15:59:47
【问题描述】:

我想在 h1“表格”标题下从多个网站中提取表格。每个网站都有多个 h1 标题,但“表格”在所有网站上都是一致的。尽管我已经设法将它们提取到一个列表中,但每个表还带有一个不同站点的 h2 标题。

我当前的代码解析所有表格,甚至是那些在 h1 'Tables' 标题之前的表格。如何排除这些表? html与下面的类似:

<h2>I don't care about this table</h2>
<table class="foo">
  <tr>
    <td>Key A</td>
  </tr>
  <tr>
    <td>A value I don't want</td>
  </tr>
</table>

<h1>Tables</h1>
<p> A description I don't care about </p>
<h2>First good table</h2>
<table class="foo">
  <tr>
    <td>Key B</td>
  </tr>
  <tr>
    <td>A value I want</td>
  </tr>
</table>


<h2>Second good table</h2>
<table class="foo">
  <tr>
    <td>Key C</td>
  </tr>
  <tr>
    <td>A value I want</td>
  </tr>
</table>

我目前的做法:

soup = BeautifulSoup(self.body, features="lxml")
headers = [tags.text for tags in soup.find_all(["h1", "h2"])]

try:
    # Find h2 table headers under h1 'Tables' header
    target_index = headers.index("Tables")
    table_headers = headers[target_index + 1 :]

except ValueError:
    print("Page doesn't contain tables")

# This includes all tables. How do we make sure we only include those under the 'Tables' header?
tables_raw = [[[cell.text for cell in row("th") + row("td")] for row in table("tr")]for table in soup("table")]

# Create dfs and assign a name
tables_df = [pd.DataFrame(table) for table in tables_raw]
tables_and_names = list(zip(table_headers, tables_df))

我确实看过 this solution,但不知道如何获得我目前拥有的 df 输出。任何帮助将不胜感激。

【问题讨论】:

    标签: python html beautifulsoup


    【解决方案1】:

    您可以将 CSS 选择器与 ~ 一起使用:

    for table in soup.select("h1:-soup-contains(Tables) ~ table"):
        for row in table.select("tr"):
            print(*[td.get_text(strip=True) for td in row.select("td")])
    

    打印:

    Key B
    A value I want
    Key C
    A value I want
    

    或者没有 CSS 选择器:

    h1 = soup.find("h1", text="Tables")
    for table in h1.find_next_siblings("table"):
        for row in table.select("tr"):
            print(*[td.get_text(strip=True) for td in row.select("td")])
    

    【讨论】:

    • 嗨@Andrej Kesely find(..., text="tables")find(..., string="tables") 有区别吗?两者都有效。 text 更贪心吗?
    • @cards 它们是相等的(根据文档crummy.com/software/BeautifulSoup/bs4/doc/#the-string-argument - 最后一句)。从现在开始我可能应该使用string=...
    • 好的。但是如果你尝试访问一个标签字符串会有不同的效果,对吧?
    • 抱歉打扰了...文档中还有.string标签属性的引用。我也尝试了以下方法:soup = bs4.BeautifulSoup('&lt;div&gt;Hi&lt;/div&gt;', 'lxml')print(hasattr(soup.div, 'string'))print('string' in dir(soup.find('div'))),它们返回 True。为什么说.string 不存在?
    • 啊哈哈是的,现在没有了!这就是为什么在我提到.text 是否“贪婪”之前!再次感谢您的建议和对文档的参考! [.get_text() 也是“贪婪”]
    【解决方案2】:

    应该这样做

    header = soup.find('h1')
    for sibling in header.next_siblings:
        if sibling.name == 'table':
            do_stuff()
    

    【讨论】:

    • 我可以隔离标题,但它仍然会拉出 if 语句之后的所有内容。
    • 使用您提供的 html 示例,它只会抓取标题下的两个表格。这就是你要求的
    • 我的意思是 sibling 在 if 语句中看起来与预期的一样,并且不会将表拉到 h1 上方。但不知何故,它仍然被tables_raw 拉动。不知道为什么。
    猜你喜欢
    • 2013-03-20
    • 2017-09-24
    • 1970-01-01
    • 2013-09-19
    • 1970-01-01
    • 1970-01-01
    • 2012-05-22
    • 1970-01-01
    • 2020-11-29
    相关资源
    最近更新 更多