table d'analyse Python BeautifulSoup

89

J'apprends python requestset BeautifulSoup. Pour un exercice, j'ai choisi d'écrire un analyseur rapide de ticket de parking à New York. Je peux obtenir une réponse html qui est assez moche. J'ai besoin de récupérer lineItemsTableet d'analyser tous les tickets.

Vous pouvez reproduire la page en allant ici: https://paydirect.link2gov.com/NYCParking-Plate/ItemSearchet en entrant une NYplaqueT630134C

soup = BeautifulSoup(plateRequest.text)
#print(soup.prettify())
#print soup.find_all('tr')

table = soup.find("table", { "class" : "lineItemsTable" })
for row in table.findAll("tr"):
    cells = row.findAll("td")
    print cells

Quelqu'un peut-il m'aider s'il vous plaît? La simple recherche de tout trne me mène nulle part.

Cmag
la source
À lire de plus près, je ne sais pas vraiment quelle est votre question. Pouvez-vous clarifier exactement pour quelle partie vous avez besoin d'aide?
TML
question links-broken: Ci-dessous un exemple de travail pour une <table> générique.
eusoubrasileiro

Réponses:

171

Voici:

data = []
table = soup.find('table', attrs={'class':'lineItemsTable'})
table_body = table.find('tbody')

rows = table_body.find_all('tr')
for row in rows:
    cols = row.find_all('td')
    cols = [ele.text.strip() for ele in cols]
    data.append([ele for ele in cols if ele]) # Get rid of empty values

Cela vous donne:

[ [u'1359711259', u'SRF', u'08/05/2013', u'5310 4 AVE', u'K', u'19', u'125.00', u'$'], 
  [u'7086775850', u'PAS', u'12/14/2013', u'3908 6th Ave', u'K', u'40', u'125.00', u'$'], 
  [u'7355010165', u'OMT', u'12/14/2013', u'3908 6th Ave', u'K', u'40', u'145.00', u'$'], 
  [u'4002488755', u'OMT', u'02/12/2014', u'NB 1ST AVE @ E 23RD ST', u'5', u'115.00', u'$'], 
  [u'7913806837', u'OMT', u'03/03/2014', u'5015 4th Ave', u'K', u'46', u'115.00', u'$'], 
  [u'5080015366', u'OMT', u'03/10/2014', u'EB 65TH ST @ 16TH AV E', u'7', u'50.00', u'$'], 
  [u'7208770670', u'OMT', u'04/08/2014', u'333 15th St', u'K', u'70', u'65.00', u'$'], 
  [u'$0.00\n\n\nPayment Amount:']
]

Quelques points à noter:

  • La dernière ligne de la sortie ci-dessus, le montant du paiement ne fait pas partie du tableau, mais c'est ainsi que le tableau est présenté. Vous pouvez le filtrer en vérifiant si la longueur de la liste est inférieure à 7.
  • La dernière colonne de chaque ligne devra être traitée séparément car il s'agit d'une zone de texte d'entrée.
shaktimaan
la source
5
je me demande pourquoi ça marche pour toi ... je reçoisrows = table_body.find_all('tr') AttributeError: 'NoneType' object has no attribute 'find_all'
Cmag
@Cmag Utilisez-vous Beautiful Soup 4?
shaktimaan
1
Remplacer find_allparfindAll
user2314737
3
@ user2314737 BS prend en charge la notation en cas de chameau et de soulignement. J'utilise un trait de soulignement qui est en phase avec les directives de codage Python.
shaktimaan
2
Ok j'ai résolu mon erreur: en vue d'inspection de HTML, il montre tbody, cependant, quand j'ai imprimé la valeur de table = soup.find('table', attrs={'class':'analysis'})celui - ci n'a montré aucun tbody là-bas, donc simplement trouver td et tr a fait le travail. Donc, selon moi, la cause de l'erreur AttributeError: 'NoneType' object has no attribute 'find_all'est lorsque nous passons une balise ou un champ qui n'est pas dans le html de la page.
Umesh Kaushik
23

Résolu, voici comment vous analysez leurs résultats html:

table = soup.find("table", { "class" : "lineItemsTable" })
for row in table.findAll("tr"):
    cells = row.findAll("td")
    if len(cells) == 9:
        summons = cells[1].find(text=True)
        plateType = cells[2].find(text=True)
        vDate = cells[3].find(text=True)
        location = cells[4].find(text=True)
        borough = cells[5].find(text=True)
        vCode = cells[6].find(text=True)
        amount = cells[7].find(text=True)
        print amount
Cmag
la source
14

Mise à jour: 2020

Si un programmeur n'est intéressé que par l'analyse de la table de la page Web, il peut utiliser la méthode pandas pandas.read_html.

Disons que nous voulons extraire le tableau de données du PIB du site Web: https://worldpopulationreview.com/countries/countries-by-gdp/#worldCountries

Ensuite, les codes suivants font parfaitement le travail (pas besoin de beautifulsoup et de html fantaisie):

import pandas as pd
import requests

url = "https://worldpopulationreview.com/countries/countries-by-gdp/#worldCountries"

r = requests.get(url)
df_list = pd.read_html(r.text) # this parses all the tables in webpages to a list
df = df_list[0]
df.head()

Production

Cinq premières lignes du tableau du site Web

Bhishan Poudel
la source
D'accord - c'est clairement la meilleure approche à partir de 2020!
kfmfe04
1
Uniquement si vous utilisez déjà des pandas quelque part dans votre projet. Trop de dépendances pour une table
Сергей Яхницкий
3

Voici un exemple de travail pour un générique <table>. ( question des liens rompus )

Extraire le tableau d' ici les pays par PIB (produit intérieur brut).

htmltable = soup.find('table', { 'class' : 'table table-striped' })
# where the dictionary specify unique attributes for the 'table' tag

La tableDataTextfonction analyse un segment html commencé par une balise <table> suivie de plusieurs balises <tr>(lignes de table) et internes <td>(données de table). Il renvoie une liste de lignes avec des colonnes internes. N'accepte qu'un seul <th>(en-tête / données du tableau) dans la première ligne.

def tableDataText(table):       
    rows = []
    trs = table.find_all('tr')
    headerow = [td.get_text(strip=True) for td in trs[0].find_all('th')] # header row
    if headerow: # if there is a header row include first
        rows.append(headerow)
        trs = trs[1:]
    for tr in trs: # for every table row
        rows.append([td.get_text(strip=True) for td in tr.find_all('td')]) # data row
    return rows

En l'utilisant, nous obtenons (deux premières lignes).

list_table = tableDataText(htmltable)
list_table[:2]

[['Rank',
  'Name',
  "GDP (IMF '19)",
  "GDP (UN '16)",
  'GDP Per Capita',
  '2019 Population'],
 ['1',
  'United States',
  '21.41 trillion',
  '18.62 trillion',
  '$65,064',
  '329,064,917']]

Cela peut être facilement transformé en pandas.DataFrameoutils plus avancés.

import pandas as pd
dftable = pd.DataFrame(list_table[1:], columns=list_table[0])
dftable.head(4)

sortie de table html pandas DataFrame

eusoubrasileiro
la source