2017-01-11 6 views
1

Я изучаю Pyhton и прекрасный суп в частности, и я выполняю упражнение Google в Regex, используя набор html-файлов, содержащих популярные детские имена для разных лет (например, baby1990.html и т. д.). Вы можете найти этот набор данных, если вы заинтересованы здесь: https://developers.google.com/edu/python/exercises/baby-namesОбъект ResultSet не имеет атрибута «findAll» в Beautiful Soup в функции

Каждый HTML-файл содержит таблицу с данными именами ребенка, который выглядит следующим образом:

enter image description here

Я написал функцию, которая извлекает имена детей из html-файлов и хранит их в dataframes, dataframes в словаре и всех dataframes, агрегированных в единый dataframe.

В каждом файле html есть две таблицы. Таблица, которая содержит данные, ребенок имеет следующий HTML-код:

<table width="100%" border="0" cellspacing="0" cellpadding="4" summary="formatting"> 

В этой строке отличительный признак является резюме = «Форматирование».

Функции я написал был отредактирован на основе обратной связи я получил и следующее:

def babynames(path): 

# This function takes the path of the directory where the html files are stored and returns a list containing the 
# a dataframe which encompasses all the tabular baby-names data in the files and as well as a dictionary holding 
# a separate dataframe for each html file 

# 0: Initialize objects 
dicnames = {} # will hold the dataframes containing the tabular data of each year 
dfnames = pd.DataFrame([]) # will hold the aggregate data 

# 1: Create a list containing the full paths of the baby files in the directory indicated by the path argument of the babynames 
# function 
allfiles = files(path) 

# 2: Begin the looping through the files 

for file in allfiles: 
     with open(file,"r") as f: soup = bs(f.read(), 'lxml') # Convert the file to a soup 

     # 3. Initialize empty lists to hold the contents of the cells 
     Rank=[] 
     Baby_1 =[] 
     Baby_2 =[] 
     df = pd.DataFrame([]) 

     # 4. Extract the Table containing the Baby data and loop through the rows of this table 

     for row in soup.select("table[summary=formatting] tr"): 

     # 5. Extract the cells 

      cells = row.findAll("td") 

      # 6. Convert to text and append to lists 
      try: 
       Rank.append(cells[0].find(text=True)) 
       Baby_1.append(cells[1].find(text=True)) 
       Baby_2.append(cells[2].find(text=True)) 
      except: 
       print "file: " , file 
       try: 
         print "cells[0]: " , cells[0] 
       except: 
         print "cells[0] : NaN" 
       try: 
         print "cells[1]: " , cells[1] 
       except: 
         print "cells[1] : NaN"  
       try: 
         print "cells[2]: " , cells[2] 
       except: 
         print "cells[2] : NaN" 

      # 7. Append the lists to the empty dataframe df 
      df["Rank"] = Rank 
      df["Baby_1"] = Baby_1 
      df["Baby_2"] = Baby_2 

      # 8. Append the year to the dataframe as a separate column 
      df["Year"] = extractyear(file) # Call the function extractyear() defined in the environment with input 
              # the full pathname stored in variable file and examined in the current 
              # iteration 

      # 9. Rearrange the order of columns 
      # df.columns.tolist() = ['Year', 'Rank', 'Baby_1', 'Baby_2'] 

      #10. Store the dataframe to a dictionary as the value which key is the name of the file 
      pattern = re.compile(r'.*(baby\d\d\d\d).*') 
      filename = re.search(pattern, file).group(1) 
      dicnames[filename] = df 

    # 11. Combine the dataframes stored in the dictionary dicname to an aggregate dataframe dfnames 
     for key, value in dicnames.iteritems(): 
      dfnames = pd.concat[dfnames, value] 

    # 12. Store the dfnames and dicname in a list called result. Return result. 
     result = [dfnames, dicnames] 
     return result 

Когда я запускаю функцию с заданной траекторией (путь моего каталога, в котором я хранится в HTML-файлах) Я получаю следующее сообщение об ошибке:

result = babynames(path) 

Out:

--------------------------------------------------------------------------- 


file: C:/Users/ALEX/MyFiles/JUPYTER NOTEBOOKS/google-python-exercises/babynames/baby1990.html 
cells[0]: cells[0] : NaN 
cells[1]: cells[1] : NaN 
cells[2]: cells[2] : NaN 
--------------------------------------------------------------------------- 
ValueError        Traceback (most recent call last) 
<ipython-input-72-5c9ebdc4dcdb> in <module>() 
----> 1 result = babynames(path) 

<ipython-input-71-a0263a6790da> in babynames(path) 
    54 
    55     # 7. Append the lists to the empty dataframe df 
---> 56     df["Rank"] = Rank 
    57     df["Baby_1"] = Baby_1 
    58     df["Baby_2"] = Baby_2 

C:\users\alex\Anaconda2\lib\site-packages\pandas\core\frame.pyc in __setitem__(self, key, value) 
    2355   else: 
    2356    # set column 
-> 2357    self._set_item(key, value) 
    2358 
    2359  def _setitem_slice(self, key, value): 

C:\users\alex\Anaconda2\lib\site-packages\pandas\core\frame.pyc in _set_item(self, key, value) 
    2421 
    2422   self._ensure_valid_index(value) 
-> 2423   value = self._sanitize_column(key, value) 
    2424   NDFrame._set_item(self, key, value) 
    2425 

C:\users\alex\Anaconda2\lib\site-packages\pandas\core\frame.pyc in _sanitize_column(self, key, value) 
    2576 
    2577    # turn me into an ndarray 
-> 2578    value = _sanitize_index(value, self.index, copy=False) 
    2579    if not isinstance(value, (np.ndarray, Index)): 
    2580     if isinstance(value, list) and len(value) > 0: 

C:\users\alex\Anaconda2\lib\site-packages\pandas\core\series.pyc in _sanitize_index(data, index, copy) 
    2768 
    2769  if len(data) != len(index): 
-> 2770   raise ValueError('Length of values does not match length of ' 'index') 
    2771 
    2772  if isinstance(data, PeriodIndex): 

ValueError: Length of values does not match length of index 

Клетки [0], ячейки 1 и ячейки [2] должны иметь значения.

Как я уже говорил есть еще одна таблица, предшествующего идентифицируются следующим кодом HTML:

<table width="100%" border="0" cellspacing="0" cellpadding="4"> 

я запустить версию функции, в которой я не указать таблицу - я не заметил, что там были две таблицы в html-файле. В этой версии я не получил такой тип ошибок. У меня были сообщения об ошибках для строки 6, что идентификация операторов try была неправильной - что я не понимаю, - и сообщение об ошибке для строки 9, где я пытаюсь изменить столбцы блока данных, что я также не мог понять.

Ваш совет будет оценен по достоинству.

+0

try 'right_table.find_all (" tr ")'. Замените 'findAll()' на 'find_all()' – MYGz

ответ

2

right_table является ResultSet экземпляром (в основном, список Tag экземпляров, представляющих элементы), он не имеет findAll() или find_all() метода.

Вместо этого, вы либо цикл по элементам right_table, если у вас несколько из них:

right_table = soup.find_all("table", summary_ = "formatting") 

for table in right_table: 
    for row in table.findAll("tr"): 
     # ... 

Или используйте find() в случае, если есть один один:

right_table = soup.find("table", summary_ = "formatting") 

Или, используйте один CSS-селектор:

for row in soup.select("table[summary=formatting] tr"): 
    # ...