Как я могу создать фрейм данных pandas с пустыми ячейками на основе результатов веб-создания?

#python #pandas #dataframe #beautifulsoup #valueerror

Вопрос:

Я пытаюсь очистить веб-страницу, используя следующий код, однако я получаю ошибку из-за «неправильно подобранных» строк. То, чего я пытаюсь достичь,-это фрейм данных pandas, который содержит название курса, а затем код на полный рабочий день, URL-адрес на полный рабочий день, код на неполный рабочий день, URL-адрес на неполный рабочий день. Проблема в том, что не все курсы имеют как полный, так и неполный рабочий день, поэтому, когда я попытался заменить пробелы на «NA», чтобы получить одинаковое количество строк, это приводит к ошибке.

Следующий код предоставляет выходные данные для всех курсов как с полным, так и с частичным курсом, и этот код не выдает ошибки, так как он допускает только курсы со всеми 5 присутствующими элементами:

 #Import modules import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns %matplotlib inline from urllib.request import urlopen from bs4 import BeautifulSoup from urllib.request import urlopen from bs4 import BeautifulSoup #Specify URL url = "http://eecs.qmul.ac.uk/postgraduate/programmes" html = urlopen(url) # Print the first 10 table rows rows = soup.find_all('tr')  print(rows[:10]) #Create data frame df = pd.DataFrame(columns = ['Course Name', 'Part Time Code', 'Part Time URL', 'Full Time Code', 'Full Time URL']) #Create loop to go through all rows for row in rows:  courses = row.find_all("td")  # The fragments list will store things to be included in the final string, such as the course title and its URLs  fragments = []  for course in courses:  if course.text.isspace():  continue  # Add the lt;tdgt;'s text to fragments  fragments.append(course.text)  # Try and find an lt;agt; tag   a_tag = course.find("a")  if a_tag:  # If one was found, add the URL to fragments  fragments.append(a_tag["href"])  # Make a string containing every fragment with ", " spacing them apart.  cleantext = ", ".join(fragments)  #Add rows to the dataframe if the information exists  if len(fragments) == 5:  df.loc[len(df.index)] = fragments  df.head(30)  

Это и есть результат: введите описание изображения здесь

И это метод, который я использовал, чтобы попытаться заменить пробелы на NA, чтобы убедиться, что в каждой строке есть 5 элементов:

 #Import modules import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns %matplotlib inline from urllib.request import urlopen from bs4 import BeautifulSoup from urllib.request import urlopen from bs4 import BeautifulSoup #Specify URL url = "http://eecs.qmul.ac.uk/postgraduate/programmes" html = urlopen(url) # Print the first 10 table rows rows = soup.find_all('tr')  #Create data frame df = pd.DataFrame(columns = ['Course Name', 'Part Time Code', 'Part Time URL', 'Full Time Code', 'Full Time URL']) #Create loop to go through all rows for row in rows:  courses = row.find_all("td")  # The fragments list will store things to be included in the final string, such as the course title and its URLs  fragments = []  for course in courses:  if course.text.isspace():  fragments.append("NA")  else:  # Add the lt;tdgt;'s text to fragments  fragments.append(course.text)  # Try and find an lt;agt; tag   a_tag = course.find("a")  if a_tag:  # If one was found, add the URL to fragments  fragments.append(a_tag["href"])  else:  fragments.append("NA")  # Make a string containing every fragment with ", " spacing them apart.  cleantext = ", ".join(fragments)  #Add rows to the dataframe if the information exists  if len(fragments) gt; 0:  df.loc[len(df.index)] = fragments  df.head(30)  

И это ошибка, из-за которой он возвращается:

 ValueError Traceback (most recent call last) lt;ipython-input-28-94bb08463416gt; in lt;modulegt;()  38 #Add rows to the dataframe if the information exists  39 if len(fragments) gt; 0: ---gt; 40 df.loc[len(df.index)] = fragments  41 df.head(30)  2 frames /usr/local/lib/python3.7/dist-packages/pandas/core/indexing.py in _setitem_with_indexer_missing(self, indexer, value)  1854 # must have conforming columns  1855 if len(value) != len(self.obj.columns): -gt; 1856 raise ValueError("cannot set a row with mismatched columns")  1857   1858 value = Series(value, index=self.obj.columns, name=indexer)  ValueError: cannot set a row with mismatched columns  

Не могли бы вы определить, как я могу решить эту проблему, чтобы курсы без кода неполной занятости или URL-адреса все еще были включены в фрейм данных, пожалуйста?

Ответ №1:

Все гораздо, гораздо проще, чем это. Найдите таблицу по идентификатору, а затем отправьте prettify отредактированную версию прямо в Pandas IO. Панды вытаскивают Нэн из коробки.

 soup = BeautifulSoup(urlopen('http://eecs.qmul.ac.uk/postgraduate/programmes')) table = soup.find("table", {"id":"PGCourse"}) df = pd.read_html(table.prettify())[0] # rename columns df.columns = ['Course Name', 'Part Time Code', 'Full Time Code']  

Правка: хорошо, затем, чтобы получить ссылки, вам нужно выполнить итерацию:

 pt_links, ft_links = [], []  for row in table.find_all("tr")[1:]:  row_data = row.find_all("td")  pt, ft = row_data[1], row_data[2]  pt_link = pt.find_all('a')  pt_links.append('' if len(pt_link) == 0 else pt_link[0]['href'])  ft_link = ft.find_all('a')  ft_links.append('' if len(ft_link) == 0 else ft_link[0]['href'])  df['Part Time URL'] = pt_links df['Full Time URL'] = ft_links  # rearrange the columns (optional) df = df[['Course Name', 'Part Time Code', 'Part Time URL', 'Full Time Code', 'Full Time URL']]