Python:Getting 来自 html 的文本使用 Beautifulsoup

Python:Getting text from html using Beautifulsoup

我正在尝试从此 link link example: kaggle user ranking no1 中提取排名文本编号。图片更清晰:

我正在使用以下代码:

def get_single_item_data(item_url):
    sourceCode = requests.get(item_url)
    plainText = sourceCode.text
    soup = BeautifulSoup(plainText)
    for item_name in soup.findAll('h4',{'data-bind':"text: rankingText"}):
        print(item_name.string)

item_url = 'https://www.kaggle.com/titericz'   
get_single_item_data(item_url)

结果是None。问题是 soup.findAll('h4',{'data-bind':"text: rankingText"}) 输出:

[<h4 data-bind="text: rankingText"></h4>]

但是在 link 的 html 中检查时就像这样:

<h4 data-bind="text: rankingText">1st</h4>。如图所示:

很明显,文字不见了。我怎样才能通过它?

编辑: 在终端中打印 soup 变量,我可以看到这个值存在:

所以应该有一种方法可以通过soup访问。

编辑 2:我尝试使用这个 Whosebug question 中投票最多的答案,但没有成功。可能是附近的解决方案。

这可能是因为动态数据填充。

一些javascript代码,页面加载后填写此标签。因此,如果您使用请求获取 html,它还没有被填充。

<h4 data-bind="text: rankingText"></h4>

请看Selenium web driver。使用此驱动程序,您可以正常获取完整页面和 运行 js。

数据使用 javascript 进行数据绑定,正如 "data-bind" 属性所建议的那样。

但是,如果您使用例如wget,您会看到 rankingText 值实际上在初始加载时位于此脚本元素内:

<script type="text/javascript"
profile: {
...
   "ranking": 96,
   "rankingText": "96th",
   "highestRanking": 3,
   "highestRankingText": "3rd",
...

所以你可以改用它。

如果您不打算按照@Ali 的建议通过selenium 尝试浏览器自动化,您将不得不解析包含所需信息的javascript.您可以通过不同的方式执行此操作。这是一个工作代码,它通过 regular expression pattern, then extracts the profile object, loads it with jsonscript 定位到 Python 字典中并打印出所需的排名:

import re
import json

from bs4 import BeautifulSoup
import requests


response = requests.get("https://www.kaggle.com/titericz")
soup = BeautifulSoup(response.content, "html.parser")

pattern = re.compile(r"profile: ({.*}),", re.MULTILINE | re.DOTALL)
script = soup.find("script", text=pattern)

profile_text = pattern.search(script.text).group(1)
profile = json.loads(profile_text)

print profile["ranking"], profile["rankingText"]

打印:

1 1st

我已经在纯文本上使用正则表达式解决了你的问题:

def get_single_item_data(item_url):
    sourceCode = requests.get(item_url)
    plainText = sourceCode.text
    #soup = BeautifulSoup(plainText, "html.parser")
    pattern = re.compile("ranking\": [0-9]+")
    name = pattern.search(plainText)
    ranking = name.group().split()[1]
    print(ranking)

item_url = 'https://www.kaggle.com/titericz'
get_single_item_data(item_url)

这个return只是排名数字,但我认为它会对你有所帮助,因为从我看到的rankText来看,只需在右侧添加'st'、'th'等人数