Raspando una mesa compleja usando Beautifulsoup y Python

NamePasswordRightsBureausFullNameEmailStatusLogon Tries
user1 User Supervisor Administrator Child Supervisor High Medium Low Active Inactive Terminated
user2 User Supervisor Administrator Child Supervisor High Medium Low Active Inactive Terminated

Estoy tratando de raspar una tabla que contiene texto, opciones desplegables y valores. El resultado sería: usuario1 | Supervisor | Medio | First1 Last1 | usuario1@empresa.com | Inactivo

usuario2 | Supervisor | Medio | First2 Last2 | usuario2@empresa.com | Activo

Destinado a ser enviado a csv. Hasta ahora tengo:

 headers = [c.get_text(strip=True) for c in soup.find('tr', attrs={'class':'listHeader'}).findAll('th')] #find_all doesn't work here it just grabs one for table in soup.find('table', attrs={'id':'MainContent_grdUsers2'}): try: column3=(table.find("option", attrs={"selected": "selected"}).get('value')) except: continue #this only grabs a specific cell for table in soup.find('table', attrs={'id':'MainContent_grdUsers2'}): try: column6=(table.find("input", attrs={"id": "MainContent_grdUsers2_txtManageUsersEmail_0"}).get('value')) except: continue 

Puedo entrar y tomar individualmente las celdas que quiero, pero hay alrededor de 100 filas de registros en esta tabla y me resulta difícil encontrar la manera de tomar todo de una vez, ya que no solo hay texto, sino valores de opciones desplegables. y valores ¿Hay alguna manera de hacer esto con Beautifulsoup? Intenté brevemente con pandas y lxml, pero nunca los había usado.

Código actualizado:

 headers = [c.get_text(strip=True) for c in soup.find('tr', attrs={'class':'listHeader'}).findAll('th')] table = soup.find('table', attrs={'id':'MainContent_grdUsers2'}) data = [] for tr in table.find_all('tr')[1:] : td = tr.find_all('td') try : data += [ [ td[0].getText() , td[2].find('option', {'selected':'selected'}).getText(), td[3].find('option', {'selected':'selected'}).getText(), td[4].find('input').get('value'), if value is None: continue td[5].find('input').get('value'), td[6].find('option', {'selected':'selected'}).getText() ] ] except Exception as ex : #print(ex) ## you can uncomment this line for debugging ## continue for row in data : print(' '.join(row)) 

Dado el html que proporcionó, esto debería funcionar:

 if soup.find('tr', attrs={'class':'listHeader'}) : headers = [ 'none' if c is None else c.get_text(strip=True) for c in soup.find('tr', attrs={'class':'listHeader'}).findAll('th') ] else : headers = None table = soup.find('table', attrs={'id':'MainContent_grdUsers2'}) data = [] for tr in table.find_all('tr')[1:] : td = tr.find_all('td') try : data += [ [ td[0].getText() , td[2].find('option', {'selected':'selected'}).getText(), td[3].find('option', {'selected':'selected'}).getText(), td[4].find('input').get('value'), td[5].find('input').get('value'), td[6].find('option', {'selected':'selected'}).getText() ] ] except Exception as ex : #print(ex) ## you can uncomment this line for debugging ## continue for row in data : print(' '.join(str(r) for r in row)) 

Salida:

 user1 Supervisor Medium First1 Last1 user1@company.com Inactive user2 Supervisor Medium First2 Last2 user2@company.com Active