ตารางวิเคราะห์ python BeautifulSoup


89

ฉันเรียน python requestsและ BeautifulSoup สำหรับการออกกำลังกายฉันเลือกที่จะเขียนโปรแกรมแยกวิเคราะห์ตั๋วจอดรถ NYC ฉบับย่อ ฉันได้รับการตอบสนอง html ซึ่งค่อนข้างน่าเกลียด ฉันต้องการที่จะคว้าlineItemsTableและแยกตั๋วทั้งหมด

คุณสามารถสร้างหน้าซ้ำได้โดยไปที่นี่: https://paydirect.link2gov.com/NYCParking-Plate/ItemSearchและป้อนNYจานT630134C

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

ใครช่วยฉันหน่อยได้ไหม การค้นหาที่เรียบง่ายtrไม่ทำให้ฉันไปไหน


เมื่ออ่านอย่างละเอียดฉันไม่แน่ใจว่าคำถามของคุณคืออะไร คุณช่วยชี้แจงได้ไหมว่าต้องการความช่วยเหลือในส่วนใด
TML

ลิงก์คำถามเสีย: ขอตัวอย่างการทำงานสำหรับ <table> ทั่วไป
eusoubrasileiro

คำตอบ:


173

ได้แล้ว:

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

สิ่งนี้ช่วยให้คุณ:

[ [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:']
]

สองสิ่งที่ควรทราบ:

  • แถวสุดท้ายในผลลัพธ์ด้านบนจำนวนการชำระเงินไม่ได้เป็นส่วนหนึ่งของตาราง แต่เป็นวิธีการจัดวางตาราง คุณสามารถกรองออกโดยตรวจสอบว่าความยาวของรายการน้อยกว่า 7 หรือไม่
  • คอลัมน์สุดท้ายของทุกแถวจะต้องจัดการแยกกันเนื่องจากเป็นกล่องข้อความอินพุต

6
ฉันสงสัยว่าทำไมมันถึงเหมาะกับคุณ ... ฉันเข้าใจrows = table_body.find_all('tr') AttributeError: 'NoneType' object has no attribute 'find_all'
Cmag

@Cmag ใช้ซุปตาร์ 4 สวยมั้ย?
shaktimaan

1
แทนที่find_allด้วยfindAll
user2314737

4
@ user2314737 BS รองรับทั้งเคสอูฐและสัญกรณ์ขีดล่าง ฉันใช้ขีดล่างซึ่งสอดคล้องกับหลักเกณฑ์การเข้ารหัส Python
shaktimaan

3
ตกลงฉันแก้ไขข้อผิดพลาดของฉัน: ในการตรวจสอบมุมมองของ html มันแสดง tbody อย่างไรก็ตามเมื่อฉันพิมพ์ค่าของ table = soup.find('table', attrs={'class':'analysis'})มันแสดงว่าไม่มีใครอยู่ที่นั่นดังนั้นเพียงแค่ค้นหา td และ tr ก็ทำงานได้ ตามฉันแล้วสาเหตุของการรับข้อผิดพลาด AttributeError: 'NoneType' object has no attribute 'find_all'คือเมื่อเราส่งแท็กหรือฟิลด์ที่ไม่อยู่ใน html ของหน้า
Umesh Kaushik

23

แก้ไขได้นี่คือวิธีที่คุณแยกวิเคราะห์ผลลัพธ์ 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

18

อัปเดต: 2020

หากโปรแกรมเมอร์สนใจเฉพาะการแยกวิเคราะห์ตารางจากหน้าเว็บพวกเขาสามารถใช้วิธีการแพนด้าpandas.read_htmlได้

สมมติว่าเราต้องการดึงตารางข้อมูล GDP จากเว็บไซต์: https://worldpopulationreview.com/countries/countries-by-gdp/#worldCountries

จากนั้นรหัสต่อไปนี้จะทำงานได้อย่างสมบูรณ์แบบ (ไม่จำเป็นต้องมี html ที่สวยงามและแฟนซี):

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()

เอาต์พุต

ห้าบรรทัดแรกของตารางจากเว็บไซต์


เห็นด้วย - นี่เป็นแนวทางที่ดีที่สุดในปี 2020 อย่างชัดเจน!
kfmfe04

2
เฉพาะในกรณีที่คุณใช้แพนด้าที่ไหนสักแห่งในโครงการของคุณแล้ว การพึ่งพาโต๊ะเดียวมากเกินไป
СергейЯхницкий

ฮ่าฮ่าคุณคัดลอกการร้องของฉันและปรับปรุงคำตอบ อย่างน้อยฉันก็อยากรู้ว่าแพนด้ามีวิธีการดังกล่าว ดี!
eusoubrasileiro

ใช่ฉันเคยใช้ data url ของ GDP จากตัวอย่างของคุณ ใช่ถ้าคุณชอบวิธีการที่รวดเร็วเราสามารถใช้pd.read_htmlแทนการเต้นรำของคำขอและซุปที่สวยงามได้ทั้งหมด
Bhishan Poudel

4

<table>นี่คือตัวอย่างที่ทำงานให้กับทั่วไป ( ลิงก์คำถามเสีย )

แยกตารางจากที่นี่ประเทศตาม GDP (ผลิตภัณฑ์มวลรวมในประเทศ)

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

tableDataTextฟังก์ชั่นแยกส่วน html ที่เริ่มมีแท็ก<table> ตามด้วยหลาย<tr>(แถวตาราง) และด้านใน<td>(ข้อมูลตาราง) แท็ก ส่งคืนรายการแถวที่มีคอลัมน์ด้านใน ยอมรับเพียงรายการเดียว<th>(ส่วนหัวตาราง / ข้อมูล) ในแถวแรก

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

ใช้มันเราจะได้รับ (สองแถวแรก)

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

ที่สามารถเปลี่ยนเป็นpandas.DataFrameเครื่องมือขั้นสูงได้อย่างง่ายดาย

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

แพนด้า DataFrame เอาต์พุตตาราง html


0
from behave import *
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
import pandas as pd
import requests
from bs4 import BeautifulSoup
from tabulate import tabulate

class readTableDataFromDB: 
    def LookupValueFromColumnSingleKey(context, tablexpath, rowName, columnName):
        print("element present readData From Table")
        element = context.driver.find_elements_by_xpath(tablexpath+"/descendant::th")
        indexrow = 1
        indexcolumn = 1
        for values in element:
            valuepresent = values.text
            print("text present here::"+valuepresent+"rowName::"+rowName)
            if valuepresent.find(columnName) != -1:
                 print("current row"+str(indexrow) +"value"+valuepresent)
                 break
            else:
                 indexrow = indexrow+1    

        indexvalue = context.driver.find_elements_by_xpath(
            tablexpath+"/descendant::tr/td[1]")
        for valuescolumn in indexvalue:
            valuepresentcolumn = valuescolumn.text
            print("Team text present here::" +
                  valuepresentcolumn+"columnName::"+rowName)
            print(indexcolumn) 
            if valuepresentcolumn.find(rowName) != -1:
                print("current column"+str(indexcolumn) +
                      "value"+valuepresentcolumn)
                break
            else:
                indexcolumn = indexcolumn+1

        print("index column"+str(indexcolumn))
        print(tablexpath +"//descendant::tr["+str(indexcolumn)+"]/td["+str(indexrow)+"]")
        #lookupelement = context.driver.find_element_by_xpath(tablexpath +"//descendant::tr["+str(indexcolumn)+"]/td["+str(indexrow)+"]")
        #print(lookupelement.text)
        return context.driver.find_elements_by_xpath(tablexpath+"//descendant::tr["+str(indexcolumn)+"]/td["+str(indexrow)+"]")

    def LookupValueFromColumnTwoKeyssss(context, tablexpath, rowName, columnName, columnName1):
        print("element present readData From Table")
        element = context.driver.find_elements_by_xpath(
            tablexpath+"/descendant::th")
        indexrow = 1
        indexcolumn = 1
        indexcolumn1 = 1
        for values in element:
            valuepresent = values.text
            print("text present here::"+valuepresent)
            indexrow = indexrow+1
            if valuepresent == columnName:
                print("current row value"+str(indexrow)+"value"+valuepresent)
                break

        for values in element:
            valuepresent = values.text
            print("text present here::"+valuepresent)
            indexrow = indexrow+1
            if valuepresent.find(columnName1) != -1:
                print("current row value"+str(indexrow)+"value"+valuepresent)
                break

        indexvalue = context.driver.find_elements_by_xpath(
            tablexpath+"/descendant::tr/td[1]")
        for valuescolumn in indexvalue:
            valuepresentcolumn = valuescolumn.text
            print("Team text present here::"+valuepresentcolumn)
            print(indexcolumn)
            indexcolumn = indexcolumn+1
            if valuepresent.find(rowName) != -1:
                print("current column"+str(indexcolumn) +
                      "value"+valuepresentcolumn)
                break
        print("indexrow"+str(indexrow))
        print("index column"+str(indexcolumn))
        lookupelement = context.driver.find_element_by_xpath(
            tablexpath+"//descendant::tr["+str(indexcolumn)+"]/td["+str(indexrow)+"]")
        print(tablexpath +
              "//descendant::tr["+str(indexcolumn)+"]/td["+str(indexrow)+"]")
        print(lookupelement.text)
        return context.driver.find_element_by_xpath(tablexpath+"//descendant::tr["+str(indexrow)+"]/td["+str(indexcolumn)+"]")
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.