Python:使用Beautifulsoup从html获取文本

问题描述 投票:4回答:4

我想从这个链接link example: kaggle user ranking no1中提取排名文本编号。图像中更清晰:

enter image description here

我使用以下代码:

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>]

但在链接的html中检查时这就像:

<h4 data-bind="text: rankingText">1st</h4>。它可以在图像中看到:

enter image description here

很明显,文本丢失了。我怎么能绕过那个?

编辑:在终端中打印soup变量我可以看到该值存在:enter image description here

所以应该有办法通过soup访问。

编辑2:我尝试使用这个stackoverflow question中投票最多的答案,但未成功。可能是周围的解决方案。

python html beautifulsoup html-parsing kaggle
4个回答
4
投票

如果您不打算像@Ali建议的那样通过selenium尝试浏览器自动化,则必须解析包含所需信息的javascript。你可以用不同的方式做到这一点。这是一个工作代码,通过script定位regular expression pattern,然后提取profile对象,将其与json一起加载到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

3
投票

使用javascript对数据进行数据绑定,如“data-bind”属性所示。

但是,如果您下载包含例如wget,你会看到在初始加载时,rankingText值实际上在这个脚本元素中:

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

所以你可以改用它。


0
投票

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

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)

这只返回排名,但我认为它会对你有帮助,因为从我看到的rankText只是在数字的右边添加'st','th'等


-1
投票

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

一些javascript代码,在页面加载后填写此标记。因此,如果您使用请求获取html,它尚未填充。

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

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

© www.soinside.com 2019 - 2024. All rights reserved.