Веб-скребок Python "find_all (attr)" возвращает пустой список - PullRequest
0 голосов
/ 12 февраля 2019

Итак, я очищаю веб-сайт и в основном хочу сохранить некоторые данные таблиц в словаре.

Ниже приведена моя программа для очистки-

from bs4 import BeautifulSoup
from collections import defaultdict
import json
import requests
import re 


sauce = 'http://m.ironman.com/triathlon/events/americas/ironman/world-championship/results.aspx'


r = requests.get(sauce)
data = r.text

soup = BeautifulSoup(data, 'html.parser')

def parse_table(soup):
    result = defaultdict(list)
    my_table = soup.find('tbody')

    for row in my_table.find_all('tr'):
        try:
            name, div_rank, gender_rank, overall_rank, swim, bike, run,
            total_time = (col.text.strip() for col in row.find_all('td')[2:])
        except ValueError:
            continue

        result[name].append({
            'div_rank': div_rank,
            'gender_rank': gender_rank,
            'overall_rank': overall_rank,
            'swim': swim,
            'bike': bike,
            'run': run,
            'total_time': total_time
            })

    return result


print(json.dumps(parse_table(soup), indent=3))

Я проверил, что print(my_table) не пусто, но если я проверю print(my_table.find_all('tr')), оно пусто.Все данные, которые мне нужны, находятся внутри тега td, который находится внутри тегов tr, которые находятся внутри my_table.

Почему find_all('tr') возвращает пустое значение?


Edit: вывод print(my_table) - это, в основном, куча tr s вроде-

<tr data-bib-number="838"
                    data-result-page="?bidid=838&rd=10/13/2018 12:00:00 AM&race=worldchampionship"
                    data-gender="female"
                    data-age="50-54"
                    data-country="usa">
                    <td><span class="icon-flag USA" style="background-image: url(/Media/mvc/Images/Countries/usa.svg );"></span></td>
                    <td class="text-bold text-left">Younts, Joanna <span class="bib-number hidden">838</span></td>
                    <td data-order="133813">                                                                          <span class="last-position"></span></td>
                    <td data-order="011952" class="small-hidden">01:19:52</td>
                    <td data-order="055020" class="small-hidden">05:50:20</td>
                    <td data-order="061111" class="small-hidden">06:11:11</td>
                    <td data-order="58" class="small-hidden group-rank">58</td>
                    <td data-order="523" class="small-hidden gender-rank">523</td>
                    <td data-order="2008" class="overall-rank">2008</td>
                </tr>

Ответы [ 2 ]

0 голосов
/ 12 февраля 2019

Проблема в том, что фактический HTML-код в таблице содержит комментарий, а не строки (может быть, расстроить скребки?).Помимо этого, было также несколько ошибок Python.Если мы фиксируем tbody и затем извлекаем из него комментарий (который содержит реальные данные), мы можем затем проанализировать комментарий как таблицу HTML.

Строки не упорядочены так, как они отображаются при просмотреHTML в браузере, я думаю, они перемешиваются после преобразования из комментария.В любом случае, мы затем получаем доступ к данным, поскольку они организованы в нашем источнике, который отличается от того, который отображается в браузере.Кажется, что общее время в таблице не содержится. Я предполагаю, что код JavaScript, который преобразует комментарий в таблицу, вычисляет это, так что вам, возможно, придется рассчитывать это самостоятельно (я не буду делать это здесь).

Код

from bs4 import BeautifulSoup, Comment
from collections import defaultdict
import json
import requests

sauce = 'http://m.ironman.com/triathlon/events/americas/ironman/world-championship/results.aspx'


r = requests.get(sauce)
data = r.text

soup = BeautifulSoup(data, 'html.parser')

def parse_table(soup):
    result = defaultdict(list)
    my_table = soup.find('tbody')

    for node in my_table.children:
        if isinstance(node, Comment):
            # Get content and strip comment "<!--" and "-->"
            # Wrap the rows in "table" tags as well.
            data = '<table>{}</table>'.format(node[4:-3])
            break

    table = BeautifulSoup(data, 'html.parser')

    for row in table.find_all('tr'):
        name, _, swim, bike, run, div_rank, gender_rank, overall_rank = [col.text.strip() for col in row.find_all('td')[1:]]

        result[name].append({
            'div_rank': div_rank,
            'gender_rank': gender_rank,
            'overall_rank': overall_rank,
            'swim': swim,
            'bike': bike,
            'run': run,
            # 'total_time': total_time
        })

    return result

print(json.dumps(parse_table(soup), indent=3))

Что даст вам различные записи (я просто покажу пару):

{
   "Goodlad, Martin 977": [
      {
         "div_rank": "156",
         "gender_rank": "899",
         "overall_rank": "1026",
         "swim": "00:57:56",
         "bike": "05:00:29",
         "run": "04:20:04"
      }
   ],
   "Maley, Joel 1840": [
      {
         "div_rank": "39",
         "gender_rank": "171",
         "overall_rank": "186",
         "swim": "01:12:01",
         "bike": "04:34:59",
         "run": "03:17:13"
      }
   ]
}
0 голосов
/ 12 февраля 2019

Проблема с html.parser.

Можете ли вы установить lxml и изменить код на следующее:

soup = BeautifulSoup(data, 'lxml')

Вывод:

defaultdict( < class 'list' > , 
        {'1': [{'div_rank': '1', 'gender_rank': '1', 'overall_rank': '00:50:37', 'swim': '04:16:04', 'bike': '02:41:31', 'run': '07:52:39', 'total_time': '5000'}],
          '2': [{'div_rank': '2', 'gender_rank': '2', 'overall_rank': '00:54:07', 'swim': '04:12:25', 'bike': '02:45:41', 'run': '07:56:41', 'total_time': '4951'}],
          '3': [{'div_rank': '3', 'gender_rank': '3', 'overall_rank': '00:49:31', 'swim': '04:21:18', 'bike': '02:46:03', 'run': '08:01:09', 'total_time': '4898'}],
          '4': [{'div_rank': '4', 'gender_rank': '4', 'overall_rank': '00:47:45', 'swim': '04:18:45', 'bike': '02:52:33', 'run': '08:03:17', 'total_time': '4872'}],
          '5': [{'div_rank': '5', 'gender_rank': '5', 'overall_rank': '00:49:28', 'swim': '04:17:17', 'bike': '02:53:38', 'run': '08:04:41', 'total_time': '4855'}],
          '6': [{'div_rank': '6', 'gender_rank': '6', 'overall_rank': '00:54:02', 'swim': '04:12:58', 'bike': '02:52:56', 'run': '08:04:45', 'total_time': '4854'}],
          '7': [{'div_rank': '7', 'gender_rank': '7', 'overall_rank': '00:50:53', 'swim': '04:15:41', 'bike': '02:54:15', 'run': '08:05:54', 'total_time': '4841'}],
          '8': [{'div_rank': '8', 'gender_rank': '8', 'overall_rank': '00:49:33', 'swim': '04:18:51', 'bike': '02:56:27', 'run': '08:09:34', 'total_time': '4797'}],
          '9': [{'div_rank': '9', 'gender_rank': 'overall_rank': '00:50:51', 'swim': '04:09:06', 'bike': '03:06:18', 'run': '08:10:32', 'total_time': '4785'}],
          '10': [{'div_rank': '10', 'gender_rank': '10', 'overall_rank': '00:54:14', 'swim': '04:11:27', 'bike': '03:00:02', 'run': '08:11:04', 'total_time': '4779'}],
          '11': [{'div_rank': '11', 'gender_rank': '11', 'overall_rank': '00:47:46', 'swim': '04:19:44', 'bike': '02:59:24', 'run': '08:11:41', 'total_time': '4771'}],
          '12': [{'div_rank': '12', 'gender_rank': '12', 'overall_rank': '00:50:39', 'swim': '04:27:47', 'bike': '02:50:36', 'run': '08:13:47', 'total_time': '4746'}],
          '13': [{'div_rank': '13', 'gender_rank': '13', 'overall_rank': '00:50:56', 'swim': '04:15:17', 'bike': '03:02:50', 'run': '08:14:02', 'total_time': '4743'}],
          '14': [{'div_rank': '14', 'gender_rank': '14', 'overall_rank': '00:50:48', 'swim': '04:19:48', 'bike': '02:58:04', 'run': '08:14:31', 'total_time': '4737'}],
          '15': [{'div_rank': '15', 'gender_rank': '15', 'overall_rank': '00:50:39', 'swim': '04:19:58', 'bike': '03:00:17', 'run': '08:15:58', 'total_time': '4720'}],
          '16': [{'div_rank': '16', 'gender_rank': '16', 'overall_rank': '00:50:45', 'swim': '04:25:04', 'bike': '02:57:35', 'run': '08:17:54', 'total_time': '4697'}],
          '17': [{'div_rank': '17', 'gender_rank': '17', 'overall_rank': '00:50:41', 'swim': '04:21:02', 'bike': '03:02:00', 'run': '08:18:18', 'total_time': '4692'}],
          '18': [{'div_rank': '18', 'gender_rank': '18', 'overall_rank': '00:50:45', 'swim': '04:19:56', 'bike': '03:03:47', 'run': '08:19:13', 'total_time': '4681'}],
          '19': [{'div_rank': '19', 'gender_rank': '19', 'overall_rank': '00:47:43', 'swim': '04:19:01', 'bike': '03:08:42', 'run': '08:19:40', 'total_time': '4675'}],
          '20': [{'div_rank': '20', 'gender_rank': '20', 'overall_rank': '00:47:51', 'swim': '04:18:38', 'bike': '03:10:07', 'run': '08:21:52', 'total_time': '4649'}]})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...