Я пытаюсь извлечь номер рейтинга из этой ссылки пример ссылки: рейтинг пользователя kaggle № 1. Более ясно на изображении:

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 в терминале, я вижу, что это значение существует: введите описание изображения здесь

Так что должен быть способ доступа через soup.

Изменить 2: Я безуспешно пытался использовать наиболее проголосовавший ответ из этого -content-add-from-js "> вопрос stackoverflow . Может быть решение где-то там.

4
Mpizos Dimitris 17 Дек 2015 в 16:40

4 ответа

Лучший ответ

Если вы не собираетесь пытаться автоматизировать браузер через selenium, как предложил @Ali, вам придется проанализировать javascript, содержащий нужную информацию . Вы можете сделать это по-разному. Вот рабочий код, который находит script с помощью шаблон регулярного выражения, затем извлекает объект 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
4
alecxe 17 Дек 2015 в 15:28

Я решил вашу проблему с помощью регулярных выражений на простой текст:

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' и т. Д. Справа от номера

0
Tales Pádua 17 Дек 2015 в 20:16

Это может из-за динамического заполнения данных.

Какой-то код JavaScript, заполните этот тег после загрузки страницы. Таким образом, если вы получаете html, используя запросы, он еще не заполнен.

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

Пожалуйста, ознакомьтесь с веб-драйвером Selenium. Используя этот драйвер, вы можете получить всю страницу и запустить js как обычно.

-1
Ali Nikneshan 17 Дек 2015 в 13:47

Данные связаны с использованием javascript, как предполагает атрибут «data-bind».

Однако, если вы загружаете страницу, например, с помощью wget, вы увидите, что значение ratingText на самом деле находится внутри этого элемента скрипта при начальной загрузке:

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

Таким образом, вы могли бы использовать это вместо этого.

3
steinar 17 Дек 2015 в 14:27