Передача данных таблицы с помощью Beautifulsoup - PullRequest
3 голосов
/ 24 июня 2019

Я пытаюсь разобрать эту веб-страницу .

Как показано ниже, каждая страница имеет статистику способностей.В конце концов я пытаюсь разобрать все способности в объект.e.g. {'corners': 15, 'crossing': 15...}

Сначала я начал анализировать одну статистику, corners, выполнив:

from bs4 import BeautifulSoup as bs
import requests
url = 'https://fmdataba.com/19/p/1165/lionel-messi/'
page = requests.get(url)
soup = bs(page.content, 'html.parser')
print(soup.prettify())
soup.find({"id": "fm_cro"})

, но это возвращает пустой список.

Может кто-нибудь помочь, пожалуйста?

enter image description here

Ответы [ 4 ]

4 голосов
/ 24 июня 2019

С помощью bs4 4.7.1 вы можете использовать nth-child(odd) и nth-child(even), чтобы получить различные tds в каждом ряду для создания своего диктата;и используйте :has и :contains, чтобы получить правильную таблицу для каждого ключевого слова и построить свой внешний дикт для размещения каждого внутреннего.

import requests
from bs4 import BeautifulSoup as bs

r = requests.get('https://fmdataba.com/19/p/1165/lionel-messi/', headers = {'User-Agent':'Mozilla/5.0'})
soup = bs(r.content, 'lxml')
abilities = ['TECHNICAL', 'MENTAL' , 'PHYSICAL']

def get_abilities(soup, keyword):
    table = soup.select_one('div:has(h3:contains("' + ability + '")) + div > table')
    d = {item.select_one('td:nth-child(odd)').text: int(item.select_one('td:nth-child(even)').text) for item in table.select('tr')}
    return d

results = {}

for ability in abilities:
    results[ability] = get_abilities(soup, ability)

print(results)  

Вывод:

enter image description here


Объяснение CSS:

Строка селектора css выглядит следующим образом:

soup.select_one('div:has(h3:contains("' + ability + '")) + div > table')

select_one isподобно select в том смысле, что он применяет селектор css внутри объекта супа, но возвращает только первое совпадение.

:has и :contains являются псевдоклассами подобно :nth-child().Глядя на рассматриваемый html-файл для первой таблицы способностей, здесь приводится объяснение частей:

Нажмите на изображение, чтобы увеличить его.

enter image description here


Дополнительное чтение:

  1. Селекторы псевдокласса
  2. Комбинированный соседний брат и сестра
  3. Дочерний комбинатор
  4. Общие сведения о селекторах Css
  5. select_one
3 голосов
/ 24 июня 2019

Вот еще один способ добиться тех же результатов без жесткого кодирования селекторов:

import requests
from bs4 import BeautifulSoup

r = requests.get('https://fmdataba.com/19/p/1165/lionel-messi/', headers={'User-Agent':'Mozilla/5.0'})
soup = BeautifulSoup(r.text, 'lxml')
datadict = {}
for container in ['TECHNICAL','MENTAL','PHYSICAL']:
    elem = soup.select_one(f".panel-heading:contains('{container}') + .panel-body")
    datadict[container] = {item.text:item.find_next_sibling().text for item in elem.select("td.active")}
print(datadict)

Выход:

{'TECHNICAL': {'Corners': '15', 'Crossing': '15', 'Dribbling': '20', 'Finishing': '20', 'First Touch': '19', 'Free Kick': '19', 'Heading': '10', 'Long Shots': '17', 'Long Throws': '4', 'Marking': '4', 'Passing': '20', 'Penalty Taking': '17', 'Tackling': '7', 'Technique': '20'}, 'MENTAL': {'Aggression': '7', 'Anticipation': '19', 'Bravery': '10', 'Composure': '18', 'Concentration': '13', 'Decisions': '20', 'Determination': '20', 'Flair': '20', 'Leadership': '14', 'Off The Ball': '16', 'Positioning': '5', 'Teamwork': '14', 'Vision': '20', 'Work Rate': '7'}, 'PHYSICAL': {'Acceleration': '18', 'Agility': '20', 'Balance': '20', 'Jumping Reach': '6', 'Natural Fitness': '14', 'Pace': '15', 'Stamina': '13', 'Strength': '9'}}
2 голосов
/ 24 июня 2019

Вы также можете использовать pandas:

import pandas as pd
import requests

url = 'https://fmdataba.com/19/p/1165/lionel-messi/'
page = requests.get(url, headers={'User-Agent':'Mozilla/5.0'})

tables = pd.read_html(page.text)
all_data = {}
for idx, name in [(2, 'TECHNICAL'), (3, 'MENTAL'), (4, 'PHYSICAL')]:
    tbl = tables[idx]
    data = {r[0]: r[1] for _, r in tbl.iterrows()}
    all_data[name] = data

tables[2] - это ТЕХНИЧЕСКАЯ таблица, tables[3] - это МЕНТАЛЬНАЯ таблица, а tables[4] - ФИЗИЧЕСКАЯ таблица.

0 голосов
/ 24 июня 2019

Основываясь на документации , методы find() и find_all() не принимают словарь, у них есть необязательный аргумент ключевого слова id, который можно использовать.

soup.find(id='fm_cro')

Это даст вам элемент с этим идентификатором (в данном случае <td> с текстом «Пересечение»). Если вы хотите получить связанный номер, вам нужно использовать методы-братья BeautifulSoup, чтобы получить следующий соседний <td> и запросить его текст (номер).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...