使用名称从网站上抓取数据表

Posted

技术标签:

【中文标题】使用名称从网站上抓取数据表【英文标题】:Scrape data tables from website using names 【发布时间】:2020-05-11 05:03:10 【问题描述】:

我在尝试抓取网站时遇到了一种特殊情况。我正在通过搜索栏搜索数百个名称,然后抓取表格。但是,与网站相比,我的列表中的某些名称是唯一的并且拼写不同。在这种情况下,我在网站上手动查找了几个名字,它仍然直接将我带到各个页面。其他时候,如果有多个名字相同或相似的人,它会进入名字列表(在这种情况下,我想要在 nba 打球的人。我已经考虑过这一点,但我认为有必要提及)。我该如何继续进入这些玩家的个人页面,而不必每次都运行脚本并点击错误以查看哪个玩家的拼写略有不同?同样,即使拼写略有不同或名称列表(需要 NBA 中的名称),数组中的名称也会直接将您带到单个页面。一些例子是 Georgios Papagiannis(在网站上列为 George Papagiannis)、Ognjen Kuzmic(列为 Ognen Kuzmic)、Nene(列为 Maybyner Nene,但会带你到一个名字列表 -- https://basketball.realgm.com/search?q=nene)。这似乎很难,但我觉得这可能是可能的。此外,似乎不是将所有抓取的数据写入 csv,而是每次都被下一个玩家覆盖。非常感谢。

我得到的错误: AttributeError: 'NoneType' object has no attribute 'text'

import requests
from bs4 import BeautifulSoup
import pandas as pd


playernames=['Carlos Delfino', 'Nene', 'Yao Ming', 'Marcus Vinicius', 'Raul Neto', 'Timothe Luwawu-Cabarrot']

result = pd.DataFrame()
for name in playernames:

    fname=name.split(" ")[0]
    lname=name.split(" ")[1]
    url="https://basketball.realgm.com/search?q=+".format(fname,lname)
    response = requests.get(url)
    soup = BeautifulSoup(response.content, 'html.parser')

    if soup.find('a',text=name).text==name:
        url="https://basketball.realgm.com"+soup.find('a',text=name)['href']
        print(url)
        response = requests.get(url)
        soup = BeautifulSoup(response.text, 'lxml')

    try:
        table1 = soup.find('h2',text='International Regular Season Stats - Per Game').findNext('table')
        table2 = soup.find('h2',text='International Regular Season Stats - Advanced Stats').findNext('table')

        df1 = pd.read_html(str(table1))[0]
        df2 = pd.read_html(str(table2))[0]

        commonCols = list(set(df1.columns) & set(df2.columns))
        df = df1.merge(df2, how='left', on=commonCols)
        df['Player'] = name
        print(df)
    except:
        print ('No international table for %s.' %name)
        df = pd.DataFrame([name], columns=['Player'])

result = result.append(df, sort=False).reset_index(drop=True)

cols = list(result.columns)
cols = [cols[-1]] + cols[:-1]
result = result[cols]
result.to_csv('international players.csv', index=False)

【问题讨论】:

搜索结果的 url 提供了一个线索:如果 url 包含“player”,那么您可以继续抓取所需的表格。如果没有 - 如果搜索结果表列出了不止一名 NBA 球员(Nene 示例没有),这也不是万无一失的 - 在表格中搜索 NBA 列中的值。如果那里有值,则从该行的播放器结果中获取 href。 不清楚你有什么问题 因此,如果您继续 basketball.realgm.com 并在搜索栏中输入 Raul Neto,它将转到他的页面,这很棒。但是,我的代码会抛出错误AttributeError: 'NoneType' object has no attribute 'text',因为他个人页面上的名字是 Raulzinho Neto。我希望能够仍然从他的页面上抓取表格,而不必将我列表中的名称更改为 Raulzinho Neto。 foszter 建议使用 url 中的“播放器”来处理这个问题,但我不确定如何。是不是更清楚了? 其他时候,我的名单将包含 Nene 的名字,没有姓氏,我计算在内,它会进入一个名字相似的球员名单 (basketball.realgm.com/search?q=nene)。从那里,我想去找那个在NBA打球的人,我也占了。在这种情况下,我想进入 Maybyner Nene 的页面,正如你所看到的,他是唯一一个在 NBA 打球的人。但是,我面临与 Raul Neto 示例相同的错误 【参考方案1】:

我对名字相似的 NBA 球员使用了循环。您可以在下面的 CSS 选择器中找到从搜索表中获取 NBA 球员的信息:

.tablesaw tr:has(a[href*="/nba/teams/"]) a[href*="/player/"]

CSS选择器含义:通过tablesaw类查找表,查找表的子tr和子a,其href包含/nba/teams/文本,然后找到a其@ 987654328@ 包含/player/

我添加了 Search Player NameReal Player Name 列,您可以查看如何找到玩家。此列使用insert 放置为第一列和第二列(参见代码中的注释)。

import requests
from bs4 import BeautifulSoup
import pandas as pd
from pandas import DataFrame

base_url = 'https://basketball.realgm.com'
player_names = ['Carlos Delfino', 'Nene', 'Yao Ming', 'Marcus Vinicius', 'Raul Neto', 'Timothe Luwawu-Cabarrot']

result = pd.DataFrame()


def def get_player_stats(search_name = None, real_name = None, player_soup = None):
    table_per_game = player_soup.find('h2', text='International Regular Season Stats - Per Game')
    table_advanced_stats = player_soup.find('h2', text='International Regular Season Stats - Advanced Stats')

    if table_per_game and table_advanced_stats:
        print('International table for %s.' % search_name)

        df1 = pd.read_html(str(table_per_game.findNext('table')))[0]
        df2 = pd.read_html(str(table_advanced_stats.findNext('table')))[0]

        common_cols = list(set(df1.columns) & set(df2.columns))
        df = df1.merge(df2, how='left', on=common_cols)

        # insert name columns for the first positions
        df.insert(0, 'Search Player Name', search_name)
        df.insert(1, 'Real Player Name', real_name)
    else:
        print('No international table for %s.' % search_name)
        df = pd.DataFrame([[search_name, real_name]], columns=['Search Player Name', 'Real Player Name'])

    return df


for name in player_names:
    url = f'base_url/search?q=name.replace(" ", "+")'
    response = requests.get(url)
    soup = BeautifulSoup(response.content, 'html.parser')

    if url == response.url:
        # Get all NBA players
        for player in soup.select('.tablesaw tr:has(a[href*="/nba/teams/"]) a[href*="/player/"]'):
            response = requests.get(base_url + player['href'])
            player_soup = BeautifulSoup(response.content, 'lxml')
            player_data = get_player_stats(search_name=player.text, real_name=name, player_soup=player_soup)
            result = result.append(player_data, sort=False).reset_index(drop=True)
    else:
        player_data = get_player_stats(search_name=name, real_name=name, player_soup=soup)
        result = result.append(player_data, sort=False).reset_index(drop=True)

result.to_csv('international players.csv', index=False)
# Append to existing file
# result.to_csv('international players.csv', index=False, mode='a')

【讨论】:

嘿,对不起,我离开了一段时间。我收到 get_player_stats 的语法错误 SyntaxError: invalid syntax。对我来说看起来不错,但您编写论点的方式似乎有问题。它为你运行了吗? 替换为 - def get_player_stats(search_name = None, real_name = None, player_soup = None): 我很好奇。如果我想使用 excel 中存在的名称列表并抓住它们来执行此脚本正在执行的操作,这可能吗?我真的找不到任何可以让我不断为每一行添加相同名称的东西。因此,如果“Carlos Delfino”、“Nene”、“Yao Ming”、“Marcus Vinicius”、“Raul Neto”、“Timothe Luwawu-Cabarrot”在第一列,是否可以为每个名称添加更多行他们拥有的每个季节?几乎是脚本已经在做的事情,但是从现有文件中获取名称并将抓取的信息添加到文件中 可以从excel中读取数据,但没那么简单。您也可以按赛季获取所有球员的姓名和数据,而无需手动输入 是的,这太棒了。谢谢你。我想看看我是否可以让任务变得更容易。我的另一个问题是关于熊猫的,我不太熟悉。 list()、set() 和 merge() 在这种情况下究竟是如何工作的?我有一些想法,但不完全清楚

以上是关于使用名称从网站上抓取数据表的主要内容,如果未能解决你的问题,请参考以下文章

从使用 Power BI 的网站抓取数据 - 从网站上的 Power BI 检索数据

使用python和beautifulsoup4抓取网页后重复数据

使用 Python 从网站上抓取数据 [关闭]

如何使用python和beautifulsoup4循环抓取网站中多个页面的数据

使用 python 和 Beautifulsoup4 从抓取数据中写入和保存 CSV 文件

从网站抓取数据的3种最佳方法