首页 文章

Python - 使用BeautifulSoup在页面中抓取多个类

提问于
浏览
2

我正在尝试 grab Agoda的多种房型的每日酒店价格以及其他信息,例如促销信息,早餐条件以及预订现在付款的后期规定 .

我的代码如下:

import requests
import math
from bs4 import BeautifulSoup

url = "http://www.agoda.com/ambassador-hotel-taipei/hotel/taipei-tw.html?asq=8m91A1C3D%252bTr%252bvRSmuClW5dm5vJXWO5dlQmHx%252fdU9qxilNob5hJg0b218wml6rCgncYsXBK0nWktmYtQJCEMu0P07Y3BjaTYhdrZvavpUnmfy3moWn%252bv8f2Lfx7HovrV95j6mrlCfGou99kE%252bA0aX0aof09AStNs69qUxvAVo53D4ZTrmAxm3bVkqZJr62cU&tyra=1%257c2&searchrequestid=2e2b0e8c-cadb-465b-8dea-2222e24a1678&pingnumber=1&checkin=2015-10-01&los=1"
res = requests.get(url)
soup = BeautifulSoup(res.text, 'html.parser')
n = len(soup.select('.room-name'))

for i in range(0, n):
    en_room = soup.select('.room-name')[i].text.strip()
    currency = soup.select('.currency')[i].text
    price = soup.select('.sellprice')[i].text

    try:
        sp_info = soup.select('.left-room-info')[i].text.strip()
    except Exception as e:
        sp_info = "N/A"

    try:
        pay_later = soup.select('.book-now-paylater')[i].text.strip()
    except Exception as e:
        pay_later = "N/A"


    print en_room, i+1, currency, price, en_room, sp_info, pay_later
    time.sleep(1)

我有两个问题:

(1)“left-room-info”类似乎包含两个子类“breakfast”和“room-promo” . 这些子类仅在特定房间类型提供此类服务时显示 .

当只显示其中一个子类时,输出效果很好 . 但是,当没有子类显示时,当我希望显示“N / A”时输出为空 . 此外,当两个子类都出现时,输出格式有不必要的空行,无法通过.strip()删除 .

有没有办法解决这些问题?

(2)当我试图从 class '.book-now-paylater'中提取信息时,提取的数据与每个房间类型不匹配 . 例如,假设有10种房型,只有房间2,4,6,8允许旅行者现在预订后付款,这些代码可以准确地提取4本书 - 现在付费的信息,但这4条信息是然后不恰当地分配给1,2,3,4号房间 .

有什么方法可以解决这个问题吗?

谢谢您的帮助!

加里

2 回答

  • 1

    (1)发生这种情况是因为即使 '.left-room-info' 选择中没有文本,也不会抛出异常, except 永远不会运行 . 您应该检查该值是否为空字符串( '' ) . 你可以用这样的简单_489175这样做

    sp_info = soup.select('.left-room-info')[i].text.strip()
    if not sp_info:
        sp_info = "N/A"
    

    当两个子类都出现时,您应该在回车符( '\r' )上拆分字符串,然后去除每个结果 . 代码看起来像这样:(注意,现在sp_info是一个列表,而不仅仅是一个字符串)

    sp_info = soup.select('.left-room-info')[i].text.strip().split('\r')
    if len(sp_info) > 1:
        sp_info = [ info.strip() for info in sp_info ]
    

    把这些碎片放在一起,我们会得到这样的东西

    sp_info = soup.select('.left-room-info')[i].text.strip().split('\r')
    if len(sp_info) > 1:
        sp_info = [ info.strip() for info in sp_info ]
    elif not sp_info[0]: # check for empty string
        sp_info = ["N/A"] # keep sp_info a list for consistancy
    

    (2)稍微复杂一些 . 你're going to have to change how you parse the page. Namely, you'可能要在 .room-type 上选择 . 你将它们与任何其他元素相关联的方式,它只选择该类的8个实例 . 以下是我将如何做到这一点:

    import requests
    import math
    from bs4 import BeautifulSoup
    
    url = "http://www.agoda.com/ambassador-hotel-taipei/hotel/taipei-tw.html?asq=8m91A1C3D%252bTr%252bvRSmuClW5dm5vJXWO5dlQmHx%252fdU9qxilNob5hJg0b218wml6rCgncYsXBK0nWktmYtQJCEMu0P07Y3BjaTYhdrZvavpUnmfy3moWn%252bv8f2Lfx7HovrV95j6mrlCfGou99kE%252bA0aX0aof09AStNs69qUxvAVo53D4ZTrmAxm3bVkqZJr62cU&tyra=1%257c2&searchrequestid=2e2b0e8c-cadb-465b-8dea-2222e24a1678&pingnumber=1&checkin=2015-10-01&los=1"
    res = requests.get(url)
    soup = BeautifulSoup(res.text)
    
    rooms = soup.select('.room-type')[1:] # the first instance of the class isn't a room
    
    room_list = []
    
    for room in rooms:
        room_info = {}
    
        room_info['en_room'] = room.select('.room-name')[0].text.strip()
        room_info['currency'] = room.select('.currency')[0].text.strip()
        room_info['price'] = room.select('.sellprice')[0].text.strip()
    
        sp_info = room.select('.left-room-info')[0].text.strip().split('\r')
        if len(sp_info) > 1:
            sp_info = ", ".join([ info.strip() for info in sp_info ])
        elif not sp_info[0]: # check for empty string
            sp_info = "N/A"
        room_info['sp_info'] = sp_info
    
        pay_later = room.select('.book-now-paylater')
        room_info['pay_later'] = pay_later[0].text.strip() if pay_later else "N/A"
    
        room_list.append(room_info)
    
  • 2

    在您的代码中,您没有正确遍历dom . 这将导致刮削问题 . (例如第二个问题) . 我将提供暗示性代码片段(不是确切的解决方案),希望您能够自己解决第一个问题 .

    # select all room types by tables tr tag
    room_types = soup.find_all('tr', class_="room-type")
    
    # iterate over the list to scrape data form each td or div inside tr
    for room in room_types:
        en_room = room.find('div', class_='room-name').text.strip()
    

相关问题