BeautifulSoup только соскабливая половину моего стола? - PullRequest
1 голос
/ 28 июня 2019

Я очищаю веб-страницу для таблицы, используя BeautifulSoup, но по какой-то причине она очищает только половину таблицы.Половина, которую я получаю, это та часть, которая не содержит полей ввода.Вот данные html:

<table class="commonTable1" cellpadding="0" cellspacing="0" border="0" width="100%" id="portAllocTable">
    <tbody>
        <tr>
            <th class="commonTableHeaderLastCell" colspan="2"><span class="commonBold"> Portfolio Allocation (%) </span></th>
        </tr>
        <tr>
            <td colspan="2" class="commonHeaderContentSeparator"><img src="/fees-web/common/images/spacer.gif" height="1" style="display: block"></td>
        </tr>
        <tr>
            <td>
                <span>AdvisorGuided (Capital Portfolio)</span>
            </td>
            <td class="commonTableBodyLastCell" align="right">
                <span>
                    <!-- When collection method is invoice,  the portfolio to charge table should be diabled.
                    Else work as it was-->
                    <input type="hidden" name="portfolioChargeList[0].feeCollectionRate" value="100" id="selText_1"><input type="text" name="portfolioChargeList[0].feeCollectionRateINPUT" maxlength="3" onkeypress="return disableMinus();" onblur="updateTotal(1);" value="100" maxvalue="100" decimals="0" showalertdialog="true" blankifzero="true" id="selText_1INPUT" style="text-align:right;width:50px" class="commonTextBoxAmount">
                </span>
            </td>
        </tr>
        <tr>
            <td>
                <span>AdvisorGuided 2 (Capital Portfolio)</span>
            </td>
            <td class="commonTableBodyLastCell" align="right">
                <span>
                    <!-- When collection method is invoice,  the portfolio to charge table should be diabled.
                    Else work as it was-->
                    <input type="hidden" name="portfolioChargeList[1].feeCollectionRate" value="0" id="selText_1"><input type="text" name="portfolioChargeList[1].feeCollectionRateINPUT" maxlength="3" onkeypress="return disableMinus();" onblur="updateTotal(1);" value="0" maxvalue="100" decimals="0" showalertdialog="true" blankifzero="true" id="selText_1INPUT" style="text-align:right;width:50px" class="commonTextBoxAmount">
                </span>
            </td>
        </tr>
        <tr>
            <td>
                <span>Client Directed (Capital Portfolio)</span>
            </td>
            <td class="commonTableBodyLastCell" align="right">
                <span>
                    <!-- When collection method is invoice,  the portfolio to charge table should be diabled.
                    Else work as it was-->
                    <input type="hidden" name="portfolioChargeList[2].feeCollectionRate" value="0" id="selText_1"><input type="text" name="portfolioChargeList[2].feeCollectionRateINPUT" maxlength="3" onkeypress="return disableMinus();" onblur="updateTotal(1);" value="0" maxvalue="100" decimals="0" showalertdialog="true" blankifzero="true" id="selText_1INPUT" style="text-align:right;width:50px" class="commonTextBoxAmount">
                </span>
            </td>
        </tr>
        <tr>
            <td>
                <span>Holding MMKT (Capital Portfolio)</span>
            </td>
            <td class="commonTableBodyLastCell" align="right">
                <span>
                    <!-- When collection method is invoice,  the portfolio to charge table should be diabled.
                    Else work as it was-->
                    <input type="hidden" name="portfolioChargeList[3].feeCollectionRate" value="0" id="selText_1"><input type="text" name="portfolioChargeList[3].feeCollectionRateINPUT" maxlength="3" onkeypress="return disableMinus();" onblur="updateTotal(1);" value="0" maxvalue="100" decimals="0" showalertdialog="true" blankifzero="true" id="selText_1INPUT" style="text-align:right;width:50px" class="commonTextBoxAmount">
                </span>
            </td>
        </tr>
        <tr>
            <td>
                <span>Total</span>
            </td>
            <td class="commonTableBodyLastCell" align="right">
                <span>
                    <input type="hidden" name="portfolioChargeList[4].feeCollectionRate" value="100" id="selText_1Total"><input type="text" name="portfolioChargeList[4].feeCollectionRateINPUT" maxlength="3" value="100" maxvalue="100" decimals="0" blankifzero="true" id="selText_1TotalINPUT" style="text-align:right;width:50px" class="commonTextBoxAmount">
                </span>
            </td>
        </tr>
    </tbody>
</table>

Вот мой код:


url = driver.page_source

soup = BeautifulSoup(url, "lxml")
table = soup.find('table', id="portAllocTable")
rows = table.findAll('td')

list_of_rows = []
for row in table.findAll('tr'):
    list_of_cells = []
    for cell in row.findAll(["th","td"]):
        text = cell.text
        list_of_cells.append(text)
    list_of_rows.append(list_of_cells)

for item in list_of_rows:
    print(' '.join(item))

Что я делаю не так?Почему печатается только левая сторона стола?Любые рекомендации о том, что изменить, будет принята с благодарностью.

Results:

 Portfolio Allocation (%) 


AdvisorGuided (Capital Portfolio)
 100 100 




AdvisorGuided 2 (Capital Portfolio)
 0 100 




Client Directed (Capital Portfolio)
 0 100 




Holding MMKT (Capital Portfolio)
 0 100 




Total
 100 100

Ответы [ 2 ]

1 голос
/ 28 июня 2019

Вам нужно будет пойти дальше в дочерний и дочерний узлы и извлечь атрибуты (эти значения не являются фактическим текстом / содержимым.

import pandas as pd
import bs4


html = '''<table class="commonTable1" cellpadding="0" cellspacing="0" border="0" width="100%" id="portAllocTable">
    <tbody>
        <tr>
            <th class="commonTableHeaderLastCell" colspan="2"><span class="commonBold"> Portfolio Allocation (%) </span></th>
        </tr>
        <tr>
            <td colspan="2" class="commonHeaderContentSeparator"><img src="/fees-web/common/images/spacer.gif" height="1" style="display: block"></td>
        </tr>
        <tr>
            <td>
                <span>AdvisorGuided (Capital Portfolio)</span>
            </td>
            <td class="commonTableBodyLastCell" align="right">
                <span>
                    <!-- When collection method is invoice,  the portfolio to charge table should be diabled.
                    Else work as it was-->
                    <input type="hidden" name="portfolioChargeList[0].feeCollectionRate" value="100" id="selText_1"><input type="text" name="portfolioChargeList[0].feeCollectionRateINPUT" maxlength="3" onkeypress="return disableMinus();" onblur="updateTotal(1);" value="100" maxvalue="100" decimals="0" showalertdialog="true" blankifzero="true" id="selText_1INPUT" style="text-align:right;width:50px" class="commonTextBoxAmount">
                </span>
            </td>
        </tr>
        <tr>
            <td>
                <span>AdvisorGuided 2 (Capital Portfolio)</span>
            </td>
            <td class="commonTableBodyLastCell" align="right">
                <span>
                    <!-- When collection method is invoice,  the portfolio to charge table should be diabled.
                    Else work as it was-->
                    <input type="hidden" name="portfolioChargeList[1].feeCollectionRate" value="0" id="selText_1"><input type="text" name="portfolioChargeList[1].feeCollectionRateINPUT" maxlength="3" onkeypress="return disableMinus();" onblur="updateTotal(1);" value="0" maxvalue="100" decimals="0" showalertdialog="true" blankifzero="true" id="selText_1INPUT" style="text-align:right;width:50px" class="commonTextBoxAmount">
                </span>
            </td>
        </tr>
        <tr>
            <td>
                <span>Client Directed (Capital Portfolio)</span>
            </td>
            <td class="commonTableBodyLastCell" align="right">
                <span>
                    <!-- When collection method is invoice,  the portfolio to charge table should be diabled.
                    Else work as it was-->
                    <input type="hidden" name="portfolioChargeList[2].feeCollectionRate" value="0" id="selText_1"><input type="text" name="portfolioChargeList[2].feeCollectionRateINPUT" maxlength="3" onkeypress="return disableMinus();" onblur="updateTotal(1);" value="0" maxvalue="100" decimals="0" showalertdialog="true" blankifzero="true" id="selText_1INPUT" style="text-align:right;width:50px" class="commonTextBoxAmount">
                </span>
            </td>
        </tr>
        <tr>
            <td>
                <span>Holding MMKT (Capital Portfolio)</span>
            </td>
            <td class="commonTableBodyLastCell" align="right">
                <span>
                    <!-- When collection method is invoice,  the portfolio to charge table should be diabled.
                    Else work as it was-->
                    <input type="hidden" name="portfolioChargeList[3].feeCollectionRate" value="0" id="selText_1"><input type="text" name="portfolioChargeList[3].feeCollectionRateINPUT" maxlength="3" onkeypress="return disableMinus();" onblur="updateTotal(1);" value="0" maxvalue="100" decimals="0" showalertdialog="true" blankifzero="true" id="selText_1INPUT" style="text-align:right;width:50px" class="commonTextBoxAmount">
                </span>
            </td>
        </tr>
        <tr>
            <td>
                <span>Total</span>
            </td>
            <td class="commonTableBodyLastCell" align="right">
                <span>
                    <input type="hidden" name="portfolioChargeList[4].feeCollectionRate" value="100" id="selText_1Total"><input type="text" name="portfolioChargeList[4].feeCollectionRateINPUT" maxlength="3" value="100" maxvalue="100" decimals="0" blankifzero="true" id="selText_1TotalINPUT" style="text-align:right;width:50px" class="commonTextBoxAmount">
                </span>
            </td>
        </tr>
    </tbody>
</table>'''


soup = bs4.BeautifulSoup(html, "lxml")
table = soup.find('table', id="portAllocTable")
rows = table.findAll('td')

list_of_rows = []
for row in table.findAll('tr'):
    list_of_cells = []
    for cell in row.find_all(["th","td"]):
        text = cell.text
        try:
            val = cell.find('input')['value']
            max_val = cell.find('input').next_sibling['maxvalue']
            list_of_cells.append(val)
            list_of_cells.append(max_val)
        except:
            pass
        list_of_cells.append(text)
    list_of_rows.append(list_of_cells)

for item in list_of_rows:
    print(' '.join(item))

Чтобы сделать стол, вы могли бы сделать что-то вроде этого. Вам придется немного очиститься, но вы должны начать:

results = pd.DataFrame()
for row in table.findAll('tr'):
    for cell in row.find_all(["th","td"]):
        text = cell.text
        try:
            val = cell.find('input')['value']
            max_val = cell.find('input').next_sibling['maxvalue']
        except:
            val = ''
            max_val = ''
            pass

        temp_df = pd.DataFrame([[text, val, max_val]], columns=['text','value','maxvalue'])
        results = results.append(temp_df).reset_index(drop=True)
0 голосов
/ 28 июня 2019

Несколько вещей приходят на ум.

Первое: это должно быть rows = table.findAll('tr'), так как HTML-тег tr обозначает строки. Впоследствии он должен for row in table.findAll('td'):, так как HTML-тег td является тегом ячейки. Но вы даже не используете переменную rows, так что суть спорная. Если вы хотите, вы можете сделать что-то вроде этого:

soup = BeautifulSoup(url, "lxml")
table = soup.find('table', id="portAllocTable")
rows = table.findAll("tr")

list_of_rows = []
for row in rows:
    list_of_cells = []
    for cell in row.findAll(['th', 'td']):
        text = cell.text
        list_of_cells.append(text)
    list_of_rows.append(list_of_cells)

for item in list_of_rows:
    print(' '.join(item))

Во-вторых, этот код не будет получать текст в полях ввода, поэтому, вероятно, поэтому вы видите текст только слева.

Наконец, вы можете попробовать разностный анализатор, такой как html5lib.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...