Python - 使用 BeautifulSoup 在页面中抓取多个 类
Python - Crawl Multiple Classes within a Page Using BeautifulSoup
我正在尝试抓取 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" class 似乎包含两个子classes "breakfast" 和"room-promo"。这些子class仅在特定房型提供此类服务时才会出现。
当只有一个子 classes 出现时,输出效果很好。但是,当 none 的子 class 出现时,当我期望显示 "N/A" 时,输出为空。此外,当两个子 classes 都出现时,输出格式有不必要的空行,无法通过 .strip().
删除
有什么办法可以解决这些问题吗?
(2) 当我尝试从 class '.book-now-paylater' 中提取信息时,提取的数据与每个房间类型不匹配。例如,假设有10种房型,只有2、4、6、8房型允许旅客先预订后付款,代码可以提取出4条先预订后付款的信息,但这4条信息是然后不恰当地分配到房间类型 1、2、3、4。
有什么办法可以解决这个问题吗?
感谢您的帮助!
加里
在您的代码中,您没有正确遍历 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()
(1) 发生这种情况是因为即使 '.left-room-info'
selection 中没有文本,它也不会抛出异常,并且您的 except
永远不会 运行。您应该检查该值是否为空字符串 (''
)。你可以用一个简单的 if not string_var
来做到这一点
sp_info = soup.select('.left-room-info')[i].text.strip()
if not sp_info:
sp_info = "N/A"
当两个 subclasses 都出现时,您应该在马车 return ('\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) 有点复杂。您将不得不更改解析页面的方式。也就是说,您可能必须在 .room-type
上 select。您现在 select 阅读这本书的方式是稍后付款,它不会将它们与任何其他元素相关联,它只是 select 那个 class 的 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)
我正在尝试抓取 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" class 似乎包含两个子classes "breakfast" 和"room-promo"。这些子class仅在特定房型提供此类服务时才会出现。
当只有一个子 classes 出现时,输出效果很好。但是,当 none 的子 class 出现时,当我期望显示 "N/A" 时,输出为空。此外,当两个子 classes 都出现时,输出格式有不必要的空行,无法通过 .strip().
删除有什么办法可以解决这些问题吗?
(2) 当我尝试从 class '.book-now-paylater' 中提取信息时,提取的数据与每个房间类型不匹配。例如,假设有10种房型,只有2、4、6、8房型允许旅客先预订后付款,代码可以提取出4条先预订后付款的信息,但这4条信息是然后不恰当地分配到房间类型 1、2、3、4。
有什么办法可以解决这个问题吗?
感谢您的帮助!
加里
在您的代码中,您没有正确遍历 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()
(1) 发生这种情况是因为即使 '.left-room-info'
selection 中没有文本,它也不会抛出异常,并且您的 except
永远不会 运行。您应该检查该值是否为空字符串 (''
)。你可以用一个简单的 if not string_var
来做到这一点
sp_info = soup.select('.left-room-info')[i].text.strip()
if not sp_info:
sp_info = "N/A"
当两个 subclasses 都出现时,您应该在马车 return ('\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) 有点复杂。您将不得不更改解析页面的方式。也就是说,您可能必须在 .room-type
上 select。您现在 select 阅读这本书的方式是稍后付款,它不会将它们与任何其他元素相关联,它只是 select 那个 class 的 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)