#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']]