【问题标题】:How to scrape content from a complex div class using Beautiful Soup如何使用 Beautiful Soup 从复杂的 div 类中抓取内容
【发布时间】:2022-09-30 23:14:09
【问题描述】:

我正在做一些练习来练习使用 Python 进行网络抓取,我想获取此 yahoo 页面表的第一行(“总收入”)的值:

https://finance.yahoo.com/quote/BAC/financials?p=BAC

查看页面源代码,我的想法是找到第一次出现的 <div class=\"\" data-test=\"fin-row\"> 并获取值,但我不确定如何在第一个 div 中导航。

下面我展示第一行的 HTML 代码:

<div class=\"\" data-test=\"fin-row\">
    <div class=\"D(tbr) fi-row Bgc($hoverBgColor):h\">
        <div class=\"D(tbc) Ta(start) Pend(15px)--mv2 Pend(10px) Bxz(bb) Py(8px) Bdends(s) Bdbs(s) Bdstarts(s) Bdstartw(1px) Bdbw(1px) Bdendw(1px) Bdc($seperatorColor) Pos(st) Start(0) Bgc($lv2BgColor) fi-row:h_Bgc($hoverBgColor) Pstart(15px)--mv2 Pstart(10px)\">
            <div class=\"D(ib) Va(m) Ell Mt(-3px) W(215px)--mv2 W(200px) undefined\" title=\"Total Revenue\">
                <button aria-label=\"Total Revenue\" class=\"P(0) M(0) Va(m) Bd(0) Fz(s) Mend(2px) tgglBtn\">
                    <svg class=\"H(16px) Fill($primaryColor) Stk($primaryColor) tgglBtn:h_Fill($linkColor) tgglBtn:h_Stk($linkColor) Cur(p)\" width=\"16\" style=\"stroke-width:0;vertical-align:bottom\" height=\"16\" viewBox=\"0 0 48 48\" data-icon=\"caret-right\">
                        <path d=\"M33.447 24.102L20.72 11.375c-.78-.78-2.048-.78-2.828 0-.78.78-.78 2.047 0 2.828l9.9 9.9-9.9 9.9c-.78.78-.78 2.047 0 2.827.78.78 2.047.78 2.828 0l12.727-12.728z\"></path>
                    </svg>
                </button>
                <span class=\"Va(m)\">Total Revenue</span>
            </div>
            <div class=\"W(3px) Pos(a) Start(100%) T(0) H(100%) Bg($pfColumnFakeShadowGradient) Pe(n) Pend(5px)\"></div>
        </div>
        <div class=\"Ta(c) Py(6px) Bxz(bb) BdB Bdc($seperatorColor) Miw(120px) Miw(100px)--pnclg Bgc($lv1BgColor) fi-row:h_Bgc($hoverBgColor) D(tbc)\" data-test=\"fin-col\"><span>90,742,000</span></div>
        <div class=\"Ta(c) Py(6px) Bxz(bb) BdB Bdc($seperatorColor) Miw(120px) Miw(100px)--pnclg D(tbc)\" data-test=\"fin-col\"><span>89,113,000</span></div>
        <div class=\"Ta(c) Py(6px) Bxz(bb) BdB Bdc($seperatorColor) Miw(120px) Miw(100px)--pnclg Bgc($lv1BgColor) fi-row:h_Bgc($hoverBgColor) D(tbc)\" data-test=\"fin-col\"><span>85,528,000</span></div>
        <div class=\"Ta(c) Py(6px) Bxz(bb) BdB Bdc($seperatorColor) Miw(120px) Miw(100px)--pnclg D(tbc)\" data-test=\"fin-col\"><span>91,244,000</span></div>
        <div class=\"Ta(c) Py(6px) Bxz(bb) BdB Bdc($seperatorColor) Miw(120px) Miw(100px)--pnclg Bgc($lv1BgColor) fi-row:h_Bgc($hoverBgColor) D(tbc)\" data-test=\"fin-col\"><span>91,247,000</span></div>
    </div>

    <div></div>

在我的代码中,我使用 Selenium 来处理页面。不确定这是否是最好的方法,但使用 urlopen 等其他库时,我无法看到 HTML 内容。我可以打开页面,单击接受按钮,但之后我不确定如何在第一个 div 中导航。我实际上得到了一个错误,如:\"AttributeError: \'NoneType\' object has no attribute \'get_text\"

import requests
from urllib.request import urlopen, Request
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Firefox()
url = \"https://finance.yahoo.com/quote/BAC/financials?p=BAC\"
driver.get(url)
html = driver.page_source
soup = BeautifulSoup(html, \"html.parser\")

# Click accept button
aceitar = driver.find_element(By.NAME, \"agree\")
aceitar.click()

# Find the div of the Revenue row <div class=\"\" data-test=\"fin-row\">
primeiraLinha = soup.find(\"div\", {\"class\":\"\"})
print(primeiraLinha.get_text())

顺便说一句,我认为 Selenium 使这个过程非常缓慢。

    标签: python web web-scraping


    【解决方案1】:

    这是一个 Selenium 解决方案,用于在 pandas 数据框中获取整个表。

    需要进口

    from selenium import webdriver
    from selenium.webdriver.chrome.service import Service
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    import pandas as pd
    

    启动网络驱动程序

    # Replace your CHROME DRIVER path here
    chrome_path = r"C:\Users\hpoddar\Desktop\Tools\chromedriver_win32\chromedriver.exe"
    s = Service(chrome_path)
    driver = webdriver.Chrome(service=s)
    

    获取页面

    driver.get('https://finance.yahoo.com/quote/BAC/financials?p=BAC')
    

    等待表加载

    WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, '//div[@class="D(tbhg)"]')))
    

    获取标题行

    headers_elem = driver.find_elements(By.XPATH, '//div[@class="D(tbhg)"]/div/div')
    col_headers = [header.text for header in headers_elem]
    df = pd.DataFrame(columns = col_headers)
    df
    
    Empty DataFrame
    Columns: [Breakdown, TTM, 12/30/2021, 12/30/2020, 12/30/2019, 12/30/2018]
    Index: []
    

    从表中获取行

    这里表中的每一行都存储在rows

    rows = driver.find_elements(By.XPATH, '//div[@class="D(tbrg)"]//div[@data-test="fin-row"]')
    for row in rows:
        row_values = row.find_elements(By.XPATH, 'div/div')
        df.loc[len(df)] = [row_value.text for row_value in row_values]
    

    输出 :

    这给了我们预期的输出

    Breakdown TTM 12/30/2021 12/30/2020 12/30/2019 12/30/2018
    0 Total Revenue 90,742,000 89,113,000 85,528,000 91,244,000 91,247,000
    1 Credit Losses Provision 560,000 4,594,000 -11,320,000 -3,590,000 -3,282,000
    2 Non Interest Expense 59,763,000 59,731,000 55,213,000 54,900,000 53,381,000
    3 Special Income Charges - - - - 0
    4 Pretax Income 31,539,000 33,976,000 18,995,000 32,754,000 34,584,000
    5 Tax Provision 3,521,000 1,998,000 1,101,000 5,324,000 6,437,000
    6 Net Income Common Stockholders 26,565,000 30,557,000 16,473,000 25,998,000 26,696,000
    7 Diluted NI Available to Com Stockholders 26,565,000 30,557,000 16,473,000 25,998,000 26,696,000
    8 Basic EPS - 3.60 1.88 2.77 2.64
    9 Diluted EPS - 3.57 1.87 2.75 2.61
    10 Basic Average Shares - 8,493,300 8,753,200 9,390,500 10,096,500
    11 Diluted Average Shares - 8,558,400 8,796,900 9,442,900 10,236,900
    12 INTEREST_INCOME_AFTER_PROVISION_FOR_LOAN_LOSS 47,080,000 47,528,000 32,040,000 45,301,000 44,150,000
    13 Net Income from Continuing & Discontinued Operation 28,018,000 31,978,000 17,894,000 27,430,000 28,147,000
    14 Normalized Income 28,018,000 31,978,000 17,894,000 27,430,000 28,147,000
    15 Total Money Market Investments 348,000 -90,000 903,000 4,843,000 3,176,000
    16 Reconciled Depreciation 1,953,000 1,898,000 1,843,000 1,729,000 2,063,000
    17 Net Income from Continuing Operation Net Minority Interest 28,018,000 31,978,000 17,894,000 27,430,000 28,147,000
    18 Total Unusual Items Excluding Goodwill - - - - 0
    19 Total Unusual Items - - - - 0
    20 Tax Rate for Calcs 0 0 0 0 0
    21 Tax Effect of Unusual Items 0 0 0 0 0

    TL:博士

    from selenium import webdriver
    from selenium.webdriver.chrome.service import Service
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    import pandas as pd
    
    chrome_path = r"C:\Users\hpoddar\Desktop\Tools\chromedriver_win32\chromedriver.exe"
    s = Service(chrome_path)
    driver = webdriver.Chrome(service=s)
    
    driver.get('https://finance.yahoo.com/quote/BAC/financials?p=BAC')
    
    WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, '//div[@class="D(tbhg)"]')))
    
    headers_elem = driver.find_elements(By.XPATH, '//div[@class="D(tbhg)"]/div/div')
    col_headers = [header.text for header in headers_elem]
    df = pd.DataFrame(columns = col_headers)
    
    rows = driver.find_elements(By.XPATH, '//div[@class="D(tbrg)"]//div[@data-test="fin-row"]')
    for row in rows:
        row_values = row.find_elements(By.XPATH, 'div/div')
        df.loc[len(df)] = [row_value.text for row_value in row_values]
    

    结果存储在df.

    【讨论】:

    • 谢谢!效果很好!抱歉耽搁了
    猜你喜欢
    • 2015-04-07
    • 2020-05-04
    • 1970-01-01
    • 2015-07-19
    • 2021-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-23
    相关资源
    最近更新 更多