首页 > 解决方案 > 如何从表格中获取所有 tr 元素并单击链接?

问题描述

我试图弄清楚如何打印表格中的所有 tr 元素,但我不能让它正常工作。

这是我正在使用的链接。

https://en.wikipedia.org/wiki/List_of_current_members_of_the_United_States_Senate

这是我的代码。

import requests
from bs4 import BeautifulSoup

link = "https://en.wikipedia.org/wiki/List_of_current_members_of_the_United_States_Senate"

html = requests.get(link).text

# If you do not want to use requests then you can use the following code below
# with urllib (the snippet above). It should not cause any issue."""
soup = BeautifulSoup(html, "lxml")
res = soup.findAll("span", {"class": "fn"})
for r in res:
    print("Name: " + r.find('a').text)
    table_body=soup.find('senators')
    rows = table_body.find_all('tr')
    for row in rows:
        cols=row.find_all('td')
        cols=[x.text.strip() for x in cols]
        print(cols)

我正在尝试打印tr名为'senators'. 另外,我想知道是否有一种方法可以点击参议员的链接,就像'Richard Shelby'我这样:

https://en.wikipedia.org/wiki/Richard_Shelby

从每个链接中,我想获取'Assumed office'. 在这种情况下,值为:'January 3, 2018'。所以,最终,我想结束这个:

Richard Shelby  May 6, 1934 (age 84)    Lawyer  U.S. House
Alabama Senate  January 3, 1987     2022
Assumed office: January 3, 2018

我现在能得到的只是打印出来的每个参议员的名字。

标签: pythonpython-3.xbeautifulsoup

解决方案


为了定位“Senators”表,可以先找到对应的“Senators” label,然后得到以下第一个table元素

soup.find(id='Senators').find_next("table")

现在,为了逐行获取数据,您必须考虑具有跨越多行的“行跨度”的单元格。您可以按照我在 <tr> 有 rowspan 时应该做什么中建议的方法,或者我在下面提供的实现(不理想但适用于您的情况)。

import copy

import requests
from bs4 import BeautifulSoup


link = "https://en.wikipedia.org/wiki/List_of_current_members_of_the_United_States_Senate"


with requests.Session() as session:
    html = session.get(link).text

    soup = BeautifulSoup(html, "lxml")
    senators_table = soup.find(id='Senators').find_next("table")

    headers = [td.get_text(strip=True) for td in senators_table.tr('th')]

    rows = senators_table.find_all('tr')

    # pre-process table to account for rowspan, TODO: extract into a function
    for row_index, tr in enumerate(rows):
        for cell_index, td in enumerate(tr('td')):
            if 'rowspan' in td.attrs:
                rowspan = int(td['rowspan'])

                del td.attrs['rowspan']

                # insert same td into subsequent rows
                for index in range(row_index + 1, row_index + rowspan):
                    try:
                        rows[index]('td')[cell_index].insert_after(copy.copy(td))
                    except IndexError:
                        continue

    # extracting the desired data
    rows = senators_table.find_all('tr')[1:]
    for row in rows:
        cells = [td.get_text(strip=True) for td in row('td')]
        print(dict(zip(headers, cells)))

如果你想,那么,按照参议员“个人资料”页面的链接,你首先需要连续从适当的单元格中提取链接,然后使用session.get()“导航”到它,如下所示:

senator_link = row.find_all('td')[3].a['href']
senator_link = urljoin(link, senator_link)
response = session.get(senator_link)

soup = BeautifulSoup(response.content, "lxml")

# TODO: parse

在哪里urljoin导入为:

from urllib.parse import urljoin

另外,仅供参考,requests.Session()这里使用的原因之一是优化向同一主机发出请求:

Session 对象允许您跨请求保留某些参数。它还在从 Session 实例发出的所有请求中保留 cookie,并将使用 urllib3 的连接池。因此,如果您向同一主机发出多个请求,则会重用底层 TCP 连接,从而显着提高性能


还有另一种方法可以解析表格数据 -.read_html()pandas. 你可以这样做:

import pandas as pd

df = pd.read_html(str(senators_table))[0]
print(df.head())

将所需的表作为数据框。


推荐阅读