在 Python 中使用 BS4 抓取数据,嵌套表

Posted

技术标签:

【中文标题】在 Python 中使用 BS4 抓取数据,嵌套表【英文标题】:Scraping data with BS4 in Python, nested table 【发布时间】:2018-06-30 02:15:59 【问题描述】:

我正在尝试从balloon-reference.com 上抓取一些数据。我编写了一些代码来从站点的其他部分获取数据,其中表格的编码更简单一些,但特定的页面集显然更复杂。这是我到目前为止的代码。

从 urllib.request 导入 urlopen 从 bs4 导入 BeautifulSoup

# Declare URL
test_url = 'https://www.baseball-reference.com/boxes/SLN/SLN201704020.shtml'

# Query the website and return the HTML
page = urlopen(test_url)

# Parse the HTML and store
soup = BeautifulSoup(page, 'lxml')

table = soup.find("div", "class": "table_outer_container")

这并没有找到我想要的表格(在这个特定的页面上,两个表格包含 At-Bats、RBI、HRs、runs 等)。我尝试了其他一些方法,例如

table = soup.find_all("table" , "class": "sortable stats_table")

但它也不起作用。我也尝试使用 pandas 阅读该网站,但没有成功,所以如果有更简单的 pandas 方法,我也愿意。

【问题讨论】:

看起来页面的整个部分都以 HTML 编码作为注释。我以前见过这种情况(大概是为了绕过擦洗?)但不确定解决方法。 相关 - ***.com/q/33138937/7954504 【参考方案1】:

我知道这段代码很复杂或很糟糕。但它可以完成工作。您可以随着时间的推移对其进行优化。

from bs4 import BeautifulSoup,Comment
import requests

r = requests.get('https://www.baseball-reference.com/boxes/SLN/SLN201704020.shtml')
soup = BeautifulSoup(r.text, 'lxml')

comments = soup.find_all(string=lambda text:isinstance(text, Comment))
for comment in comments:
    comment.extract()

    #After getting rid of comments we need Soup again
    another_soup = BeautifulSoup(str(comment),'lxml')

    tables = another_soup.find_all('table' ,"class": "sortable stats_table")

    for table in tables:
        #Since we can't get id from table we are going to use table header as stat type.
        stat_type = ''
        for data in table.find('thead').find_all('tr'):
            stat_type = data.th.text.strip()

        #You only need batting.
        if stat_type != 'Batting': break

        for data in table.find('tbody').find_all('tr'):
            player = data.th.text.strip()
            stats = data.find_all('td')

            stat_ab = stats[0].text
            stat_r = stats[1].text
            stat_h = stats[2].text
            stat_rbi = stats[3].text
            # Table goes on
            print(player,stat_ab,stat_r,stat_h,stat_rbi)

        print('-------------------------------------')

输出是:

Kyle Schwarber LF 3 0 2 0
Kris Bryant 3B 4 0 0 0
Anthony Rizzo 1B 4 0 1 0
Ben Zobrist RF 3 1 0 0
Addison Russell SS 4 0 1 0
Jason Heyward CF 4 1 1 0
Willson Contreras C 4 1 2 3
Jon Lester P 2 0 0 0
Carl Edwards P 0 0 0 0
Koji Uehara P 0 0 0 0
Tommy La Stella PH 1 0 0 0
Pedro Strop P 0 0 0 0
Jon Jay PH 1 0 0 0
Mike Montgomery P 0 0 0 0
Javier Baez 2B 4 0 1 0
-------------------------------------
Dexter Fowler CF 4 1 1 0
Aledmys Diaz SS 5 0 2 0
Matt Carpenter 1B 4 0 1 1
Jhonny Peralta 3B 4 0 1 0
Seung-hwan Oh P 0 0 0 0
Jose Martinez PH 1 1 1 0
Yadier Molina C 3 0 2 0
Stephen Piscotty RF 3 1 1 0
Jedd Gyorko 2B 2 0 0 0
Kolten Wong PH-2B 2 0 0 0
Randal Grichuk LF 4 1 2 3
Carlos Martinez P 3 0 0 0
Greg Garcia 3B 0 0 0 0
-------------------------------------

【讨论】:

谢谢,只要我能在我的电脑上得到这个输出,这应该可以工作。我尝试运行它,但没有安装 Comment,当我尝试 pip install comment 时出现错误。我试图到处搜索以修复它,但没有运气。提出一个新问题。 编辑:没关系,我没有意识到 Comment 是 BS4 本身的一个包。那是浪费了几个小时。这行得通,谢谢。【参考方案2】:

这是从两个表中获取数据的另一种方式:

import requests
from bs4 import BeautifulSoup, Comment

res = requests.get("https://www.baseball-reference.com/boxes/SLN/SLN201704020.shtml",headers="User-Agent":"Mozilla/5.0")
soup = BeautifulSoup(res.text, 'lxml')
for comment in soup.find_all(string=lambda text:isinstance(text,Comment)):
    data = BeautifulSoup(comment,"lxml")
    for items in data.select("#ChicagoCubsbatting tr,#StLouisCardinalsbatting tr"):
        tds = ' '.join([' '.join(item.text.split()) for item in items.select("th,td")])
        print(tds)

部分输出:

Batting AB R H RBI BB SO PA BA OBP SLG OPS Pit Str WPA aLI WPA+ WPA- RE24 PO A Details
Kyle Schwarber LF 3 0 2 0 0 1 4 .667 .750 1.000 1.750 20 10 0.170 1.75 0.196 -0.026 1.1 2 0 2B,HBP
Kris Bryant 3B 4 0 0 0 0 3 4 .000 .000 .000 .000 19 13 -0.260 2.31 0.000 -0.260 -1.6 0 0 
Anthony Rizzo 1B 4 0 1 0 0 1 4 .250 .250 .250 .500 14 8 -0.214 2.74 0.035 -0.249 -0.9 5 0

【讨论】:

以上是关于在 Python 中使用 BS4 抓取数据,嵌套表的主要内容,如果未能解决你的问题,请参考以下文章

从抓取bs4中过滤python中的数据

需要帮助使用 bs4 和 python 从幻灯片中抓取图像

Python:有条件地在抓取过程中跳过url

python怎么自动抓取网页上每日天气预报

bs4

Bs4