Mxc*_*Fhn 3 python beautifulsoup web-crawler
我正在尝试使用 BeautifulSoup 抓取 coinmarketcap.com (我知道有一个 API,出于培训目的,我想使用 BeautifulSoup)。到目前为止爬取的每一条信息都非常容易选择,但现在我喜欢让“持有者统计信息”看起来像这样:
我用于选择包含所需信息的特定 div 的测试代码如下所示:
import requests
from bs4 import BeautifulSoup
url = 'https://coinmarketcap.com/currencies/bitcoin/holders/'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
holders = soup.select('div', class_='n0m7sa-0 kkBhMM')
print(holders)
Run Code Online (Sandbox Code Playgroud)
print(holders)的输出不是 div 的预期内容,而是网站的整个 html 内容。我附加了一张图片,因为输出代码太长。
有谁知道,为什么会这样?
.select()当你想用作 css 选择器时应该使用。在这种情况下,holders = soup.select('div', class_='n0m7sa-0 kkBhMM')类部分基本上被忽略......并且它找到<div>任何类的所有部分。要指定特定的类,请使用.find_all(), 或更改您的.select()
holders = soup.select('div.n0m7sa-0.kkBhMM')
或者
holders = soup.find_all('div', class_='n0m7sa-0 kkBhMM')
现在,在这两种情况下,它将返回None一个空列表。这是因为该 class 属性不在源 html 中。该站点是动态的,因此这些类是在初始请求后生成的。所以你要么需要先使用Selenium渲染页面,然后拉取html,要么看看是否有api可以直接获取数据源。
有一个api可以获取数据:
import requests
import pandas as pd
alpha = ['count', 'ratio']
payload = {
'id': '1',
'range': '7d'}
for each in alpha:
url = f'https://api.coinmarketcap.com/data-api/v3/cryptocurrency/detail/holders/{each}'
jsonData = requests.get(url, params=payload).json()['data']['points']
if each == 'count':
count_df = pd.DataFrame.from_dict(jsonData,orient='index')
count_df = count_df.rename(columns={0:'Total Addresses'})
else:
ratio_df = pd.DataFrame.from_dict(jsonData,orient='index')
df = count_df.merge(ratio_df, how='left', left_index=True, right_index=True)
df = df.sort_index()
Run Code Online (Sandbox Code Playgroud)
输出:
print(df.to_string())
Total Addresses topTenHolderRatio topTwentyHolderRatio topFiftyHolderRatio topHundredHolderRatio
2021-11-24T00:00:00Z 39279627 5.25 7.19 10.51 13.26
2021-11-25T00:00:00Z 39255811 5.25 7.19 10.49 13.22
2021-11-26T00:00:00Z 39339840 5.25 7.19 10.51 13.24
2021-11-27T00:00:00Z 39391849 5.23 7.11 10.45 13.18
2021-11-28T00:00:00Z 39505340 5.24 7.11 10.45 13.18
2021-11-29T00:00:00Z 39502099 5.24 7.11 10.43 13.16
2021-11-30T00:00:00Z 39523000 5.24 7.11 10.38 13.12
Run Code Online (Sandbox Code Playgroud)
您的其他选项是数据位于<script>json 格式的标签内。S0,您也可以通过这种方式从初始请求站点中取出它:
from bs4 import BeautifulSoup
import requests
import json
import re
url = 'https://coinmarketcap.com/currencies/bitcoin/holders/'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
jsonStr = str(soup.find('script', {'id':'__NEXT_DATA__'}))
jsonStr = re.search(r"({.*})", jsonStr).groups()[0]
jsonData = json.loads(jsonStr)['props']['initialProps']['pageProps']['info']['holders']
df = pd.DataFrame(jsonData).drop('holderList', axis=1).drop_duplicates()
Run Code Online (Sandbox Code Playgroud)
输出:
print(df.to_string())
holderCount dailyActive topTenHolderRatio topTwentyHolderRatio topFiftyHolderRatio topHundredHolderRatio
0 39523000 963625 5.24 7.11 10.38 13.12
Run Code Online (Sandbox Code Playgroud)
对于项目信息中的社交统计信息,它位于特定的 api 中:
import requests
import pandas as pd
url = 'https://api.coinmarketcap.com/data-api/v3/project-info/detail?slug=bitcoin'
jsonData = requests.get(url).json()
socialStats = jsonData['data']['socialStats']
row = {}
for k, v in socialStats.items():
if type(v) == dict:
row.update(v)
else:
row.update({k:v})
df = pd.DataFrame([row])
Run Code Online (Sandbox Code Playgroud)
输出:
print(df.to_string())
cryptoId commits contributors stars forks watchers lastCommitAt members updatedTime
0 1 31588 836 59687 30692 3881 2021-11-30T00:09:02.000Z 3617460 2021-11-30T16:00:02.365Z
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
657 次 |
| 最近记录: |