如何从包含请求和 BeautifulSoup4 的动态内容的网站中提取 table 数据?
How to extract table data from website with dynamically content with requests and BeautifulSoup4?
我从该页面提取 table 时遇到一些问题:www.nasdaq.com/market-activity/stocks/aapl/dividend-history
我的代码是:
import requests
from bs4 import BeautifulSoup
headers = {'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'}
page = requests.get("https://www.nasdaq.com/market-activity/stocks/aapl/dividend-history", headers=headers)
soup = BeautifulSoup(page.content, 'html.parser')
table = soup.find('table', attrs={'class':'dividend-history__table'})
table_body = table.find('tbody', attrs={'class': 'dividend-history__table-body'})
data = []
rows = table_body.find('tr', attrs={'class': 'dividend-history__row dividend-history__row--data'})
for row in rows:
cols = row.find('td')
cols = [ele.text.strip() for ele in cols]
data.append([ele for ele in cols if ele]) # Get rid of empty values
他们在 iframe 中有 table。我不确定我做错了什么 - 这是我第一次使用 BeautifulSoup - 我通常使用请求 + xPath 来处理这种事情。
会发生什么?
- Table 不在您猜测的 iframe 中。
- Table 数据是动态生成的,所以你无法用你的方法获取它
- 如果内容是静态的,到这行为止一切都会正常。
看一下 find()
只得到第一次出现的过滤器 - 只有一个 <tr>
而不是你应该使用 find_all()
rows = table_body.find('tr', attrs={'class': 'dividend-history__row dividend-history__row--data'})
您尝试循环一个不可迭代对象:
for row in rows:
与 find()
相同:
cols = row.find('td')
再次迭代一个不可迭代对象:
cols = [ele.text.strip() for ele in cols]
换一种方式怎么样?
从网站抓取数据的方法多种多样,如果它们处理的是动态数据,您经常会遇到 requests
的限制。
使用网站怎么样api?
有请求和 pandas 可以这么简单:
import requests
import pandas as pd
url = "https://api.nasdaq.com/api/quote/AAPL/dividends?assetclass=stocks"
headers = {"user-agent": "Mozilla/5.0"}
r = requests.get(url, headers=headers)
df = pd.json_normalize(r.json()['data']['dividends']['rows'])
df
输出
exOrEffDate type amount declarationDate recordDate paymentDate
11/06/2020 CASH [=14=].205 10/29/2020 11/09/2020 11/12/2020
08/07/2020 CASH [=14=].82 07/30/2020 08/10/2020 08/13/2020
05/08/2020 CASH [=14=].82 04/30/2020 05/11/2020 05/14/2020
02/07/2020 CASH [=14=].77 01/28/2020 02/10/2020 02/13/2020
11/07/2019 CASH [=14=].77 10/30/2019 11/11/2019 11/14/2019
我从该页面提取 table 时遇到一些问题:www.nasdaq.com/market-activity/stocks/aapl/dividend-history
我的代码是:
import requests
from bs4 import BeautifulSoup
headers = {'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'}
page = requests.get("https://www.nasdaq.com/market-activity/stocks/aapl/dividend-history", headers=headers)
soup = BeautifulSoup(page.content, 'html.parser')
table = soup.find('table', attrs={'class':'dividend-history__table'})
table_body = table.find('tbody', attrs={'class': 'dividend-history__table-body'})
data = []
rows = table_body.find('tr', attrs={'class': 'dividend-history__row dividend-history__row--data'})
for row in rows:
cols = row.find('td')
cols = [ele.text.strip() for ele in cols]
data.append([ele for ele in cols if ele]) # Get rid of empty values
他们在 iframe 中有 table。我不确定我做错了什么 - 这是我第一次使用 BeautifulSoup - 我通常使用请求 + xPath 来处理这种事情。
会发生什么?
- Table 不在您猜测的 iframe 中。
- Table 数据是动态生成的,所以你无法用你的方法获取它
- 如果内容是静态的,到这行为止一切都会正常。
看一下 find()
只得到第一次出现的过滤器 - 只有一个 <tr>
而不是你应该使用 find_all()
rows = table_body.find('tr', attrs={'class': 'dividend-history__row dividend-history__row--data'})
您尝试循环一个不可迭代对象:
for row in rows:
与 find()
相同:
cols = row.find('td')
再次迭代一个不可迭代对象:
cols = [ele.text.strip() for ele in cols]
换一种方式怎么样?
从网站抓取数据的方法多种多样,如果它们处理的是动态数据,您经常会遇到 requests
的限制。
使用网站怎么样api?
有请求和 pandas 可以这么简单:
import requests
import pandas as pd
url = "https://api.nasdaq.com/api/quote/AAPL/dividends?assetclass=stocks"
headers = {"user-agent": "Mozilla/5.0"}
r = requests.get(url, headers=headers)
df = pd.json_normalize(r.json()['data']['dividends']['rows'])
df
输出
exOrEffDate type amount declarationDate recordDate paymentDate
11/06/2020 CASH [=14=].205 10/29/2020 11/09/2020 11/12/2020
08/07/2020 CASH [=14=].82 07/30/2020 08/10/2020 08/13/2020
05/08/2020 CASH [=14=].82 04/30/2020 05/11/2020 05/14/2020
02/07/2020 CASH [=14=].77 01/28/2020 02/10/2020 02/13/2020
11/07/2019 CASH [=14=].77 10/30/2019 11/11/2019 11/14/2019