【问题标题】:Scraping a nested and unstructured table in python (lxml)在 python (lxml) 中抓取嵌套和非结构化表
【发布时间】:2020-01-11 19:18:23
【问题描述】:

我正在 scraping 的网站(使用 lxml )除了一张表之外的所有东西都可以正常工作,其中所有 trtd 's 和标题 th's 是嵌套混合的,形成一个非结构化的 HTML 表格。

<table class='table'>
    <tr>
        <th>Serial No.
            <th>Full Name
                <tr>
                    <td>1
                        <td rowspan='1'> John 
                            <tr>
                                <td>2
                                    <td rowspan='1'>Jane Alleman
                                        <tr>
                                            <td>3
                                                <td rowspan='1'>Mukul Jha
                                                 .....
                                                 .....
                                                 .....
</table>

我尝试了以下 xpaths,但每一个都只是返回一个 空列表

persons = [x for x in tree.xpath('//table[@class="table"]/tr/th/th/tr/td/td/text()')]

persons = [x for x in tree.xpath('//table[@class="table"]/tr/td/td/text()')]

persons = [x for x in tree.xpath('//table[@class="table"]/tr/th/th/tr/td/td/text()') if x.isdigit() ==False] # to remove the serial no.s

最后,这样嵌套的原因是什么,是为了防止刮擦

【问题讨论】:

  • 显示此页面的URL,然后我们可以测试代码。
  • 也许这只是个错误——有人忘记了代码中的结束标签。
  • @furas 它只是对网站page.text 给出的实际表格的简单转换,因为结构完全相同。其次,这种设计的需求是什么。我认为这样做是为了防止报废(也许)。
  • 查看delhimetrorail.info/…中倒数第二个表格设计
  • 链接页面的最后一个表格看起来很简单;您可以从您的网站发布一张完整的表格吗?

标签: python web-scraping lxml lxml.html


【解决方案1】:

似乎lxml 加载表格的方式与浏览器类似,它在内存中创建了正确的结构,当您使用lxml.html.tostring(table) 时您可以看到正确的 HTML

所以它的表格格式正确,需要正常的'./tr/td//text()' 才能获取所有值

import requests
import lxml.html

text = requests.get('https://delhimetrorail.info/dwarka-sector-8-delhi-metro-station-to-dwarka-sector-14-delhi-metro-station').text

s = lxml.html.fromstring(text)

table = s.xpath('//table')[1]

for row in table.xpath('./tr'):
    cells = row.xpath('./td//text()')
    print(cells)

print(lxml.html.tostring(table, pretty_print=True).decode())

结果

['Fare', ' DMRC Rs. 30']
['Time', '0:14']
['First', '6:03']
['Last', '22:24']
['Phone ', '8800793196']

<table class="table">
<tr>
<td title="Monday To Saturday">Fare</td>
<td><div> DMRC Rs. 30</div></td>
</tr>
<tr>
<td>Time</td>
<td>0:14</td>
</tr>
<tr>
<td>First</td>
<td>6:03</td>
</tr>
<tr>
<td>Last</td>
<td>22:24</td>
</tr>
<tr>
<td>Phone </td>
<td><a href="tel:8800793196">8800793196</a></td>
</tr>
</table>

用于比较的原始 HTML - 缺少结束标记

<table class='table'>
<tr><td  title='Monday To Saturday'>Fare<td><div> DMRC Rs. 30</div></tr>
<tr><td>Time<td>0:14</tr>
<tr><td>First<td>6:03</tr>
<tr><td>Last<td>22:24
<tr><td>Phone <td><a href='tel:8800793196'>8800793196</a></tr>
</table>

【讨论】:

  • s.xpath 中有什么内容?
  • 我添加了s = lxml.html.fromstring(text)。最初我在我切断的代码中有带有Beautifulsoup 的行。看来我删除了太多行:)
【解决方案2】:

与 furas 的回答类似,但使用 pandas 抓取页面上的最后一个表格:

import requests
import lxml
import pandas as pd

url = 'https://delhimetrorail.info/dwarka-sector-8-delhi-metro-station-to-dwarka-sector-14-delhi-metro-station'
response = requests.get(url)

root = lxml.html.fromstring(response.text)
rows = []
info = root.xpath('//table[4]/tr/td[@rowspan]')
for i in info:
    row = []
    row.append(i.getprevious().text)
    row.append(i.text)
    rows.append(row)

columns = root.xpath('//table[4]//th/text()')
df1 = pd.DataFrame(rows, columns=columns)
df1

输出:

   Gate Dwarka Sector 14 Metro Station
0   1   Eros Etro Mall
1   2   Nirmal Bharatiya Public School

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-04
    • 1970-01-01
    • 1970-01-01
    • 2022-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多