Очистите таблицу в Википедии с помощью beautifulsoup - PullRequest
0 голосов
/ 29 мая 2020

Я пытался очистить таблицу в Википедии с помощью Beautifulsoup, но столкнулся с некоторыми проблемами.

Страница: https://en.wikipedia.org/wiki/New_York_City Таблица: введите описание изображения здесь

Таблица: «Расовый состав»

На странице источник, таблица, кажется, начинается со строки 1470.

Вот код, который я попробовал первым:

website_url = requests.get('https://en.wikipedia.org/wiki/New_York_City').text
soup = BeautifulSoup(website_url,'lxml')
table = soup.find('table',{'class':'wikitable sortable collapsible'})

headers = [header.text for header in table.find_all('th')]

table_rows = table.find_all('tr')        
rows = []
for row in table_rows:
   td = row.find_all('td')
   row = [row.text for row in td]
   rows.append(row)

with open('NYC_DEMO.csv', 'w') as f:
   writer = csv.writer(f)
   writer.writerow(headers)
   writer.writerows(row for row in rows if row)

И вот ошибка:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-24-e6000bdafe11> in <module>
      3 table = soup.find('table',{'class':'wikitable sortable collapsible'})
      4 
----> 5 headers = [header.text for header in table.find_all('th')]
      6 
      7 table_rows = table.find_all('tr')

AttributeError: 'NoneType' object has no attribute 'find_all'

Полагаю, это это код со страницы Википедии, который нам нужно получить:

<tbody><tr>
<th>Racial composition</th>
<th>2010<sup id="cite_ref-QuickFacts2010_226-1" class="reference"><a href="#cite_note-QuickFacts2010-226">&#91;224&#93;</a></sup></th>
<th>1990<sup id="cite_ref-pop_228-0" class="reference"><a href="#cite_note-pop-228">&#91;226&#93;</a></sup></th>
<th>1970<sup id="cite_ref-pop_228-1" class="reference"><a href="#cite_note-pop-228">&#91;226&#93;</a></sup></th>
<th>1940<sup id="cite_ref-pop_228-2" class="reference"><a href="#cite_note-pop-228">&#91;226&#93;</a></sup>
</th></tr>
<tr>
<td><a href="/wiki/White_American" class="mw-redirect" title="White American">White</a></td>
<td>44.0%</td>
<td>52.3%</td>
<td>76.6%</td>
<td>93.6%
</td></tr>
<tr>
...

Я предполагаю, что он не может найти нужную таблицу? На этой странице довольно много таблиц, так как мне правильно указать на эту таблицу?

Заранее спасибо за вашу помощь.

Ответы [ 2 ]

1 голос
/ 29 мая 2020

Проблема в том, что он не вернет таблицу с class="wikitable sortable collapsible", потому что она явно не входит в html. вам нужно будет использовать регулярное выражение, чтобы найти классы, которые СОДЕРЖАТ эту подстроку, так как это будет работать. Во-вторых, .find() вернет только первый найденный элемент. Если таблица, которую вы пытаетесь захватить, не имеет указанного c и уникального атрибута для ее идентификации, использование .find() не будет работать. Если есть несколько элементов, вам нужно использовать .find_all(), и даже тогда вам нужно будет перебирать их, чтобы получить нужную таблицу.

Как кто-то сказал, вы также можете использовать pandas ' .read_html(). Это вернет все теги таблицы в списке, а затем нужно будет найти позицию индекса нужной таблицы. Я предоставил вам оба варианта:

Использование Pandas:

import pandas as pd

url = 'https://en.wikipedia.org/wiki/New_York_City'

df = pd.read_html(url)[9]
df.to_csv('NYC_DEMO.csv',index=False)

Использование BeautifulSoup:

import requests
from bs4 import BeautifulSoup

url = 'https://en.wikipedia.org/wiki/New_York_City'
website_url = requests.get(url).text
soup = BeautifulSoup(website_url,'html.parser')
tables = soup.find_all('table')
for table in tables:
    if 'Racial composition' in table.text:
        headers = [header.text.strip() for header in table.find_all('th')]
        rows = []
        table_rows = table.find_all('tr')    
        for row in table_rows:
           td = row.find_all('td')
           row = [row.text for row in td]
           rows.append(row)

df = pd.DataFrame(rows, columns=headers)       

Вывод:

print (df)
                 Racial composition 2010[224] 1990[226]   1970[226] 1940[226]
0                             White     44.0%     52.3%       76.6%     93.6%
1                     —Non-Hispanic     33.3%     43.2%  62.9%[227]     92.0%
2         Black or African American     25.5%     28.7%       21.1%      6.1%
3  Hispanic or Latino (of any race)     28.6%     24.4%  16.2%[227]      1.6%
4                             Asian     12.7%      7.0%        1.2%         –
1 голос
/ 29 мая 2020

Полагаю, он не может найти нужную таблицу?

Кажется, это так, да. Если вы проверите значение table, вы увидите, что это None, и поэтому вызов find_all для него не работает.

Если вы проверите таблицу на странице, вы посмотрите, что его классы - wikitable collapsible collapsed mw-collapsible mw-made-collapsible, а класса sortable там нет. Вот почему ваша программа не находит ни одного подходящего элемента table.

На этой странице довольно много таблиц, так как мне правильно указать на эту таблицу?

Во-первых, вы можете подключиться к какому-нибудь уникальному идентификатору, например к id элемента, но в вашем случае его нет. Если бы у него был thead или какой-то заголовок, вы могли бы попробовать с этим, но опять же, это не тот случай.

Затем вам нужно go дальше вверх по дереву DOM, и проверьте его родителей, есть ли у них какие-либо уникальные идентификаторы. По плану вы добавляете родителя в селектор. К сожалению, основная часть статей Википедии, кажется, заключена в один большой элемент без семантического разделения разделов. Это затрудняет очистку.

На этом этапе я бы сказал, что вам остается просто смотреть на страницу браузера и думать о том, как вы могли бы естественным образом идентифицировать таблицу (непрограммно). Вы смотрите на него и видите, что в заголовке указано Расовый состав . И вы можете получить его с помощью чего-то вроде

table_heading = soup.find('th', text='Racial composition')      # this gives you the `th`
if table_heading:
    table = table_heading.find_parents('table')

Могут быть некоторые другие beautifulsoup API, которых я не знаю, но вы можете добавить это в свой код, и он должен работать.

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