【问题标题】:Using BeautifulSoup/CSS-Selectors to parse sibling rows使用 BeautifulSoup/CSS-Selectors 解析同级行
【发布时间】:2015-01-27 16:58:00
【问题描述】:

我想要抓取以下 HTML 结构:

<table class="showList">
    <tbody>
        <tr class="showListHeader">
            <th class="artistCol">Artists</th>
            <th class="venueCol">Venue</th>
            <th class="locationCol">Location</th>
        </tr>

        <tr class="dateRow">
            <td>11/26/14</td>
        </tr>

        <tr>
            <td class="artistCol">Artist1</td>
            <td class="venueCol">Venue1</td>
            <td class="locationCol">Location1</td>
        </tr>

        <tr>
            <td class="artistCol">Artist2</td>
            <td class="venueCol">Venue2</td>
            <td class="locationCol">Location2</td>
        </tr>

        <tr>
            <td class="artistCol">Artist3</td>
            <td class="venueCol">Venue3</td>
            <td class="locationCol">Location3</td>
        </tr>

        <tr class="dateRow">
            <td>11/28/14</td>
        </tr>

        <tr>
            <td class="artistCol">Artist4</td>
            <td class="venueCol">Venue4</td>
            <td class="locationCol">Location4</td>
        </tr>

        <tr>
            <td class="artistCol">Artist5</td>
            <td class="venueCol">Venue5</td>
            <td class="locationCol">Location5</td>
        </tr>
    </tbody>
</table>

看起来有点像这样:

+----------+--------+-----------+
|  Artist  | Venue  | Location  |
+----------+--------+-----------+
| 11/26/14 |        |           |
| Artist1  | Venue1 | Location1 |
| Artist2  | Venue2 | Location2 |
| Artist3  | Venue3 | Location3 |
| 11/28/14 |        |           |
| Artist4  | Venue4 | Location4 |
| Artist5  | Venue5 | Location5 |
+----------+--------+-----------+

我想得到以下结果:

[
    {date: 11/26/14, artist: Artist1, venue: Venue1, location: location1},
    {date: 11/26/14, artist: Artist2, venue: Venue2, location: location2},
    {date: 11/26/14, artist: Artist3, venue: Venue3, location: location3},
    {date: 11/28/14, artist: Artist4, venue: Venue4, location: location4},
    {date: 11/28/14, artist: Artist5, venue: Venue5, location: location5}
]

让我失望的是这些条目没有嵌套在日期中,它们是兄弟姐妹。 我知道如何使用 jQuery 来做到这一点,但对使用 CSS 选择器或 Scrapy 支持的 BeautifulSoup 知之甚少。任何有关我将如何解决此问题的帮助将不胜感激,如果我可以提供更多信息,请询问

【问题讨论】:

    标签: css web-scraping css-selectors beautifulsoup scrapy


    【解决方案1】:

    这个想法是用class="dateRow" 遍历所有tr 标签,为每个tr 获取以下tr 兄弟姐妹;一旦遇到具有dateRow 类的tr 元素,就打破循环:

    for tr in response.xpath('//tr[@class="dateRow"]'):
        date = tr.xpath('td/text()').extract()[0]
    
        for row in tr.xpath('following-sibling::tr'):
            # break the loop once we hit a tr with a class attribute defined
            if row.xpath('@class'):
                break
    
            artist = row.xpath('td[@class="artistCol"]/text()').extract()[0]
            venue = row.xpath('td[@class="venueCol"]/text()').extract()[0]
            location = row.xpath('td[@class="locationCol"]/text()').extract()[0]
    
            print {'date': date, 'artist': artist, 'venue': venue, 'location': location}
    

    来自scrapy shell的演示:

    $ scrapy shell index.html
    >>> for tr in response.xpath('//tr[@class="dateRow"]'):
    ...     date = tr.xpath('td/text()').extract()[0]
    ...     for row in tr.xpath('following-sibling::tr'):
    ...         if row.xpath('@class'):
    ...             break
    ...         artist = row.xpath('td[@class="artistCol"]/text()').extract()[0]
    ...         venue = row.xpath('td[@class="venueCol"]/text()').extract()[0]
    ...         location = row.xpath('td[@class="locationCol"]/text()').extract()[0]
    ...         print {'date': date, 'artist': artist, 'venue': venue, 'location': location}
    ... 
    {'date': u'11/26/14', 'venue': u'Venue1', 'location': u'Location1', 'artist': u'Artist1'}
    {'date': u'11/26/14', 'venue': u'Venue2', 'location': u'Location2', 'artist': u'Artist2'}
    {'date': u'11/26/14', 'venue': u'Venue3', 'location': u'Location3', 'artist': u'Artist3'}
    {'date': u'11/28/14', 'venue': u'Venue4', 'location': u'Location4', 'artist': u'Artist4'}
    {'date': u'11/28/14', 'venue': u'Venue5', 'location': u'Location5', 'artist': u'Artist5'}
    

    UPD(使用您提供的链接):

    for tr in response.xpath('//table[@class="showList"]//tr[@class="dateRow"]'):
        date = tr.xpath('td/a/text()').extract()[0]
    
        for row in tr.xpath('following-sibling::tr[@class = "dateRow" or @class = " "]'):
            if row.xpath('@id'):
                break
    
            artist = row.xpath('td[@class="artistCol"]/a/text()').extract()[0]
            venue = row.xpath('td[@class="venueCol"]/a/text()').extract()[0]
            location = row.xpath('td[@class="locationCol"]/a/text()').extract()[0]
    
            print {'date': date, 'artist': artist, 'venue': venue, 'location': location}
    

    演示:

    >>> for tr in response.xpath('//table[@class="showList"]//tr[@class="dateRow"]'):
    ...     date = tr.xpath('td/a/text()').extract()[0]
    ...     for row in tr.xpath('following-sibling::tr[@class = "dateRow" or @class = " "]'):
    ...         if row.xpath('@id'):
    ...             break
    ...         artist = row.xpath('td[@class="artistCol"]/a/text()').extract()[0]
    ...         venue = row.xpath('td[@class="venueCol"]/a/text()').extract()[0]
    ...         location = row.xpath('td[@class="locationCol"]/a/text()').extract()[0]
    ...         print {'date': date, 'artist': artist, 'venue': venue, 'location': location}
    ... 
    {'date': u'11/26/14', 'venue': u'The Stone Pony', 'location': u'Asbury Park', 'artist': u'River City Extension'}
    {'date': u'11/26/14', 'venue': u'The Wonder Bar', 'location': u'Asbury Park', 'artist': u'Jessica Paris'}
    {'date': u'11/26/14', 'venue': u'Third Base Pub', 'location': u'Branchville', 'artist': u'Fish House Road'}
    {'date': u'11/26/14', 'venue': u'Bliss Lounge', 'location': u'Clifton', 'artist': u'Erick Morillo'}
    {'date': u'11/26/14', 'venue': u'The Claddagh Lounge', 'location': u'Highlands', 'artist': u'Turtle Soup'}
    {'date': u'11/26/14', 'venue': u'The Brighton Bar', 'location': u'Long Branch', 'artist': u'Hot Blood'}
    ...
    {'date': u'01/24/15', 'venue': u'Bergen Performing Arts Center', 'location': u'Englewood', 'artist': u'Kashmir'}
    {'date': u'01/24/15', 'venue': u"Hansil's Bar & Grill ", 'location': u'Oakland', 'artist': u"Hott Mott's Rhythm & Blues Band"}
    {'date': u'01/24/15', 'venue': u'Studio Luloo', 'location': u'Oaklyn', 'artist': u'The Escape'}
    {'date': u'01/24/15', 'venue': u'Union County Performing Arts Center', 'location': u'Rahway', 'artist': u'Milton'}
    {'date': u'01/24/15', 'venue': u'Starland Ballroom', 'location': u'Sayreville', 'artist': u'Marilyn Manson'}
    {'date': u'01/24/15', 'venue': u'Library II', 'location': u'Voorhees', 'artist': u'Hotlanta'}
    

    【讨论】:

    • 这绝对很有帮助,在看到您的回答后,我意识到其他行确实有一个我没有包含在我的原始问题中的类,但它们只是一个空格 (class=" ") 我可以用 tr.xpath('following-sibling::tr[@class=" "]') 来实现吗?
    • @MauricioTrajano 是的,区分 trdateRow 类和包含事件数据的行应该不是问题。您能否向我展示您的真实 html,以便我可以使用它并为您提供解决方案?谢谢。
    • 确定网站是:jambase.com/shows/Shows.aspx?State=nj&StartDate=11/26/…,非常感谢您的帮助,这是一个学校项目,我需要创建和查询音乐数据库
    • @MauricioTrajano 谢谢,我已经更新了答案(现在依赖于 id 属性的存在)。试一试。
    • 非常感谢!如果可以的话,我会给你 1000 倍的票,你帮我省了很多麻烦
    猜你喜欢
    • 1970-01-01
    • 2018-08-19
    • 2019-06-16
    • 1970-01-01
    • 2013-09-30
    • 2013-03-10
    • 1970-01-01
    • 2013-10-05
    • 2015-03-29
    相关资源
    最近更新 更多